Skip to content

Commit 858ec52

Browse files
authored
Port EventPipe CoreCLR changes to Mono. (#41152)
* [MonoVM] Enable startup events over EventPipe. Mono port of CoreCLR PR: #36720. * [MonoVM] Add the ability for profilers to listen to EventPipe events. Mono port of CoreCLR PR: #37002. * [MonoVM] Add ProcessInfo command to Diagnostics Server. Mono port of CoreCLR PR: #38967. * [MonoVM] Unregister callback when setting a provider for deferred delete. Mono port of CoreCLR PR: #40191. * [MonoVM] Generational aware analysis based on environment variable. Mono port of CoreCLR PR: #40332. NOTE, the ability to pause a session was not ported since it currently have no use in Mono and looks like a temporary solution in CoreCLR. * [MonoVM] Rebrand Diagnostics Server to DiagnosticPort. Mono port of CoreCLR PR: #40499.
1 parent c0862a5 commit 858ec52

24 files changed

+514
-213
lines changed

src/mono/mono/eventpipe/ep-buffer-manager.c

Lines changed: 9 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,6 @@ buffer_manager_allocate_buffer_for_thread (
423423

424424
// Allocating a buffer requires us to take the lock.
425425
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section1)
426-
427-
// if we are deallocating then give up, see the comments in ep_buffer_manager_suspend_write_event () for why this is important.
428-
if ((bool)ep_rt_volatile_load_uint32_t (&buffer_manager->write_event_suspending)) {
429-
*write_suspended = true;
430-
ep_raise_error_holding_spin_lock (section1);
431-
}
432-
433426
thread_buffer_list = ep_thread_session_state_get_buffer_list (thread_session_state);
434427
if (thread_buffer_list == NULL) {
435428
thread_buffer_list = ep_buffer_list_alloc (buffer_manager, ep_thread_session_state_get_thread (thread_session_state));
@@ -797,8 +790,6 @@ ep_buffer_manager_alloc (
797790
instance->session = session;
798791
instance->size_of_all_buffers = 0;
799792

800-
ep_rt_volatile_store_uint32_t (&instance->write_event_suspending, (uint32_t)false);
801-
802793
#ifdef EP_CHECKED_BUILD
803794
instance->num_buffers_allocated = 0;
804795
instance->num_buffers_stolen = 0;
@@ -837,8 +828,6 @@ ep_buffer_manager_free (EventPipeBufferManager * buffer_manager)
837828
{
838829
ep_return_void_if_nok (buffer_manager != NULL);
839830

840-
ep_rt_volatile_store_uint32_t (&buffer_manager->write_event_suspending, (uint32_t)true);
841-
842831
ep_buffer_manager_deallocate_buffers (buffer_manager);
843832

844833
ep_rt_wait_event_free (&buffer_manager->rt_wait_event);
@@ -931,10 +920,6 @@ ep_buffer_manager_write_event (
931920
thread_lock = ep_thread_get_rt_lock_ref (current_thread);
932921

933922
EP_SPIN_LOCK_ENTER (thread_lock, section1)
934-
if (ep_rt_volatile_load_uint32_t_without_barrier (&buffer_manager->write_event_suspending) != (uint32_t)false)
935-
// This session is suspending, we need to avoid initializing any session state and exit
936-
ep_raise_error_holding_spin_lock (section1);
937-
938923
session_state = ep_thread_get_or_create_session_state (current_thread, session);
939924
ep_raise_error_if_nok_holding_spin_lock (session_state != NULL, section1);
940925

@@ -977,24 +962,13 @@ ep_buffer_manager_write_event (
977962

978963
thread_lock = ep_thread_get_rt_lock_ref (current_thread);
979964
EP_SPIN_LOCK_ENTER (thread_lock, section3)
980-
if (ep_rt_volatile_load_uint32_t_without_barrier (&buffer_manager->write_event_suspending) != (uint32_t)false) {
981-
// After leaving the manager's lock in buffer_manager_allocated_buffer_for_thread some other thread decided to suspend writes.
982-
// We need to immediately return the buffer we just took without storing it or writing to it.
983-
// suspend_write_event () is spinning waiting for this buffer to be relinquished.
984-
ep_buffer_convert_to_read_only (buffer);
985-
986-
// We treat this as the write_event() call occurring after this session stopped listening for events, effectively the
987-
// same as if ep_event_is_enabled returned false.
988-
ep_raise_error_holding_spin_lock (section3);
989-
} else {
990965
ep_thread_session_state_set_write_buffer (session_state, buffer);
991966
// Try to write the event after we allocated a buffer.
992967
// This is the first time if the thread had no buffers before the call to this function.
993968
// This is the second time if this thread did have one or more buffers, but they were full.
994969
alloc_new_buffer = !ep_buffer_write_event (buffer, event_thread, session, ep_event, payload, activity_id, related_activity_id, stack);
995970
EP_ASSERT(!alloc_new_buffer);
996971
ep_thread_session_state_increment_sequence_number (session_state);
997-
}
998972
EP_SPIN_LOCK_EXIT (thread_lock, section3)
999973
}
1000974
}
@@ -1034,73 +1008,33 @@ ep_buffer_manager_suspend_write_event (
10341008
ep_rt_thread_array_alloc (&thread_array);
10351009
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section1);
10361010
EP_ASSERT (ep_buffer_manager_ensure_consistency (buffer_manager) == true);
1037-
ep_rt_volatile_store_uint32_t (&buffer_manager->write_event_suspending, (uint32_t)true);
1038-
1039-
// From this point until write_event_suspending is reset to false it is impossible
1040-
// for new EventPipeThreadSessionStates to be added to the thread_session_state_list or
1041-
// for new EventBuffers to be added to an existing EventPipeBufferList. The only
1042-
// way ep_buffer_manager_allocate_buffer_for_thread is allowed to add one is by:
1043-
// 1) take rt_lock - ep_buffer_manager_allocate_buffer_for_thread can't own it now because this thread owns it,
1044-
// but after this thread gives it up lower in this function it could be acquired.
1045-
// 2) observe write_event_suspending = false - that won't happen, acquiring rt_lock
1046-
// guarantees ep_buffer_manager_allocate_buffer_for_thread will observe all the memory changes this
1047-
// thread made prior to releasing m_lock and we've already set it true.
1048-
// This ensures that we iterate over the list of threads below we've got the complete list.
1011+
// Find all threads that have used this buffer manager.
10491012
ep_rt_thread_session_state_list_iterator_t thread_session_state_list_iterator;
10501013
ep_rt_thread_session_state_list_iterator_begin (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
10511014
while (!ep_rt_thread_session_state_list_iterator_end (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator)) {
1052-
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)));
1015+
EventPipeThread *thread = ep_thread_session_state_get_thread (ep_rt_thread_session_state_list_iterator_value (&thread_session_state_list_iterator));
1016+
ep_rt_thread_array_append (&thread_array, thread);
10531017
ep_rt_thread_session_state_list_iterator_next (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
1018+
1019+
// Once EventPipeSession::SuspendWriteEvent completes, we shouldn't have any
1020+
// in progress writes left.
1021+
EP_ASSERT (ep_thread_get_session_write_in_progress (thread) != session_index);
10541022
}
10551023
EP_SPIN_LOCK_EXIT (&buffer_manager->rt_lock, section1);
10561024

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

1079-
// Wait for any straggler ep_buffer_manager_write_event threads that may have already allocated a buffer but
1080-
// hadn't yet relinquished it.
1081-
ep_rt_thread_session_state_list_iterator_t thread_session_state_list_iterator;
1082-
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section3)
1083-
ep_rt_thread_session_state_list_iterator_begin (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
1084-
while (!ep_rt_thread_session_state_list_iterator_end (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator)) {
1085-
EventPipeBufferList *buffer_list = ep_thread_session_state_get_buffer_list (ep_rt_thread_session_state_list_iterator_value (&thread_session_state_list_iterator));
1086-
if (buffer_list) {
1087-
EventPipeThread *const event_pipe_thread = ep_buffer_list_get_thread (buffer_list);
1088-
if (event_pipe_thread) {
1089-
EP_YIELD_WHILE (ep_thread_get_session_write_in_progress (event_pipe_thread) == session_index);
1090-
// It still guarantees that the thread has returned its buffer, but it also now guarantees that
1091-
// that the thread has returned from ep_session_write_event () and has relinquished the session pointer
1092-
// This yield is guaranteed to eventually finish because threads will eventually exit write_event ()
1093-
// setting the flag back to -1. If the thread could quickly re-enter WriteEvent and set the flag
1094-
// back to this_session_id we could theoretically get unlucky and never observe the gap, but
1095-
// setting s_pSessions[this_session_id] = NULL above guaranteed that can't happen indefinately.
1096-
// Sooner or later the thread is going to see the NULL value and once it does it won't store
1097-
// this_session_id into the flag again.
1098-
}
1099-
}
1100-
ep_rt_thread_session_state_list_iterator_next (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);
1101-
}
1102-
EP_SPIN_LOCK_EXIT (&buffer_manager->rt_lock, section3)
1103-
11041038
ep_on_exit:
11051039
ep_requires_lock_held ();
11061040
ep_rt_thread_array_free (&thread_array);
@@ -1338,15 +1272,6 @@ ep_buffer_manager_deallocate_buffers (EventPipeBufferManager *buffer_manager)
13381272
// Take the buffer manager manipulation lock
13391273
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section1)
13401274
EP_ASSERT (ep_buffer_manager_ensure_consistency (buffer_manager));
1341-
EP_ASSERT ((bool)ep_rt_volatile_load_uint32_t (&buffer_manager->write_event_suspending));
1342-
1343-
// This m_writeEventSuspending flag + locks ensures that no thread will touch any of the
1344-
// state we are dismantling here. This includes:
1345-
// a) EventPipeThread m_sessions[session_id]
1346-
// b) EventPipeThreadSessionState
1347-
// c) EventPipeBufferList
1348-
// d) EventPipeBuffer
1349-
// e) EventPipeBufferManager.m_pThreadSessionStateList
13501275

13511276
ep_rt_thread_session_state_list_iterator_t thread_session_state_list_iterator;
13521277
ep_rt_thread_session_state_list_iterator_begin (&buffer_manager->thread_session_state_list, &thread_session_state_list_iterator);

src/mono/mono/eventpipe/ep-buffer-manager.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ struct _EventPipeBufferManager_Internal {
134134
uint32_t num_buffers_stolen;
135135
uint32_t num_buffers_leaked;
136136
#endif
137-
volatile uint32_t write_event_suspending;
138137
};
139138

140139
#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_BUFFER_MANAGER_GETTER_SETTER)

src/mono/mono/eventpipe/ep-event-source.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ ep_event_source_enable (
190190
EP_ASSERT (event_source != NULL);
191191
EP_ASSERT (session != NULL);
192192

193+
ep_requires_lock_held ();
194+
193195
EventPipeSessionProvider *session_provider = ep_session_provider_alloc (event_source->provider_name, (uint64_t)-1, EP_EVENT_LEVEL_LOG_ALWAYS, NULL);
194196
if (session_provider != NULL)
195197
ep_session_add_session_provider (session, session_provider);
@@ -207,8 +209,8 @@ ep_event_source_send_process_info (
207209
ep_char16_t *arch_info_utf16 = NULL;
208210

209211
command_line_utf16 = ep_rt_utf8_to_utf16_string (command_line, -1);
210-
os_info_utf16 = ep_rt_utf8_to_utf16_string (_ep_os_info, -1);
211-
arch_info_utf16 = ep_rt_utf8_to_utf16_string (_ep_arch_info, -1);
212+
os_info_utf16 = ep_rt_utf8_to_utf16_string (ep_event_source_get_os_info (), -1);
213+
arch_info_utf16 = ep_rt_utf8_to_utf16_string (ep_event_source_get_arch_info (), -1);
212214

213215
EventData data [3] = { { 0 } };
214216
if (command_line_utf16)

src/mono/mono/eventpipe/ep-event-source.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,24 @@ struct _EventPipeEventSource {
3434
};
3535
#endif
3636

37+
static
38+
inline
39+
const char *
40+
ep_event_source_get_os_info (void)
41+
{
42+
extern const char *_ep_os_info;
43+
return _ep_os_info;
44+
}
45+
46+
static
47+
inline
48+
const char *
49+
ep_event_source_get_arch_info (void)
50+
{
51+
extern const char *_ep_arch_info;
52+
return _ep_arch_info;
53+
}
54+
3755
EventPipeEventSource *
3856
ep_event_source_alloc (void);
3957

src/mono/mono/eventpipe/ep-event.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ struct _EventPipeEvent {
5252
EP_DEFINE_GETTER(EventPipeEvent *, event, uint64_t, keywords)
5353
EP_DEFINE_GETTER_REF(EventPipeEvent *, event, volatile int64_t *, enabled_mask)
5454
EP_DEFINE_SETTER(EventPipeEvent *, event, int64_t, enabled_mask)
55+
EP_DEFINE_GETTER(EventPipeEvent *, event, uint8_t *, metadata)
5556
EP_DEFINE_GETTER(EventPipeEvent *, event, EventPipeProvider *, provider)
5657
EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, event_id)
58+
EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, event_version)
59+
EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, metadata_len)
5760
EP_DEFINE_GETTER(EventPipeEvent *, event, EventPipeEventLevel, level)
5861
EP_DEFINE_GETTER(EventPipeEvent *, event, bool, need_stack)
5962

src/mono/mono/eventpipe/ep-file.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ ep_file_alloc (
340340
// Start at 0 - The value is always incremented prior to use, so the first ID will be 1.
341341
instance->stack_id_counter = 0;
342342

343+
ep_rt_volatile_store_uint32_t (&instance->initialized, 0);
344+
343345
#ifdef EP_CHECKED_BUILD
344346
instance->last_sorted_timestamp = ep_perf_counter_query ();
345347
#endif
@@ -368,9 +370,9 @@ ep_file_free (EventPipeFile *file)
368370
ep_rt_metadata_labels_free (&file->metadata_ids);
369371
ep_rt_stack_hash_free (&file->stack_hash);
370372

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

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

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

src/mono/mono/eventpipe/ep-file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct _EventPipeFile_Internal {
4848
uint32_t sampling_rate_in_ns;
4949
uint32_t stack_id_counter;
5050
volatile uint32_t metadata_id_counter;
51+
volatile uint32_t initialized;
5152
// The format to serialize.
5253
EventPipeSerializationFormat format;
5354
};

src/mono/mono/eventpipe/ep-provider.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,24 @@ ep_provider_add_event (
257257
ep_exit_error_handler ();
258258
}
259259

260+
void
261+
ep_provider_set_delete_deferred (
262+
EventPipeProvider *provider,
263+
bool deferred)
264+
{
265+
EP_ASSERT (provider != NULL);
266+
provider->delete_deferred = deferred;
267+
268+
// EventSources will be collected once they ungregister themselves,
269+
// so we can't call back in to them.
270+
if (provider->callback_func && provider->callback_data_free_func)
271+
provider->callback_data_free_func (provider->callback_func, provider->callback_data);
272+
273+
provider->callback_func = NULL;
274+
provider->callback_data_free_func = NULL;
275+
provider->callback_data = NULL;
276+
}
277+
260278
const EventPipeProviderCallbackData *
261279
provider_set_config (
262280
EventPipeProvider *provider,

src/mono/mono/eventpipe/ep-provider.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ struct _EventPipeProvider {
5656
EP_DEFINE_GETTER(EventPipeProvider *, provider, const ep_char8_t *, provider_name)
5757
EP_DEFINE_GETTER(EventPipeProvider *, provider, const ep_char16_t *, provider_name_utf16)
5858
EP_DEFINE_GETTER(EventPipeProvider *, provider, bool, delete_deferred)
59-
EP_DEFINE_SETTER(EventPipeProvider *, provider, bool, delete_deferred)
6059
EP_DEFINE_GETTER(EventPipeProvider *, provider, uint64_t, sessions)
6160

6261
static
@@ -116,5 +115,10 @@ ep_provider_add_event (
116115
const uint8_t *metadata,
117116
uint32_t metadata_len);
118117

118+
void
119+
ep_provider_set_delete_deferred (
120+
EventPipeProvider *provider,
121+
bool deferred);
122+
119123
#endif /* ENABLE_PERFTRACING */
120124
#endif /** __EVENTPIPE_PROVIDER_H__ **/

src/mono/mono/eventpipe/ep-rt-mono.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,17 @@
7575
#define EP_RT_DEFINE_ARRAY(array_name, array_type, item_type) \
7676
static inline void ep_rt_ ## array_name ## _alloc (array_type *ep_array) { ep_array->array = g_array_new (FALSE, FALSE, sizeof (item_type)); } \
7777
static inline void ep_rt_ ## array_name ## _free (array_type *ep_array) { g_array_free (ep_array->array, TRUE); } \
78+
static inline void ep_rt_ ## array_name ## _clear (array_type *ep_array) { g_array_set_size (ep_array->array, 0); } \
7879
static inline void ep_rt_ ## array_name ## _append (array_type *ep_array, item_type item) { g_array_append_val (ep_array->array, item); } \
80+
static inline bool ep_rt_ ## array_name ## _remove (array_type *ep_array, const item_type item) { \
81+
for (gint i = 0; i < ep_array->array->len; ++i ) { \
82+
if (g_array_index (ep_array->array, item_type, i) == item) { \
83+
ep_array->array = g_array_remove_index_fast (ep_array->array, i); \
84+
return true; \
85+
} \
86+
} \
87+
return false; \
88+
} \
7989
static inline size_t ep_rt_ ## array_name ## _size (const array_type *ep_array) { return ep_array->array->len; }
8090

8191
#define EP_RT_DEFINE_ARRAY_ITERATOR(array_name, array_type, iterator_type, item_type) \
@@ -374,6 +384,9 @@ ep_rt_atomic_dec_int64_t (volatile int64_t *value)
374384
* EventPipe.
375385
*/
376386

387+
EP_RT_DEFINE_ARRAY (session_id_array, ep_rt_session_id_array_t, EventPipeSessionID)
388+
EP_RT_DEFINE_ARRAY_ITERATOR (session_id_array, ep_rt_session_id_array_t, ep_rt_session_id_array_iterator_t, EventPipeSessionID)
389+
377390
static
378391
inline
379392
EventPipeThreadHolder *
@@ -617,7 +630,21 @@ ep_rt_sample_profiler_get_sampling_rate (void)
617630
static
618631
inline
619632
void
620-
ep_rt_sample_set_sampling_rate (uint32_t nanoseconds)
633+
ep_rt_sample_profiler_set_sampling_rate (uint32_t nanoseconds)
634+
{
635+
//TODO: Not supported.
636+
}
637+
638+
static
639+
void
640+
ep_rt_sample_profiler_can_start_sampling (void)
641+
{
642+
//TODO: Not supported.
643+
}
644+
645+
static
646+
void
647+
ep_rt_notify_profiler_provider_created (EventPipeProvider *provider)
621648
{
622649
//TODO: Not supported.
623650
}

0 commit comments

Comments
 (0)