@@ -246,22 +246,37 @@ ContextNode *getFlatProfile(FunctionData &Data, GUID Guid,
246246
247247ContextNode *getUnhandledContext (FunctionData &Data, GUID Guid,
248248 uint32_t NumCounters) {
249- // 1) if we are under a root (regardless if this thread is collecting or not a
249+
250+ // 1) if we are currently collecting a contextual profile, fetch a ContextNode
251+ // in the `Unhandled` set. We want to do this regardless of `ProfilingStarted`
252+ // to (hopefully) offset the penalty of creating these contexts to before
253+ // profiling.
254+ //
255+ // 2) if we are under a root (regardless if this thread is collecting or not a
250256 // contextual profile for that root), do not collect a flat profile. We want
251257 // to keep flat profiles only for activations that can't happen under a root,
252258 // to avoid confusing profiles. We can, for example, combine flattened and
253259 // flat profiles meaningfully, as we wouldn't double-count anything.
254260 //
255- // 2 ) to avoid lengthy startup, don't bother with flat profiles until the
256- // profiling started. We would reset them anyway when profiling starts.
261+ // 3 ) to avoid lengthy startup, don't bother with flat profiles until the
262+ // profiling has started. We would reset them anyway when profiling starts.
257263 // HOWEVER. This does lose profiling for message pumps: those functions are
258264 // entered once and never exit. They should be assumed to be entered before
259265 // profiling starts - because profiling should start after the server is up
260266 // and running (which is equivalent to "message pumps are set up").
261- if (IsUnderContext || !__sanitizer::atomic_load_relaxed (&ProfilingStarted))
262- return TheScratchContext;
263- return markAsScratch (
264- onContextEnter (*getFlatProfile (Data, Guid, NumCounters)));
267+ ContextRoot *R = __llvm_ctx_profile_current_context_root;
268+ if (!R) {
269+ if (IsUnderContext || !__sanitizer::atomic_load_relaxed (&ProfilingStarted))
270+ return TheScratchContext;
271+ else
272+ return markAsScratch (
273+ onContextEnter (*getFlatProfile (Data, Guid, NumCounters)));
274+ }
275+ auto [Iter, Ins] = R->Unhandled .insert ({Guid, nullptr });
276+ if (Ins)
277+ Iter->second =
278+ getCallsiteSlow (Guid, &R->FirstUnhandledCalleeNode , NumCounters, 0 );
279+ return markAsScratch (onContextEnter (*Iter->second ));
265280}
266281
267282ContextNode *__llvm_ctx_profile_get_context (FunctionData *Data, void *Callee,
@@ -396,6 +411,8 @@ void __llvm_ctx_profile_start_collection() {
396411 ++NumMemUnits;
397412
398413 resetContextNode (*Root->FirstNode );
414+ if (Root->FirstUnhandledCalleeNode )
415+ resetContextNode (*Root->FirstUnhandledCalleeNode );
399416 __sanitizer::atomic_store_relaxed (&Root->TotalEntries , 0 );
400417 }
401418 __sanitizer::atomic_store_relaxed (&ProfilingStarted, true );
@@ -416,8 +433,9 @@ bool __llvm_ctx_profile_fetch(ProfileWriter &Writer) {
416433 __sanitizer::Printf (" [ctxprof] Contextual Profile is %s\n " , " invalid" );
417434 return false ;
418435 }
419- Writer.writeContextual (*Root->FirstNode , __sanitizer::atomic_load_relaxed (
420- &Root->TotalEntries ));
436+ Writer.writeContextual (
437+ *Root->FirstNode , Root->FirstUnhandledCalleeNode ,
438+ __sanitizer::atomic_load_relaxed (&Root->TotalEntries ));
421439 }
422440 Writer.endContextSection ();
423441 Writer.startFlatSection ();
0 commit comments