Skip to content

Commit d184ddb

Browse files
committed
[EventPipe] Optimize SequencePoint maps and TSS cleanup
Now that EventPipeThreads lifetimes do not depend on SequencePoint lifetimes, the following can be optimized: 1) SequencePoints directly map native thread ids There is no dependence on keeping a thread alive, and so ref counting can be removed and thread ids can be used as keys. 2) ThreadSessionStates can be cleaned up without waiting for sequence points that refer to the thread id to be written
1 parent 85178f6 commit d184ddb

File tree

6 files changed

+35
-99
lines changed

6 files changed

+35
-99
lines changed

src/native/eventpipe/ep-block.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -906,10 +906,10 @@ ep_sequence_point_block_init (
906906
const uint32_t thread_count = dn_umap_size (map);
907907
ep_write_buffer_uint32_t (&sequence_point_block->block.write_pointer, thread_count);
908908

909-
DN_UMAP_FOREACH_BEGIN (const EventPipeThreadSessionState *, key, uint32_t, sequence_number, map) {
909+
DN_UMAP_FOREACH_BEGIN (ep_rt_thread_id_t, key, uint32_t, sequence_number, map) {
910910
ep_write_buffer_uint64_t (
911911
&sequence_point_block->block.write_pointer,
912-
ep_thread_get_os_thread_id (ep_thread_session_state_get_thread (key)));
912+
ep_rt_thread_id_t_to_uint64_t (key));
913913

914914
ep_write_buffer_uint32_t (
915915
&sequence_point_block->block.write_pointer,

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

Lines changed: 21 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,8 @@ buffer_manager_init_sequence_point_thread_list (
429429
ep_thread_session_state_set_track_state (thread_session_state, EP_SEQUENCE_POINT_THREAD_ID_TRACKED);
430430
}
431431

432-
dn_umap_ptr_uint32_insert (ep_sequence_point_get_thread_sequence_numbers (sequence_point), thread_session_state, sequence_number);
433-
ep_thread_addref (ep_thread_holder_get_thread (ep_thread_session_state_get_thread_holder_ref (thread_session_state)));
432+
ep_rt_thread_id_t os_thread_id = ep_thread_get_os_thread_id (ep_thread_session_state_get_thread (thread_session_state));
433+
dn_umap_threadid_uint32_insert (ep_sequence_point_get_thread_sequence_numbers (sequence_point), os_thread_id, sequence_number);
434434
} DN_LIST_FOREACH_END;
435435

436436
// This needs to come after querying the thread sequence numbers to ensure that any recorded
@@ -736,15 +736,8 @@ buffer_manager_advance_to_non_empty_buffer (
736736
// get the next buffer
737737
current_buffer = buffer_list->head_buffer;
738738

739-
if (!current_buffer && (ep_rt_volatile_load_uint32_t_without_barrier (ep_thread_get_unregistered_ref (ep_thread_session_state_get_thread (thread_session_state))) > 0)) {
740-
if (buffer_manager->sequence_point_alloc_budget != 0) {
741-
// The next sequence point needs to update the sequence number for this thread
742-
// Delay the thread session state removal until the next sequence point is written.
743-
ep_thread_session_state_set_delete_deferred (thread_session_state, true);
744-
} else {
745-
buffer_manager_remove_and_delete_thread_session_state (buffer_manager, thread_session_state);
746-
}
747-
}
739+
if (!current_buffer && (ep_rt_volatile_load_uint32_t_without_barrier (ep_thread_get_unregistered_ref (ep_thread_session_state_get_thread (thread_session_state))) > 0))
740+
buffer_manager_remove_and_delete_thread_session_state (buffer_manager, thread_session_state);
748741

749742
if (!current_buffer || ep_buffer_get_creation_timestamp (current_buffer) >= before_timestamp) {
750743
// no more buffers in the list before this timestamp, we're done
@@ -1188,9 +1181,10 @@ ep_buffer_manager_write_all_buffers_to_file_v4 (
11881181
if (buffer_manager->current_event == NULL)
11891182
break;
11901183

1191-
uint64_t capture_thread_id = ep_thread_get_os_thread_id (ep_buffer_get_writer_thread (buffer_manager->current_buffer));
1184+
uint64_t capture_thread_id = ep_rt_thread_id_t_to_uint64_t (ep_thread_get_os_thread_id (ep_buffer_get_writer_thread (buffer_manager->current_buffer)));
11921185

11931186
EventPipeThreadSessionState *current_thread_session_state = buffer_manager->current_thread_session_state;
1187+
ep_rt_thread_id_t os_thread_id = ep_thread_get_os_thread_id (ep_thread_session_state_get_thread (current_thread_session_state));
11941188

11951189
// loop across events on this thread
11961190
bool events_written_for_thread = false;
@@ -1207,11 +1201,23 @@ ep_buffer_manager_write_all_buffers_to_file_v4 (
12071201
buffer_manager_move_next_event_same_thread (buffer_manager, current_timestamp_boundary);
12081202
}
12091203

1210-
ep_thread_session_state_set_last_read_sequence_number (current_thread_session_state, sequence_number);
1204+
dn_list_it_t found = dn_list_find (buffer_manager->thread_session_state_list, current_thread_session_state);
1205+
if (!dn_list_it_end (found)) {
1206+
// If the ThreadSessionState hasn't been removed through buffer_manager_advance_to_non_empty_buffer,
1207+
// we need to update the last_read_sequence_number for any future sequence points being initialized.
1208+
ep_thread_session_state_set_last_read_sequence_number (current_thread_session_state, sequence_number);
1209+
}
1210+
12111211
if (sequence_point != NULL) {
1212-
dn_umap_it_t found = dn_umap_ptr_uint32_find (ep_sequence_point_get_thread_sequence_numbers (sequence_point), current_thread_session_state);
1212+
dn_umap_it_t found = dn_umap_threadid_uint32_find (ep_sequence_point_get_thread_sequence_numbers (sequence_point), os_thread_id);
12131213
EP_ASSERT (!dn_umap_it_end (found));
1214-
dn_umap_ptr_uint32_insert_or_assign (ep_sequence_point_get_thread_sequence_numbers (sequence_point), current_thread_session_state, sequence_number);
1214+
uint32_t thread_sequence_number = !dn_umap_it_end (found) ? dn_umap_it_value_uint32_t (found) : 0;
1215+
// Sequence numbers can overflow so we can't use a direct last_read > sequence_number comparison
1216+
// If a thread is able to drop more than 0x80000000 events in between sequence points then we will
1217+
// miscategorize it, but that seems unlikely.
1218+
uint32_t last_read_delta = sequence_number - thread_sequence_number;
1219+
if (0 < last_read_delta && last_read_delta < 0x80000000)
1220+
dn_umap_threadid_uint32_insert_or_assign (ep_sequence_point_get_thread_sequence_numbers (sequence_point), os_thread_id, sequence_number);
12151221
}
12161222

12171223
// Have we written events in any sequence point?
@@ -1227,42 +1233,11 @@ ep_buffer_manager_write_all_buffers_to_file_v4 (
12271233

12281234
// stopped at sequence point case
12291235

1230-
// the sequence point captured a lower bound for sequence number on each thread, but iterating
1231-
// through the events we may have observed that a higher numbered event was recorded. If so we
1232-
// should adjust the sequence numbers upwards to ensure the data in the stream is consistent.
1233-
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section2)
1234-
for (dn_list_it_t it = dn_list_begin (buffer_manager->thread_session_state_list); !dn_list_it_end (it); ) {
1235-
EventPipeThreadSessionState *session_state = *dn_list_it_data_t (it, EventPipeThreadSessionState *);
1236-
dn_umap_it_t found = dn_umap_ptr_uint32_find (ep_sequence_point_get_thread_sequence_numbers (sequence_point), session_state);
1237-
uint32_t thread_sequence_number = !dn_umap_it_end (found) ? dn_umap_it_value_uint32_t (found) : 0;
1238-
uint32_t last_read_sequence_number = ep_thread_session_state_get_last_read_sequence_number (session_state);
1239-
EP_ASSERT (thread_sequence_number == 0 || thread_sequence_number == last_read_sequence_number);
1240-
// Sequence numbers can overflow so we can't use a direct last_read > sequence_number comparison
1241-
// If a thread is able to drop more than 0x80000000 events in between sequence points then we will
1242-
// miscategorize it, but that seems unlikely.
1243-
uint32_t last_read_delta = last_read_sequence_number - thread_sequence_number;
1244-
if (0 < last_read_delta && last_read_delta < 0x80000000) {
1245-
dn_umap_ptr_uint32_insert_or_assign (ep_sequence_point_get_thread_sequence_numbers (sequence_point), session_state, last_read_sequence_number);
1246-
if (dn_umap_it_end (found))
1247-
ep_thread_addref (ep_thread_holder_get_thread (ep_thread_session_state_get_thread_holder_ref (session_state)));
1248-
}
1249-
1250-
it = dn_list_it_next (it);
1251-
1252-
if (ep_thread_session_state_get_delete_deferred (session_state))
1253-
dn_vector_ptr_push_back (&session_states_to_delete, session_state);
1254-
}
1255-
EP_SPIN_LOCK_EXIT (&buffer_manager->rt_lock, section2)
1256-
12571236
// emit the sequence point into the file
12581237
ep_file_write_sequence_point (file, sequence_point);
12591238

12601239
// we are done with the sequence point
12611240
EP_SPIN_LOCK_ENTER (&buffer_manager->rt_lock, section3)
1262-
DN_VECTOR_PTR_FOREACH_BEGIN (EventPipeThreadSessionState *, thread_session_state, &session_states_to_delete) {
1263-
if (ep_thread_session_state_get_delete_deferred (thread_session_state))
1264-
buffer_manager_remove_and_delete_thread_session_state (buffer_manager, thread_session_state);
1265-
} DN_VECTOR_PTR_FOREACH_END;
12661241
buffer_manager_dequeue_sequence_point (buffer_manager);
12671242
sequence_point = NULL;
12681243
EP_SPIN_LOCK_EXIT (&buffer_manager->rt_lock, section3)
@@ -1349,27 +1324,6 @@ ep_buffer_manager_ensure_consistency (EventPipeBufferManager *buffer_manager)
13491324
}
13501325
#endif
13511326

1352-
static
1353-
void
1354-
buffer_manager_remove_thread_session_state_from_sequence_points (
1355-
EventPipeBufferManager *buffer_manager,
1356-
EventPipeThreadSessionState *thread_session_state)
1357-
{
1358-
EP_ASSERT (buffer_manager != NULL);
1359-
EP_ASSERT (thread_session_state != NULL);
1360-
1361-
ep_buffer_manager_requires_lock_held (buffer_manager);
1362-
1363-
DN_LIST_FOREACH_BEGIN (EventPipeSequencePoint *, current_sequence_point, buffer_manager->sequence_points) {
1364-
dn_umap_it_t found = dn_umap_ptr_uint32_find (ep_sequence_point_get_thread_sequence_numbers (current_sequence_point), thread_session_state);
1365-
if (!dn_umap_it_end (found)) {
1366-
dn_umap_erase (found);
1367-
// buffer_manager_init_sequence_point_thread_list - every entry of this map was holding an extra ref to the thread
1368-
ep_thread_release (ep_thread_session_state_get_thread (thread_session_state));
1369-
}
1370-
} DN_LIST_FOREACH_END;
1371-
}
1372-
13731327
static
13741328
void
13751329
buffer_manager_remove_and_delete_thread_session_state (
@@ -1383,7 +1337,6 @@ buffer_manager_remove_and_delete_thread_session_state (
13831337

13841338
dn_list_remove (buffer_manager->thread_session_state_list, thread_session_state);
13851339
ep_thread_set_session_state (ep_thread_session_state_get_thread (thread_session_state), ep_thread_session_state_get_session (thread_session_state), NULL);
1386-
buffer_manager_remove_thread_session_state_from_sequence_points (buffer_manager, thread_session_state);
13871340
ep_thread_session_state_free (thread_session_state);
13881341
}
13891342

src/native/eventpipe/ep-event-instance.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,6 @@ void
228228
sequence_point_fini (EventPipeSequencePoint *sequence_point)
229229
{
230230
EP_ASSERT (sequence_point != NULL);
231-
232-
// Each entry in the map owns a ref-count on the corresponding thread
233-
if (dn_umap_size (sequence_point->thread_sequence_numbers) != 0) {
234-
DN_UMAP_FOREACH_KEY_BEGIN (EventPipeThreadSessionState *, key, sequence_point->thread_sequence_numbers) {
235-
ep_thread_release (ep_thread_session_state_get_thread (key));
236-
} DN_UMAP_FOREACH_END;
237-
}
238-
239231
dn_umap_free (sequence_point->thread_sequence_numbers);
240232
}
241233

src/native/eventpipe/ep-thread.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ ep_thread_alloc (void)
3131
EventPipeThread *instance = ep_rt_object_alloc (EventPipeThread);
3232
ep_raise_error_if_nok (instance != NULL);
3333

34-
instance->os_thread_id = ep_rt_thread_id_t_to_uint64_t (ep_rt_current_thread_get_id ());
34+
instance->os_thread_id = ep_rt_current_thread_get_id ();
3535
memset (instance->session_state, 0, sizeof (instance->session_state));
3636

3737
instance->writing_event_in_progress = UINT32_MAX;
@@ -127,12 +127,8 @@ ep_thread_unregister (EventPipeThread *thread)
127127
EventPipeBufferManager *buffer_manager = ep_session_get_buffer_manager (thread_session_state->session);
128128
EP_ASSERT (buffer_manager != NULL);
129129

130-
if (ep_buffer_list_is_empty (thread_session_state->buffer_list)) {
131-
if (ep_buffer_manager_uses_sequence_points (buffer_manager))
132-
thread_session_state->delete_deferred = true;
133-
else
134-
ep_buffer_manager_remove_and_delete_thread_session_state (buffer_manager, thread_session_state);
135-
}
130+
if (ep_buffer_list_is_empty (thread_session_state->buffer_list))
131+
ep_buffer_manager_remove_and_delete_thread_session_state (buffer_manager, thread_session_state);
136132
}
137133

138134
bool found = false;
@@ -338,7 +334,6 @@ ep_thread_session_state_alloc (
338334
instance->buffer_list = ep_buffer_list_alloc (buffer_manager, thread);
339335
ep_raise_error_if_nok (instance->buffer_list != NULL);
340336

341-
instance->delete_deferred = false;
342337
instance->track_state = EP_SEQUENCE_POINT_THREAD_ID_UNTRACKED;
343338

344339
ep_on_exit:

src/native/eventpipe/ep-thread.h

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct _EventPipeThread_Internal {
5454
EventPipeSession *rundown_session;
5555
// This is initialized when the Thread object is first constructed and remains
5656
// immutable afterwards.
57-
uint64_t os_thread_id;
57+
ep_rt_thread_id_t os_thread_id;
5858
// The EventPipeThreadHolder maintains one count while the thread is alive
5959
// and each session's EventPipeBufferList maintains one count while it
6060
// exists.
@@ -90,7 +90,7 @@ ep_thread_get_activity_id_cref (ep_rt_thread_activity_id_handle_t activity_id_ha
9090

9191
EP_DEFINE_GETTER(EventPipeThread *, thread, EventPipeSession *, rundown_session);
9292
EP_DEFINE_SETTER(EventPipeThread *, thread, EventPipeSession *, rundown_session);
93-
EP_DEFINE_GETTER(EventPipeThread *, thread, uint64_t, os_thread_id);
93+
EP_DEFINE_GETTER(EventPipeThread *, thread, ep_rt_thread_id_t, os_thread_id);
9494
EP_DEFINE_GETTER_REF(EventPipeThread *, thread, int32_t *, ref_count);
9595
EP_DEFINE_GETTER_REF(EventPipeThread *, thread, volatile uint32_t *, unregistered);
9696

@@ -293,15 +293,6 @@ struct _EventPipeThreadSessionState_Internal {
293293
// buffers are later read and there are fewer than X events timestamped
294294
// prior to the sequence point we can be certain the others were dropped.
295295
volatile uint32_t sequence_number;
296-
// An ThreadSessionState is no longer needed when the following are met:
297-
// 1. The thread is unregistered - No more events can be written.
298-
// 2. The buffers are empty - No more events need to be flushed.
299-
// 3. The following SequencePoint is written - No more mapped sequence
300-
// numbers need to be updated.
301-
// If this is set to true, that means we have detected 1 and 2 through
302-
// buffer_manager_advance_to_non_empty_buffer, but sequence points are active,
303-
// so we defer the deletion until the next sequence point updates its map.
304-
bool delete_deferred;
305296
EventPipeThreadSequencePointTrackState track_state;
306297
};
307298

@@ -315,8 +306,6 @@ EP_DEFINE_GETTER_REF(EventPipeThreadSessionState *, thread_session_state, EventP
315306
EP_DEFINE_GETTER(EventPipeThreadSessionState *, thread_session_state, EventPipeSession *, session)
316307
EP_DEFINE_GETTER(EventPipeThreadSessionState *, thread_session_state, uint32_t, last_read_sequence_number)
317308
EP_DEFINE_SETTER(EventPipeThreadSessionState *, thread_session_state, uint32_t, last_read_sequence_number)
318-
EP_DEFINE_GETTER(EventPipeThreadSessionState *, thread_session_state, bool, delete_deferred)
319-
EP_DEFINE_SETTER(EventPipeThreadSessionState *, thread_session_state, bool, delete_deferred)
320309
EP_DEFINE_GETTER(EventPipeThreadSessionState *, thread_session_state, EventPipeThreadSequencePointTrackState, track_state)
321310
EP_DEFINE_SETTER(EventPipeThreadSessionState *, thread_session_state, EventPipeThreadSequencePointTrackState, track_state)
322311

src/native/eventpipe/ep-types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,5 +411,12 @@ ep_system_time_set (
411411
uint16_t second,
412412
uint16_t milliseconds);
413413

414+
/*
415+
* EventPipe-specific container type definitions.
416+
*/
417+
418+
DN_UMAP_IT_KEY_T (threadid, ep_rt_thread_id_t)
419+
DN_UMAP_T (threadid, ep_rt_thread_id_t, uint32, uint32_t)
420+
414421
#endif /* ENABLE_PERFTRACING */
415422
#endif /* __EVENTPIPE_TYPES_H__ */

0 commit comments

Comments
 (0)