@@ -127,8 +127,13 @@ static bool EvalContextClassPut(EvalContext *ctx, const char *ns, const char *na
127127static const char * EvalContextCurrentNamespace (const EvalContext * ctx );
128128static ClassRef IDRefQualify (const EvalContext * ctx , const char * id );
129129
130- static EventFrame * EventFrameCreate (char * type , const char * name , const char * source , SourceOffset offset );
130+ static EventFrame * EventFrameCreate (char * type , const char * name , const char * source , SourceOffset offset , char * id );
131131static void EventFrameDestroy (EventFrame * event );
132+
133+ static char * BundleGetCallStackID (const Bundle * bp );
134+ static char * PromiseGetCallStackID (const Promise * pp );
135+ static char * FunctionGetCallStackID (const FnCall * fp );
136+
132137static EventFrame * BundleToEventFrame (const Bundle * bp );
133138static EventFrame * PromiseToEventFrame (const Promise * pp );
134139static EventFrame * FunctionToEventFrame (const FnCall * fp );
@@ -349,6 +354,20 @@ static StackFrame *LastStackFrameByType(const EvalContext *ctx, StackFrameType t
349354 return NULL ;
350355}
351356
357+ static StackFrame * LastStackFrameByEvent (const EvalContext * ctx )
358+ {
359+ for (size_t i = 0 ; i < SeqLength (ctx -> stack ); i ++ )
360+ {
361+ StackFrame * frame = LastStackFrame (ctx , i );
362+ if (frame -> event != NULL )
363+ {
364+ return frame ;
365+ }
366+ }
367+
368+ return NULL ;
369+ }
370+
352371static LogLevel AdjustLogLevel (LogLevel base , LogLevel adjust )
353372{
354373 if (adjust == -1 )
@@ -1443,7 +1462,22 @@ void EvalContextStackPushBundleFrame(EvalContext *ctx, const Bundle *owner, cons
14431462 assert (ctx != NULL );
14441463 assert (!LastStackFrame (ctx , 0 ) || LastStackFrame (ctx , 0 )-> type == STACK_FRAME_TYPE_PROMISE_ITERATION );
14451464
1446- EvalContextStackPushFrame (ctx , StackFrameNewBundle (owner , inherits_previous , ctx -> profiling ));
1465+ StackFrame * prev_frame = LastStackFrameByEvent (ctx );
1466+ StackFrame * frame = StackFrameNewBundle (owner , inherits_previous , ctx -> profiling );
1467+
1468+ EventFrame * pushed_event = frame -> event ;
1469+ EvalContextStackPushFrame (ctx , frame );
1470+ if (pushed_event != NULL )
1471+ {
1472+ if (prev_frame == NULL || prev_frame -> event == NULL )
1473+ {
1474+ pushed_event -> stacktrace = SafeStringDuplicate (pushed_event -> id );
1475+ }
1476+ else
1477+ {
1478+ pushed_event -> stacktrace = StringFormat ("%s;%s" , prev_frame -> event -> stacktrace , pushed_event -> id );
1479+ }
1480+ }
14471481
14481482 if (RlistLen (args ) > 0 )
14491483 {
@@ -1523,9 +1557,22 @@ void EvalContextStackPushPromiseFrame(EvalContext *ctx, const Promise *owner)
15231557
15241558 EvalContextVariableClearMatch (ctx );
15251559
1560+ StackFrame * prev_frame = LastStackFrameByEvent (ctx );
15261561 StackFrame * frame = StackFrameNewPromise (owner , ctx -> profiling );
15271562
15281563 EvalContextStackPushFrame (ctx , frame );
1564+ EventFrame * pushed_event = frame -> event ;
1565+ if (pushed_event != NULL )
1566+ {
1567+ if (prev_frame == NULL || prev_frame -> event == NULL )
1568+ {
1569+ pushed_event -> stacktrace = SafeStringDuplicate (pushed_event -> id );
1570+ }
1571+ else
1572+ {
1573+ pushed_event -> stacktrace = StringFormat ("%s;%s" , prev_frame -> event -> stacktrace , pushed_event -> id );
1574+ }
1575+ }
15291576
15301577 // create an empty table
15311578 frame -> data .promise .vars = VariableTableNew ();
@@ -3898,7 +3945,7 @@ void EvalContextSetProfiling(EvalContext *ctx, bool profiling)
38983945 ctx -> profiling = profiling ;
38993946}
39003947
3901- static EventFrame * EventFrameCreate (char * type , const char * name , const char * source , SourceOffset offset )
3948+ static EventFrame * EventFrameCreate (char * type , const char * name , const char * source , SourceOffset offset , char * id )
39023949{
39033950 EventFrame * event = (EventFrame * ) xmalloc (sizeof (EventFrame ));
39043951
@@ -3907,7 +3954,8 @@ static EventFrame *EventFrameCreate(char *type, const char *name, const char *so
39073954 event -> filename = GetAbsolutePath (source );
39083955 event -> elapsed = 0 ;
39093956 event -> offset = offset ;
3910- event -> id = StringFormat ("%s_%s_%s_%ld_%ld" , type , name , source , offset .start , offset .line );
3957+ event -> id = id ;
3958+ event -> stacktrace = "" ;
39113959
39123960 return event ;
39133961}
@@ -3933,6 +3981,7 @@ static JsonElement *EventToJson(EventFrame *event)
39333981 JsonObjectAppendString (json_event , "filename" , event -> filename );
39343982 JsonObjectAppendString (json_event , "id" , event -> id );
39353983 JsonObjectAppendInteger64 (json_event , "elapsed" , event -> elapsed );
3984+ JsonObjectAppendString (json_event , "callstack" , event -> stacktrace );
39363985
39373986 JsonElement * offset = JsonObjectCreate (4 );
39383987 JsonObjectAppendInteger (offset , "start" , event -> offset .start );
@@ -3948,19 +3997,19 @@ static JsonElement *EventToJson(EventFrame *event)
39483997static EventFrame * BundleToEventFrame (const Bundle * bp )
39493998{
39503999 assert (bp != NULL );
3951- return EventFrameCreate ("bundle" , bp -> name , bp -> source_path , bp -> offset );
4000+ return EventFrameCreate ("bundle" , bp -> name , bp -> source_path , bp -> offset , BundleGetCallStackID ( bp ) );
39524001}
39534002
39544003static EventFrame * PromiseToEventFrame (const Promise * pp )
39554004{
39564005 assert (pp != NULL );
3957- return EventFrameCreate ("promise" , PromiseGetPromiseType (pp ), PromiseGetBundle (pp )-> source_path , pp -> offset );
4006+ return EventFrameCreate ("promise" , PromiseGetPromiseType (pp ), PromiseGetBundle (pp )-> source_path , pp -> offset , PromiseGetCallStackID ( pp ) );
39584007}
39594008
39604009static EventFrame * FunctionToEventFrame (const FnCall * fp )
39614010{
39624011 assert (fp != NULL );
3963- return EventFrameCreate ("function" , fp -> name , PromiseGetBundle (fp -> caller )-> source_path , fp -> caller -> offset );
4012+ return EventFrameCreate ("function" , fp -> name , PromiseGetBundle (fp -> caller )-> source_path , fp -> caller -> offset , FunctionGetCallStackID ( fp ) );
39644013}
39654014
39664015void EvalContextAddFunctionEvent (EvalContext * ctx , const FnCall * fp , int64_t start )
@@ -3994,31 +4043,6 @@ void EvalContextProfilingStart(EvalContext *ctx)
39944043 ctx -> profiler .elapsed = EvalContextEventStart ();
39954044}
39964045
3997- static HashMap * SumEventFrames (Seq * events )
3998- {
3999- HashMap * map = HashMapNew ((MapHashFn ) StringHash , (MapKeyEqualFn ) StringEqual , NULL , NULL , 10 );
4000-
4001- size_t length = SeqLength (events );
4002- EventFrame * curr ;
4003- EventFrame * prev ;
4004- MapKeyValue * mkv ;
4005- for (int i = 0 ; i < length ; i ++ )
4006- {
4007- curr = SeqAt (events , i );
4008- mkv = HashMapGet (map , curr -> id );
4009-
4010- if (mkv == NULL )
4011- {
4012- HashMapInsert (map , curr -> id , curr );
4013- continue ;
4014- }
4015- prev = mkv -> value ;
4016- prev -> elapsed += curr -> elapsed ;
4017- }
4018-
4019- return map ;
4020- }
4021-
40224046void EvalContextProfilingEnd (EvalContext * ctx , const Policy * policy )
40234047{
40244048 assert (ctx != NULL );
@@ -4034,19 +4058,16 @@ void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy)
40344058
40354059 ctx -> profiler .elapsed = end - start ;
40364060
4037- HashMap * map = SumEventFrames (ctx -> profiler .events );
40384061 JsonElement * profiling = JsonObjectCreate (2 );
40394062
40404063 JsonElement * json_policy = PolicyToJson (policy );
40414064 JsonObjectAppendObject (profiling , "policy" , json_policy );
40424065
40434066 JsonElement * events = JsonArrayCreate (10 );
40444067 {
4045- HashMapIterator iter = HashMapIteratorInit (map );
4046- MapKeyValue * mkv ;
4047- while ((mkv = HashMapIteratorNext (& iter )) != NULL )
4068+ for (size_t i = 0 ; i < SeqLength (ctx -> profiler .events ); i ++ )
40484069 {
4049- EventFrame * event = mkv -> value ;
4070+ EventFrame * event = SeqAt ( ctx -> profiler . events , i ) ;
40504071 JsonArrayAppendObject (events , EventToJson (event ));
40514072 }
40524073 }
@@ -4060,6 +4081,24 @@ void EvalContextProfilingEnd(EvalContext *ctx, const Policy *policy)
40604081 JsonDestroy (profiling );
40614082}
40624083
4084+ static char * BundleGetCallStackID (const Bundle * bp )
4085+ {
4086+ assert (bp != NULL );
4087+ return StringFormat ("bundle_%s_%s:%s_%s:%ld_%ld-%ld" , bp -> type , bp -> ns , bp -> name , bp -> source_path , bp -> offset .line , bp -> offset .start , bp -> offset .end );
4088+ }
4089+
4090+ static char * PromiseGetCallStackID (const Promise * pp )
4091+ {
4092+ assert (pp != NULL );
4093+ return StringFormat ("promise_%s_%ld_%ld-%ld" , PromiseGetPromiseType (pp ), pp -> offset .line , pp -> offset .start , pp -> offset .end );
4094+ }
4095+
4096+ static char * FunctionGetCallStackID (const FnCall * fp )
4097+ {
4098+ assert (fp != NULL );
4099+ return StringFormat ("function_%s_%ld_%ld-%ld" , fp -> name , fp -> caller -> offset .line , fp -> caller -> offset .start , fp -> caller -> offset .end );
4100+ }
4101+
40634102// ##############################################################
40644103
40654104void EvalContextSetCommonEvalOrder (EvalContext * ctx , EvalContextEvalOrder eval_order )
@@ -4094,4 +4133,4 @@ bool EvalContextIsClassicOrder(EvalContext *ctx)
40944133 // The fallback is to use what is defined in body common control,
40954134 // or if not defined there either, default to true (normal order)
40964135 return (ctx -> common_eval_order != EVAL_ORDER_TOP_DOWN );
4097- }
4136+ }
0 commit comments