@@ -67,7 +67,7 @@ void ProfileGenerator::findDisjointRanges(RangeSample &DisjointRanges,
67
67
/*
68
68
Regions may overlap with each other. Using the boundary info, find all
69
69
disjoint ranges and their sample count. BoundaryPoint contains the count
70
- mutiple samples begin/end at this points.
70
+ multiple samples begin/end at this points.
71
71
72
72
|<--100-->| Sample1
73
73
|<------200------>| Sample2
@@ -264,9 +264,12 @@ static FrameLocation getCallerContext(StringRef CalleeContext,
264
264
StringRef CallerContext = CalleeContext.rsplit (" @ " ).first ;
265
265
CallerNameWithContext = CallerContext.rsplit (' :' ).first ;
266
266
auto ContextSplit = CallerContext.rsplit (" @ " );
267
+ StringRef CallerFrameStr = ContextSplit.second .size () == 0
268
+ ? ContextSplit.first
269
+ : ContextSplit.second ;
267
270
FrameLocation LeafFrameLoc = {" " , {0 , 0 }};
268
271
StringRef Funcname;
269
- SampleContext::decodeContextString (ContextSplit. second , Funcname,
272
+ SampleContext::decodeContextString (CallerFrameStr , Funcname,
270
273
LeafFrameLoc.second );
271
274
LeafFrameLoc.first = Funcname.str ();
272
275
return LeafFrameLoc;
@@ -316,5 +319,196 @@ void CSProfileGenerator::populateInferredFunctionSamples() {
316
319
}
317
320
}
318
321
322
+ // Helper function to extract context prefix
323
+ // PrefixContextId is the context id string except for the leaf probe's
324
+ // context, the final ContextId will be:
325
+ // ContextId = PrefixContextId + LeafContextId;
326
+ // Remind that the string in ContextStrStack is in callee-caller order
327
+ // So process the string vector reversely
328
+ static std::string
329
+ extractPrefixContextId (const SmallVector<const PseudoProbe *, 16 > &Probes,
330
+ ProfiledBinary *Binary) {
331
+ SmallVector<std::string, 16 > ContextStrStack;
332
+ for (const auto *P : Probes) {
333
+ Binary->getInlineContextForProbe (P, ContextStrStack, true );
334
+ }
335
+ std::ostringstream OContextStr;
336
+ for (auto &CxtStr : ContextStrStack) {
337
+ if (OContextStr.str ().size ())
338
+ OContextStr << " @ " ;
339
+ OContextStr << CxtStr;
340
+ }
341
+ return OContextStr.str ();
342
+ }
343
+
344
+ void PseudoProbeCSProfileGenerator::generateProfile () {
345
+ // Enable CS and pseudo probe functionalities in SampleProf
346
+ FunctionSamples::ProfileIsCS = true ;
347
+ FunctionSamples::ProfileIsProbeBased = true ;
348
+ for (const auto &BI : BinarySampleCounters) {
349
+ ProfiledBinary *Binary = BI.first ;
350
+ for (const auto &CI : BI.second ) {
351
+ const ProbeBasedCtxKey *CtxKey =
352
+ dyn_cast<ProbeBasedCtxKey>(CI.first .getPtr ());
353
+ std::string PrefixContextId =
354
+ extractPrefixContextId (CtxKey->Probes , Binary);
355
+ // Fill in function body samples from probes, also infer caller's samples
356
+ // from callee's probe
357
+ populateBodySamplesWithProbes (CI.second .RangeCounter , PrefixContextId,
358
+ Binary);
359
+ // Fill in boundary samples for a call probe
360
+ populateBoundarySamplesWithProbes (CI.second .BranchCounter ,
361
+ PrefixContextId, Binary);
362
+ }
363
+ }
364
+ }
365
+
366
+ void PseudoProbeCSProfileGenerator::extractProbesFromRange (
367
+ const RangeSample &RangeCounter, ProbeCounterMap &ProbeCounter,
368
+ ProfiledBinary *Binary) {
369
+ RangeSample Ranges;
370
+ findDisjointRanges (Ranges, RangeCounter);
371
+ for (const auto &Range : Ranges) {
372
+ uint64_t RangeBegin = Binary->offsetToVirtualAddr (Range.first .first );
373
+ uint64_t RangeEnd = Binary->offsetToVirtualAddr (Range.first .second );
374
+ uint64_t Count = Range.second ;
375
+ // Disjoint ranges have introduce zero-filled gap that
376
+ // doesn't belong to current context, filter them out.
377
+ if (Count == 0 )
378
+ continue ;
379
+
380
+ InstructionPointer IP (Binary, RangeBegin, true );
381
+
382
+ // Disjoint ranges may have range in the middle of two instr,
383
+ // e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
384
+ // can be Addr1+1 to Addr2-1. We should ignore such range.
385
+ if (IP.Address > RangeEnd)
386
+ continue ;
387
+
388
+ while (IP.Address <= RangeEnd) {
389
+ const AddressProbesMap &Address2ProbesMap =
390
+ Binary->getAddress2ProbesMap ();
391
+ auto It = Address2ProbesMap.find (IP.Address );
392
+ if (It != Address2ProbesMap.end ()) {
393
+ for (const auto &Probe : It->second ) {
394
+ if (!Probe.isBlock ())
395
+ continue ;
396
+ ProbeCounter[&Probe] += Count;
397
+ }
398
+ }
399
+
400
+ IP.advance ();
401
+ }
402
+ }
403
+ }
404
+
405
+ void PseudoProbeCSProfileGenerator::populateBodySamplesWithProbes (
406
+ const RangeSample &RangeCounter, StringRef PrefixContextId,
407
+ ProfiledBinary *Binary) {
408
+ ProbeCounterMap ProbeCounter;
409
+ // Extract the top frame probes by looking up each address among the range in
410
+ // the Address2ProbeMap
411
+ extractProbesFromRange (RangeCounter, ProbeCounter, Binary);
412
+ for (auto PI : ProbeCounter) {
413
+ const PseudoProbe *Probe = PI.first ;
414
+ uint64_t Count = PI.second ;
415
+ FunctionSamples &FunctionProfile =
416
+ getFunctionProfileForLeafProbe (PrefixContextId, Probe, Binary);
417
+
418
+ FunctionProfile.addBodySamples (Probe->Index , 0 , Count);
419
+ FunctionProfile.addTotalSamples (Count);
420
+ if (Probe->isEntry ()) {
421
+ FunctionProfile.addHeadSamples (Count);
422
+ // Look up for the caller's function profile
423
+ const auto *InlinerDesc = Binary->getInlinerDescForProbe (Probe);
424
+ if (InlinerDesc != nullptr ) {
425
+ // Since the context id will be compressed, we have to use callee's
426
+ // context id to infer caller's context id to ensure they share the
427
+ // same context prefix.
428
+ StringRef CalleeContextId =
429
+ FunctionProfile.getContext ().getNameWithContext (true );
430
+ StringRef CallerContextId;
431
+ FrameLocation &&CallerLeafFrameLoc =
432
+ getCallerContext (CalleeContextId, CallerContextId);
433
+ uint64_t CallerIndex = CallerLeafFrameLoc.second .LineOffset ;
434
+ assert (CallerIndex &&
435
+ " Inferred caller's location index shouldn't be zero!" );
436
+ FunctionSamples &CallerProfile =
437
+ getFunctionProfileForContext (CallerContextId);
438
+ CallerProfile.setFunctionHash (InlinerDesc->FuncHash );
439
+ CallerProfile.addBodySamples (CallerIndex, 0 , Count);
440
+ CallerProfile.addTotalSamples (Count);
441
+ CallerProfile.addCalledTargetSamples (CallerIndex, 0 ,
442
+ FunctionProfile.getName (), Count);
443
+ }
444
+ }
445
+ }
446
+ }
447
+
448
+ void PseudoProbeCSProfileGenerator::populateBoundarySamplesWithProbes (
449
+ const BranchSample &BranchCounter, StringRef PrefixContextId,
450
+ ProfiledBinary *Binary) {
451
+ for (auto BI : BranchCounter) {
452
+ uint64_t SourceOffset = BI.first .first ;
453
+ uint64_t TargetOffset = BI.first .second ;
454
+ uint64_t Count = BI.second ;
455
+ uint64_t SourceAddress = Binary->offsetToVirtualAddr (SourceOffset);
456
+ const PseudoProbe *CallProbe = Binary->getCallProbeForAddr (SourceAddress);
457
+ if (CallProbe == nullptr )
458
+ continue ;
459
+ FunctionSamples &FunctionProfile =
460
+ getFunctionProfileForLeafProbe (PrefixContextId, CallProbe, Binary);
461
+ FunctionProfile.addBodySamples (CallProbe->Index , 0 , Count);
462
+ FunctionProfile.addTotalSamples (Count);
463
+ StringRef CalleeName = FunctionSamples::getCanonicalFnName (
464
+ Binary->getFuncFromStartOffset (TargetOffset));
465
+ if (CalleeName.size () == 0 )
466
+ continue ;
467
+ FunctionProfile.addCalledTargetSamples (CallProbe->Index , 0 , CalleeName,
468
+ Count);
469
+ }
470
+ }
471
+
472
+ FunctionSamples &PseudoProbeCSProfileGenerator::getFunctionProfileForLeafProbe (
473
+ StringRef PrefixContextId, SmallVector<std::string, 16 > &LeafInlinedContext,
474
+ const PseudoProbeFuncDesc *LeafFuncDesc) {
475
+ assert (LeafInlinedContext.size () &&
476
+ " Profile context must have the leaf frame" );
477
+ std::ostringstream OContextStr;
478
+ OContextStr << PrefixContextId.str ();
479
+
480
+ for (uint32_t I = 0 ; I < LeafInlinedContext.size () - 1 ; I++) {
481
+ if (OContextStr.str ().size ())
482
+ OContextStr << " @ " ;
483
+ OContextStr << LeafInlinedContext[I];
484
+ }
485
+ // For leaf inlined context with the top frame, we should strip off the top
486
+ // frame's probe id, like:
487
+ // Inlined stack: [foo:1, bar:2], the ContextId will be "foo:1 @ bar"
488
+ if (OContextStr.str ().size ())
489
+ OContextStr << " @ " ;
490
+ StringRef LeafLoc = LeafInlinedContext.back ();
491
+ OContextStr << LeafLoc.split (" :" ).first .str ();
492
+
493
+ FunctionSamples &FunctionProile =
494
+ getFunctionProfileForContext (OContextStr.str ());
495
+ FunctionProile.setFunctionHash (LeafFuncDesc->FuncHash );
496
+ return FunctionProile;
497
+ }
498
+
499
+ FunctionSamples &PseudoProbeCSProfileGenerator::getFunctionProfileForLeafProbe (
500
+ StringRef PrefixContextId, const PseudoProbe *LeafProbe,
501
+ ProfiledBinary *Binary) {
502
+ SmallVector<std::string, 16 > LeafInlinedContext;
503
+ Binary->getInlineContextForProbe (LeafProbe, LeafInlinedContext);
504
+ // Note that the context from probe doesn't include leaf frame,
505
+ // hence we need to retrieve and append the leaf frame.
506
+ const auto *FuncDesc = Binary->getFuncDescForGUID (LeafProbe->GUID );
507
+ LeafInlinedContext.emplace_back (FuncDesc->FuncName + " :" +
508
+ Twine (LeafProbe->Index ).str ());
509
+ return getFunctionProfileForLeafProbe (PrefixContextId, LeafInlinedContext,
510
+ FuncDesc);
511
+ }
512
+
319
513
} // end namespace sampleprof
320
514
} // end namespace llvm
0 commit comments