@@ -482,14 +482,6 @@ writer_get_or_create_thread_entry(BinaryWriter *writer, uint64_t thread_id,
482482 entry -> thread_id = thread_id ;
483483 entry -> interpreter_id = interpreter_id ;
484484 entry -> block_stream_index = UINT32_MAX ;
485- entry -> current_repeat = UINT32_MAX ;
486- entry -> prev_stack_capacity = MAX_STACK_DEPTH ;
487-
488- entry -> prev_stack = PyMem_Calloc (entry -> prev_stack_capacity , sizeof (uint32_t ));
489- if (!entry -> prev_stack ) {
490- PyErr_NoMemory ();
491- return NULL ;
492- }
493485
494486 writer -> thread_count ++ ;
495487 if (is_new ) {
@@ -637,6 +629,11 @@ static void
637629block_reset (BinaryWriter * writer )
638630{
639631 SampleBlock * block = writer -> block ;
632+ /* Only threads with a stream in this block need resetting */
633+ for (uint32_t i = 0 ; i < block -> stream_count ; i ++ ) {
634+ size_t thread = block -> streams [i ].thread_index ;
635+ writer -> thread_entries [thread ].block_stream_index = UINT32_MAX ;
636+ }
640637 for (unsigned column = 0 ; column < COLUMN_COUNT ; column ++ ) {
641638 block -> columns [column ].size = 0 ;
642639 }
@@ -646,10 +643,6 @@ block_reset(BinaryWriter *writer)
646643 block -> max_frame = 0 ;
647644 block -> size = 0 ;
648645 memset (block -> cache , 0 , sizeof (block -> cache ));
649- for (size_t thread = 0 ; thread < writer -> thread_count ; thread ++ ) {
650- writer -> thread_entries [thread ].block_stream_index = UINT32_MAX ;
651- writer -> thread_entries [thread ].current_repeat = UINT32_MAX ;
652- }
653646}
654647
655648static unsigned
@@ -780,13 +773,13 @@ stack_hash(const uint32_t *stack, size_t depth)
780773}
781774
782775static size_t
783- common_outer_frames (const ThreadEntry * entry , const uint32_t * stack ,
776+ common_outer_frames (const BlockStream * stream , const uint32_t * stack ,
784777 size_t depth )
785778{
786779 size_t shared = 0 ;
787- while (shared < depth && shared < entry -> prev_stack_depth &&
780+ while (shared < depth && shared < stream -> prev_stack_depth &&
788781 stack [depth - 1 - shared ] ==
789- entry -> prev_stack [entry -> prev_stack_depth - 1 - shared ]) {
782+ stream -> prev_stack [stream -> prev_stack_depth - 1 - shared ]) {
790783 shared ++ ;
791784 }
792785 return shared ;
@@ -831,24 +824,24 @@ stack_cache_insert(StackCacheEntry *bucket, StackCacheEntry entry)
831824}
832825
833826static int
834- write_stack_repeat (BinaryWriter * writer , ThreadEntry * entry , size_t depth )
827+ write_stack_repeat (BinaryWriter * writer , BlockStream * stream , size_t depth )
835828{
836829 SampleBlock * block = writer -> block ;
837- if (entry -> current_repeat == UINT32_MAX ) {
830+ if (stream -> current_repeat == UINT32_MAX ) {
838831 Repeat repeat = {
839832 (uint32_t )block -> columns [COLUMN_STACK_INSTRUCTIONS ].size , 1 };
840833 if (buffer_append (& block -> repeats ,
841834 & repeat , sizeof (repeat )) < 0 ) {
842835 return -1 ;
843836 }
844837 block -> size += sizeof (repeat );
845- entry -> current_repeat =
838+ stream -> current_repeat =
846839 (uint32_t )(block -> repeats .size / sizeof (repeat ) - 1 );
847840 writer -> stats .repeat_records ++ ;
848841 }
849842 else {
850843 Repeat * repeats = (Repeat * )block -> repeats .data ;
851- repeats [entry -> current_repeat ].count ++ ;
844+ repeats [stream -> current_repeat ].count ++ ;
852845 }
853846 writer -> stats .repeat_samples ++ ;
854847 writer -> stats .frames_saved += depth ;
@@ -923,15 +916,15 @@ write_stack_replace_suffix(BinaryWriter *writer, StackCacheEntry *bucket,
923916}
924917
925918static int
926- write_stack (BinaryWriter * writer , ThreadEntry * entry , int new_stream ,
919+ write_stack (BinaryWriter * writer , BlockStream * stream , int new_stream ,
927920 const uint32_t * stack , size_t depth )
928921{
929922 SampleBlock * block = writer -> block ;
930- size_t shared = common_outer_frames (entry , stack , depth );
923+ size_t shared = common_outer_frames (stream , stack , depth );
931924 /* Same stack as this stream's previous sample: extend its REPEAT */
932925 if (!new_stream && shared == depth &&
933- shared == entry -> prev_stack_depth ) {
934- return write_stack_repeat (writer , entry , depth );
926+ shared == stream -> prev_stack_depth ) {
927+ return write_stack_repeat (writer , stream , depth );
935928 }
936929
937930 /* Enough new frames to be worth looking up an earlier complete stack */
@@ -958,9 +951,9 @@ write_stack(BinaryWriter *writer, ThreadEntry *entry, int new_stream,
958951 if (result < 0 ) {
959952 return -1 ;
960953 }
961- entry -> current_repeat = UINT32_MAX ;
962- memcpy (entry -> prev_stack , stack , depth * sizeof (uint32_t ));
963- entry -> prev_stack_depth = depth ;
954+ stream -> current_repeat = UINT32_MAX ;
955+ memcpy (stream -> prev_stack , stack , depth * sizeof (uint32_t ));
956+ stream -> prev_stack_depth = depth ;
964957 return 0 ;
965958}
966959
@@ -995,6 +988,10 @@ static int
995988block_add_stream (BinaryWriter * writer , ThreadEntry * entry )
996989{
997990 SampleBlock * block = writer -> block ;
991+ if (GROW_ARRAY (block -> streams , block -> stream_count ,
992+ block -> stream_capacity , BlockStream ) < 0 ) {
993+ return -1 ;
994+ }
998995 /* Stream table entry: thread_id (8 bytes) + interpreter_id (4 bytes) */
999996 uint8_t stream_entry [STREAM_ENTRY_SIZE ];
1000997 memcpy (stream_entry + STM_OFF_THREAD_ID ,
@@ -1005,9 +1002,12 @@ block_add_stream(BinaryWriter *writer, ThreadEntry *entry)
10051002 stream_entry , sizeof (stream_entry )) < 0 ) {
10061003 return -1 ;
10071004 }
1005+ BlockStream * stream = & block -> streams [block -> stream_count ];
1006+ stream -> thread_index = (size_t )(entry - writer -> thread_entries );
1007+ stream -> prev_timestamp = block -> base_timestamp - writer -> sample_interval_us ;
1008+ stream -> current_repeat = UINT32_MAX ;
1009+ stream -> prev_stack_depth = 0 ;
10081010 entry -> block_stream_index = block -> stream_count ++ ;
1009- entry -> prev_timestamp = block -> base_timestamp - writer -> sample_interval_us ;
1010- entry -> prev_stack_depth = 0 ;
10111011 return 0 ;
10121012}
10131013
@@ -1036,9 +1036,10 @@ block_add_sample(BinaryWriter *writer, ThreadEntry *entry,
10361036 if (new_stream && block_add_stream (writer , entry ) < 0 ) {
10371037 return -1 ;
10381038 }
1039+ BlockStream * stream = & block -> streams [entry -> block_stream_index ];
10391040 /* Store the difference from the expected timestamp */
10401041 uint64_t residual =
1041- timestamp - entry -> prev_timestamp - writer -> sample_interval_us ;
1042+ timestamp - stream -> prev_timestamp - writer -> sample_interval_us ;
10421043 uint8_t residual_bytes [MAX_VARINT_SIZE ];
10431044 size_t residual_size =
10441045 encode_varint_i64 (residual_bytes , (int64_t )residual );
@@ -1050,10 +1051,10 @@ block_add_sample(BinaryWriter *writer, ThreadEntry *entry,
10501051 & status , sizeof (status )) < 0 ) {
10511052 return -1 ;
10521053 }
1053- if (write_stack (writer , entry , new_stream , stack , depth ) < 0 ) {
1054+ if (write_stack (writer , stream , new_stream , stack , depth ) < 0 ) {
10541055 return -1 ;
10551056 }
1056- entry -> prev_timestamp = timestamp ;
1057+ stream -> prev_timestamp = timestamp ;
10571058 block -> sample_count ++ ;
10581059 writer -> total_samples ++ ;
10591060 return 0 ;
@@ -1072,6 +1073,7 @@ block_destroy(SampleBlock *block)
10721073 buffer_clear (& block -> transformed );
10731074 buffer_clear (& block -> compressed );
10741075 buffer_clear (& block -> output );
1076+ PyMem_Free (block -> streams );
10751077 PyMem_Free (block );
10761078}
10771079
@@ -1102,6 +1104,13 @@ binary_writer_create(PyObject *path, uint64_t sample_interval_us, int compressio
11021104 PyErr_NoMemory ();
11031105 goto error ;
11041106 }
1107+ writer -> block -> streams = PyMem_Malloc (
1108+ INITIAL_BLOCK_STREAM_CAPACITY * sizeof (BlockStream ));
1109+ if (writer -> block -> streams == NULL ) {
1110+ PyErr_NoMemory ();
1111+ goto error ;
1112+ }
1113+ writer -> block -> stream_capacity = INITIAL_BLOCK_STREAM_CAPACITY ;
11051114
11061115 writer -> string_hash = _Py_hashtable_new_full (
11071116 string_hash_func ,
@@ -1591,12 +1600,7 @@ binary_writer_destroy(BinaryWriter *writer)
15911600 }
15921601 PyMem_Free (writer -> frame_entries );
15931602
1594- if (writer -> thread_entries ) {
1595- for (size_t i = 0 ; i < writer -> thread_count ; i ++ ) {
1596- PyMem_Free (writer -> thread_entries [i ].prev_stack );
1597- }
1598- PyMem_Free (writer -> thread_entries );
1599- }
1603+ PyMem_Free (writer -> thread_entries );
16001604
16011605 PyMem_Free (writer );
16021606}
0 commit comments