Skip to content

Commit 323d1fe

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 86b0fad commit 323d1fe

File tree

6 files changed

+36
-100
lines changed

6 files changed

+36
-100
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: 22 additions & 69 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
@@ -737,15 +737,8 @@ buffer_manager_advance_to_non_empty_buffer (
737737
// get the next buffer
738738
current_buffer = buffer_list->head_buffer;
739739

740-
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)) {
741-
if (buffer_manager->sequence_point_alloc_budget != 0) {
742-
// The next sequence point needs to update the sequence number for this thread
743-
// Delay the thread session state removal until the next sequence point is written.
744-
ep_thread_session_state_set_delete_deferred (thread_session_state, true);
745-
} else {
746-
buffer_manager_remove_and_delete_thread_session_state (buffer_manager, thread_session_state);
747-
}
748-
}
740+
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))
741+
buffer_manager_remove_and_delete_thread_session_state (buffer_manager, thread_session_state);
749742

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

1192-
uint64_t capture_thread_id = ep_thread_get_os_thread_id (ep_buffer_get_writer_thread (buffer_manager->current_buffer));
1185+
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)));
11931186

11941187
EventPipeThreadSessionState *current_thread_session_state = buffer_manager->current_thread_session_state;
1188+
ep_rt_thread_id_t os_thread_id = ep_thread_get_os_thread_id (ep_thread_session_state_get_thread (current_thread_session_state));
11951189

11961190
// loop across events on this thread
11971191
bool events_written_for_thread = false;
@@ -1208,11 +1202,23 @@ ep_buffer_manager_write_all_buffers_to_file_v4 (
12081202
buffer_manager_move_next_event_same_thread (buffer_manager, current_timestamp_boundary);
12091203
}
12101204

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

12181224
// Have we written events in any sequence point?
@@ -1228,42 +1234,11 @@ ep_buffer_manager_write_all_buffers_to_file_v4 (
12281234

12291235
// stopped at sequence point case
12301236

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

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

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

13851339
dn_list_remove (buffer_manager->thread_session_state_list, thread_session_state);
13861340
ep_thread_set_session_state (ep_thread_session_state_get_thread (thread_session_state), ep_thread_session_state_get_session (thread_session_state), NULL);
1387-
buffer_manager_remove_thread_session_state_from_sequence_points (buffer_manager, thread_session_state);
13881341
ep_thread_session_state_free (thread_session_state);
13891342
}
13901343

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 = p_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 ((void *)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)