Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 9 additions & 84 deletions src/mono/mono/eventpipe/ep-buffer-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,13 +423,6 @@ buffer_manager_allocate_buffer_for_thread (

// Allocating a buffer requires us to take the lock.
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section1)

// if we are deallocating then give up, see the comments in ep_buffer_manager_suspend_write_event () for why this is important.
if ((bool)ep_rt_volatile_load_uint32_t (&buffer_manager->write_event_suspending)) {
*write_suspended = true;
ep_raise_error_holding_spin_lock (section1);
}

thread_buffer_list = ep_thread_session_state_get_buffer_list (thread_session_state);
if (thread_buffer_list == NULL) {
thread_buffer_list = ep_buffer_list_alloc (buffer_manager, ep_thread_session_state_get_thread (thread_session_state));
Expand Down Expand Up @@ -797,8 +790,6 @@ ep_buffer_manager_alloc (
instance->session = session;
instance->size_of_all_buffers = 0;

ep_rt_volatile_store_uint32_t (&instance->write_event_suspending, (uint32_t)false);

#ifdef EP_CHECKED_BUILD
instance->num_buffers_allocated = 0;
instance->num_buffers_stolen = 0;
Expand Down Expand Up @@ -837,8 +828,6 @@ ep_buffer_manager_free (EventPipeBufferManager * buffer_manager)
{
ep_return_void_if_nok (buffer_manager != NULL);

ep_rt_volatile_store_uint32_t (&buffer_manager->write_event_suspending, (uint32_t)true);

ep_buffer_manager_deallocate_buffers (buffer_manager);

ep_rt_wait_event_free (&buffer_manager->rt_wait_event);
Expand Down Expand Up @@ -931,10 +920,6 @@ ep_buffer_manager_write_event (
thread_lock = ep_thread_get_rt_lock_ref (current_thread);

EP_SPIN_LOCK_ENTER (thread_lock, section1)
if (ep_rt_volatile_load_uint32_t_without_barrier (&buffer_manager->write_event_suspending) != (uint32_t)false)
// This session is suspending, we need to avoid initializing any session state and exit
ep_raise_error_holding_spin_lock (section1);

session_state = ep_thread_get_or_create_session_state (current_thread, session);
ep_raise_error_if_nok_holding_spin_lock (session_state != NULL, section1);

Expand Down Expand Up @@ -977,24 +962,13 @@ ep_buffer_manager_write_event (

thread_lock = ep_thread_get_rt_lock_ref (current_thread);
EP_SPIN_LOCK_ENTER (thread_lock, section3)
if (ep_rt_volatile_load_uint32_t_without_barrier (&buffer_manager->write_event_suspending) != (uint32_t)false) {
// After leaving the manager's lock in buffer_manager_allocated_buffer_for_thread some other thread decided to suspend writes.
// We need to immediately return the buffer we just took without storing it or writing to it.
// suspend_write_event () is spinning waiting for this buffer to be relinquished.
ep_buffer_convert_to_read_only (buffer);

// We treat this as the write_event() call occurring after this session stopped listening for events, effectively the
// same as if ep_event_is_enabled returned false.
ep_raise_error_holding_spin_lock (section3);
} else {
ep_thread_session_state_set_write_buffer (session_state, buffer);
// Try to write the event after we allocated a buffer.
// This is the first time if the thread had no buffers before the call to this function.
// This is the second time if this thread did have one or more buffers, but they were full.
alloc_new_buffer = !ep_buffer_write_event (buffer, event_thread, session, ep_event, payload, activity_id, related_activity_id, stack);
EP_ASSERT(!alloc_new_buffer);
ep_thread_session_state_increment_sequence_number (session_state);
}
EP_SPIN_LOCK_EXIT (thread_lock, section3)
}
}
Expand Down Expand Up @@ -1034,73 +1008,33 @@ ep_buffer_manager_suspend_write_event (
ep_rt_thread_array_alloc (&thread_array);
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section1);
EP_ASSERT (ep_buffer_manager_ensure_consistency (buffer_manager) == true);
ep_rt_volatile_store_uint32_t (&buffer_manager->write_event_suspending, (uint32_t)true);

// From this point until write_event_suspending is reset to false it is impossible
// for new EventPipeThreadSessionStates to be added to the thread_session_state_list or
// for new EventBuffers to be added to an existing EventPipeBufferList. The only
// way ep_buffer_manager_allocate_buffer_for_thread is allowed to add one is by:
// 1) take rt_lock - ep_buffer_manager_allocate_buffer_for_thread can't own it now because this thread owns it,
// but after this thread gives it up lower in this function it could be acquired.
// 2) observe write_event_suspending = false - that won't happen, acquiring rt_lock
// guarantees ep_buffer_manager_allocate_buffer_for_thread will observe all the memory changes this
// thread made prior to releasing m_lock and we've already set it true.
// This ensures that we iterate over the list of threads below we've got the complete list.
// Find all threads that have used this buffer manager.
ep_rt_thread_session_state_list_iterator_t thread_session_state_list_iterator;
ep_rt_thread_session_state_list_iterator_begin (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
while (!ep_rt_thread_session_state_list_iterator_end (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator)) {
ep_rt_thread_array_append (&thread_array, ep_thread_session_state_get_thread (ep_rt_thread_session_state_list_iterator_value (&thread_session_state_list_iterator)));
EventPipeThread *thread = ep_thread_session_state_get_thread (ep_rt_thread_session_state_list_iterator_value (&thread_session_state_list_iterator));
ep_rt_thread_array_append (&thread_array, thread);
ep_rt_thread_session_state_list_iterator_next (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);

// Once EventPipeSession::SuspendWriteEvent completes, we shouldn't have any
// in progress writes left.
EP_ASSERT (ep_thread_get_session_write_in_progress (thread) != session_index);
}
EP_SPIN_LOCK_EXIT (&buffer_manager->rt_lock, section1);

// Iterate through all the threads, forcing them to finish writes in progress inside EventPipeThread::m_lock,
// relinquish any buffers stored in EventPipeThread::m_pWriteBuffer and prevent storing new ones.
// Iterate through all the threads, forcing them to relinquish any buffers stored in
// EventPipeThread's write buffer and prevent storing new ones.
ep_rt_thread_array_iterator_t thread_array_iterator;
ep_rt_thread_array_iterator_begin (&thread_array, &thread_array_iterator);
while (!ep_rt_thread_array_iterator_end (&thread_array, &thread_array_iterator)) {
EventPipeThread *thread = ep_rt_thread_array_iterator_value (&thread_array_iterator);
EP_SPIN_LOCK_ENTER (ep_thread_get_rt_lock_ref (thread), section2)
EventPipeThreadSessionState *thread_session_state = ep_thread_get_session_state (thread, buffer_manager->session);
ep_thread_session_state_set_write_buffer (thread_session_state, NULL);
// From this point until write_event_suspending is reset to false it is impossible
// for this thread to set the write buffer to a non-null value which in turn means
// it can't write events into any buffer. To do this it would need to both:
// 1) Acquire the thread lock - it can't right now but it will be able to do so after
// we release the lock below
// 2) Observe write_event_suspending = false - that won't happen, acquiring the thread
// lock guarantees ep_buffer_manager_write_event will observe all the memory
// changes this thread made prior to releasing the thread
// lock and we already set it true.
EP_SPIN_LOCK_EXIT (ep_thread_get_rt_lock_ref (thread), section2)
ep_rt_thread_array_iterator_next (&thread_array, &thread_array_iterator);
}

// Wait for any straggler ep_buffer_manager_write_event threads that may have already allocated a buffer but
// hadn't yet relinquished it.
ep_rt_thread_session_state_list_iterator_t thread_session_state_list_iterator;
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section3)
ep_rt_thread_session_state_list_iterator_begin (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
while (!ep_rt_thread_session_state_list_iterator_end (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator)) {
EventPipeBufferList *buffer_list = ep_thread_session_state_get_buffer_list (ep_rt_thread_session_state_list_iterator_value (&thread_session_state_list_iterator));
if (buffer_list) {
EventPipeThread *const event_pipe_thread = ep_buffer_list_get_thread (buffer_list);
if (event_pipe_thread) {
EP_YIELD_WHILE (ep_thread_get_session_write_in_progress (event_pipe_thread) == session_index);
// It still guarantees that the thread has returned its buffer, but it also now guarantees that
// that the thread has returned from ep_session_write_event () and has relinquished the session pointer
// This yield is guaranteed to eventually finish because threads will eventually exit write_event ()
// setting the flag back to -1. If the thread could quickly re-enter WriteEvent and set the flag
// back to this_session_id we could theoretically get unlucky and never observe the gap, but
// setting s_pSessions[this_session_id] = NULL above guaranteed that can't happen indefinately.
// Sooner or later the thread is going to see the NULL value and once it does it won't store
// this_session_id into the flag again.
}
}
ep_rt_thread_session_state_list_iterator_next (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
}
EP_SPIN_LOCK_EXIT (&buffer_manager->rt_lock, section3)

ep_on_exit:
ep_requires_lock_held ();
ep_rt_thread_array_free (&thread_array);
Expand Down Expand Up @@ -1338,15 +1272,6 @@ ep_buffer_manager_deallocate_buffers (EventPipeBufferManager *buffer_manager)
// Take the buffer manager manipulation lock
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section1)
EP_ASSERT (ep_buffer_manager_ensure_consistency (buffer_manager));
EP_ASSERT ((bool)ep_rt_volatile_load_uint32_t (&buffer_manager->write_event_suspending));

// This m_writeEventSuspending flag + locks ensures that no thread will touch any of the
// state we are dismantling here. This includes:
// a) EventPipeThread m_sessions[session_id]
// b) EventPipeThreadSessionState
// c) EventPipeBufferList
// d) EventPipeBuffer
// e) EventPipeBufferManager.m_pThreadSessionStateList

ep_rt_thread_session_state_list_iterator_t thread_session_state_list_iterator;
ep_rt_thread_session_state_list_iterator_begin (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/eventpipe/ep-buffer-manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ struct _EventPipeBufferManager_Internal {
uint32_t num_buffers_stolen;
uint32_t num_buffers_leaked;
#endif
volatile uint32_t write_event_suspending;
};

#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_BUFFER_MANAGER_GETTER_SETTER)
Expand Down
6 changes: 4 additions & 2 deletions src/mono/mono/eventpipe/ep-event-source.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ ep_event_source_enable (
EP_ASSERT (event_source != NULL);
EP_ASSERT (session != NULL);

ep_requires_lock_held ();

EventPipeSessionProvider *session_provider = ep_session_provider_alloc (event_source->provider_name, (uint64_t)-1, EP_EVENT_LEVEL_LOG_ALWAYS, NULL);
if (session_provider != NULL)
ep_session_add_session_provider (session, session_provider);
Expand All @@ -207,8 +209,8 @@ ep_event_source_send_process_info (
ep_char16_t *arch_info_utf16 = NULL;

command_line_utf16 = ep_rt_utf8_to_utf16_string (command_line, -1);
os_info_utf16 = ep_rt_utf8_to_utf16_string (_ep_os_info, -1);
arch_info_utf16 = ep_rt_utf8_to_utf16_string (_ep_arch_info, -1);
os_info_utf16 = ep_rt_utf8_to_utf16_string (ep_event_source_get_os_info (), -1);
arch_info_utf16 = ep_rt_utf8_to_utf16_string (ep_event_source_get_arch_info (), -1);

EventData data [3] = { { 0 } };
if (command_line_utf16)
Expand Down
18 changes: 18 additions & 0 deletions src/mono/mono/eventpipe/ep-event-source.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,24 @@ struct _EventPipeEventSource {
};
#endif

static
inline
const char *
ep_event_source_get_os_info (void)
{
extern const char *_ep_os_info;
return _ep_os_info;
}

static
inline
const char *
ep_event_source_get_arch_info (void)
{
extern const char *_ep_arch_info;
return _ep_arch_info;
}

EventPipeEventSource *
ep_event_source_alloc (void);

Expand Down
3 changes: 3 additions & 0 deletions src/mono/mono/eventpipe/ep-event.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ struct _EventPipeEvent {
EP_DEFINE_GETTER(EventPipeEvent *, event, uint64_t, keywords)
EP_DEFINE_GETTER_REF(EventPipeEvent *, event, volatile int64_t *, enabled_mask)
EP_DEFINE_SETTER(EventPipeEvent *, event, int64_t, enabled_mask)
EP_DEFINE_GETTER(EventPipeEvent *, event, uint8_t *, metadata)
EP_DEFINE_GETTER(EventPipeEvent *, event, EventPipeProvider *, provider)
EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, event_id)
EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, event_version)
EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, metadata_len)
EP_DEFINE_GETTER(EventPipeEvent *, event, EventPipeEventLevel, level)
EP_DEFINE_GETTER(EventPipeEvent *, event, bool, need_stack)

Expand Down
7 changes: 5 additions & 2 deletions src/mono/mono/eventpipe/ep-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ ep_file_alloc (
// Start at 0 - The value is always incremented prior to use, so the first ID will be 1.
instance->stack_id_counter = 0;

ep_rt_volatile_store_uint32_t (&instance->initialized, 0);

#ifdef EP_CHECKED_BUILD
instance->last_sorted_timestamp = ep_perf_counter_query ();
#endif
Expand Down Expand Up @@ -368,9 +370,9 @@ ep_file_free (EventPipeFile *file)
ep_rt_metadata_labels_free (&file->metadata_ids);
ep_rt_stack_hash_free (&file->stack_hash);

// If there's no fast_serializer, stream_writer ownership
// If file has not been initialized, stream_writer ownership
// have not been passed along and needs to be freed by file.
if (!file->fast_serializer)
if (ep_rt_volatile_load_uint32_t (&file->initialized) == 0)
ep_stream_writer_free_vcall (file->stream_writer);

ep_fast_serializable_object_fini (&file->fast_serializable_object);
Expand All @@ -393,6 +395,7 @@ ep_file_initialize_file (EventPipeFile *file)
}

if (success) {
ep_rt_volatile_store_uint32_t (&file->initialized, 1);
// Create the file stream and write the FastSerialization header.
file->fast_serializer = ep_fast_serializer_alloc (file->stream_writer);

Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/eventpipe/ep-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct _EventPipeFile_Internal {
uint32_t sampling_rate_in_ns;
uint32_t stack_id_counter;
volatile uint32_t metadata_id_counter;
volatile uint32_t initialized;
// The format to serialize.
EventPipeSerializationFormat format;
};
Expand Down
18 changes: 18 additions & 0 deletions src/mono/mono/eventpipe/ep-provider.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,24 @@ ep_provider_add_event (
ep_exit_error_handler ();
}

void
ep_provider_set_delete_deferred (
EventPipeProvider *provider,
bool deferred)
{
EP_ASSERT (provider != NULL);
provider->delete_deferred = deferred;

// EventSources will be collected once they ungregister themselves,
// so we can't call back in to them.
if (provider->callback_func && provider->callback_data_free_func)
provider->callback_data_free_func (provider->callback_func, provider->callback_data);

provider->callback_func = NULL;
provider->callback_data_free_func = NULL;
provider->callback_data = NULL;
}

const EventPipeProviderCallbackData *
provider_set_config (
EventPipeProvider *provider,
Expand Down
6 changes: 5 additions & 1 deletion src/mono/mono/eventpipe/ep-provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ struct _EventPipeProvider {
EP_DEFINE_GETTER(EventPipeProvider *, provider, const ep_char8_t *, provider_name)
EP_DEFINE_GETTER(EventPipeProvider *, provider, const ep_char16_t *, provider_name_utf16)
EP_DEFINE_GETTER(EventPipeProvider *, provider, bool, delete_deferred)
EP_DEFINE_SETTER(EventPipeProvider *, provider, bool, delete_deferred)
EP_DEFINE_GETTER(EventPipeProvider *, provider, uint64_t, sessions)

static
Expand Down Expand Up @@ -116,5 +115,10 @@ ep_provider_add_event (
const uint8_t *metadata,
uint32_t metadata_len);

void
ep_provider_set_delete_deferred (
EventPipeProvider *provider,
bool deferred);

#endif /* ENABLE_PERFTRACING */
#endif /** __EVENTPIPE_PROVIDER_H__ **/
29 changes: 28 additions & 1 deletion src/mono/mono/eventpipe/ep-rt-mono.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,17 @@
#define EP_RT_DEFINE_ARRAY(array_name, array_type, item_type) \
static inline void ep_rt_ ## array_name ## _alloc (array_type *ep_array) { ep_array->array = g_array_new (FALSE, FALSE, sizeof (item_type)); } \
static inline void ep_rt_ ## array_name ## _free (array_type *ep_array) { g_array_free (ep_array->array, TRUE); } \
static inline void ep_rt_ ## array_name ## _clear (array_type *ep_array) { g_array_set_size (ep_array->array, 0); } \
static inline void ep_rt_ ## array_name ## _append (array_type *ep_array, item_type item) { g_array_append_val (ep_array->array, item); } \
static inline bool ep_rt_ ## array_name ## _remove (array_type *ep_array, const item_type item) { \
for (gint i = 0; i < ep_array->array->len; ++i ) { \
if (g_array_index (ep_array->array, item_type, i) == item) { \
ep_array->array = g_array_remove_index_fast (ep_array->array, i); \
return true; \
} \
} \
return false; \
} \
static inline size_t ep_rt_ ## array_name ## _size (const array_type *ep_array) { return ep_array->array->len; }

#define EP_RT_DEFINE_ARRAY_ITERATOR(array_name, array_type, iterator_type, item_type) \
Expand Down Expand Up @@ -374,6 +384,9 @@ ep_rt_atomic_dec_int64_t (volatile int64_t *value)
* EventPipe.
*/

EP_RT_DEFINE_ARRAY (session_id_array, ep_rt_session_id_array_t, EventPipeSessionID)
EP_RT_DEFINE_ARRAY_ITERATOR (session_id_array, ep_rt_session_id_array_t, ep_rt_session_id_array_iterator_t, EventPipeSessionID)

static
inline
EventPipeThreadHolder *
Expand Down Expand Up @@ -617,7 +630,21 @@ ep_rt_sample_profiler_get_sampling_rate (void)
static
inline
void
ep_rt_sample_set_sampling_rate (uint32_t nanoseconds)
ep_rt_sample_profiler_set_sampling_rate (uint32_t nanoseconds)
{
//TODO: Not supported.
}

static
void
ep_rt_sample_profiler_can_start_sampling (void)
{
//TODO: Not supported.
}

static
void
ep_rt_notify_profiler_provider_created (EventPipeProvider *provider)
{
//TODO: Not supported.
}
Expand Down
3 changes: 3 additions & 0 deletions src/mono/mono/eventpipe/ep-rt-types-mono.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ typedef struct _rt_mono_array_iterator_internal_t ep_rt_buffer_list_array_iterat
typedef struct _rt_mono_array_internal_t ep_rt_thread_array_t;
typedef struct _rt_mono_array_iterator_internal_t ep_rt_thread_array_iterator_t;

typedef struct _rt_mono_array_internal_t ep_rt_session_id_array_t;
typedef struct _rt_mono_array_iterator_internal_t ep_rt_session_id_array_iterator_t;

typedef MonoThreadHandle ep_rt_thread_handle_t;

typedef gpointer ep_rt_file_handle_t;
Expand Down
Loading