Skip to content

Commit 0c2e2d8

Browse files
authored
Merge pull request #67341 from zoecarver/perf-annotations-pretty-stack-traces
[nfc][opts] Add a few pretty-stack traces to performance diagnostics.
2 parents d6e0ca3 + f6b1775 commit 0c2e2d8

File tree

1 file changed

+78
-3
lines changed

1 file changed

+78
-3
lines changed

lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,41 @@ using namespace swift;
2626

2727
namespace {
2828

29+
class PrettyStackTracePerformanceDiagnostics
30+
: public llvm::PrettyStackTraceEntry {
31+
const SILNode *node;
32+
const char *action;
33+
34+
public:
35+
PrettyStackTracePerformanceDiagnostics(const char *action, SILNodePointer node)
36+
: node(node), action(action) {}
37+
38+
virtual void print(llvm::raw_ostream &OS) const override {
39+
OS << "While " << action << " -- visiting node ";
40+
node->print(OS);
41+
42+
if (auto inst = dyn_cast<SILInstruction>(node)) {
43+
OS << "While visiting instruction in function ";
44+
inst->getFunction()->print(OS);
45+
}
46+
}
47+
};
48+
49+
class PrettyStackTraceSILGlobal
50+
: public llvm::PrettyStackTraceEntry {
51+
const SILGlobalVariable *node;
52+
const char *action;
53+
54+
public:
55+
PrettyStackTraceSILGlobal(const char *action, SILGlobalVariable *node)
56+
: node(node), action(action) {}
57+
58+
virtual void print(llvm::raw_ostream &OS) const override {
59+
OS << "While " << action << " -- visiting node ";
60+
node->print(OS);
61+
}
62+
};
63+
2964
/// Issues performance diagnostics for functions which are annotated with
3065
/// performance annotations, like @_noLocks, @_noAllocation.
3166
///
@@ -156,6 +191,9 @@ bool PerformanceDiagnostics::visitFunction(SILFunction *function,
156191
if (visitCallee(&inst, bca->getCalleeList(as), perfConstr, parentLoc))
157192
return true;
158193
} else if (auto *bi = dyn_cast<BuiltinInst>(&inst)) {
194+
PrettyStackTracePerformanceDiagnostics stackTrace(
195+
"visitFunction::BuiltinInst (once, once with context)", &inst);
196+
159197
switch (bi->getBuiltinInfo().ID) {
160198
case BuiltinValueKind::Once:
161199
case BuiltinValueKind::OnceWithContext:
@@ -226,6 +264,9 @@ bool PerformanceDiagnostics::checkClosureValue(SILValue closure,
226264
// the call site.
227265
return false;
228266
} else {
267+
PrettyStackTracePerformanceDiagnostics stackTrace(
268+
"validating closure (function ref, callee) - unkown callee", callInst);
269+
229270
diagnose(LocWithParent(callInst->getLoc().getSourceLoc(), parentLoc), diag::performance_unknown_callees);
230271
return true;
231272
}
@@ -249,6 +290,8 @@ bool PerformanceDiagnostics::visitCallee(SILInstruction *callInst,
249290
loc = parentLoc;
250291

251292
if (callees.isIncomplete()) {
293+
PrettyStackTracePerformanceDiagnostics stackTrace("incomplete", callInst);
294+
252295
diagnose(*loc, diag::performance_unknown_callees);
253296
return true;
254297
}
@@ -263,6 +306,8 @@ bool PerformanceDiagnostics::visitCallee(SILInstruction *callInst,
263306
return false;
264307

265308
if (!callee->isDefinition()) {
309+
PrettyStackTracePerformanceDiagnostics stackTrace("incomplete", callInst);
310+
266311
diagnose(*loc, diag::performance_callee_unavailable);
267312
return true;
268313
}
@@ -310,6 +355,8 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
310355
if (impact & RuntimeEffect::Casting) {
311356
// TODO: be more specific on casting.
312357
// E.g. distinguish locking and allocating dynamic casts, etc.
358+
PrettyStackTracePerformanceDiagnostics stackTrace("bad cast", inst);
359+
313360
diagnose(loc, diag::performance_dynamic_casting);
314361
return true;
315362
}
@@ -319,21 +366,30 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
319366

320367
// Try to give a good error message by looking which type of code it is.
321368
switch (inst->getKind()) {
322-
case SILInstructionKind::KeyPathInst:
369+
case SILInstructionKind::KeyPathInst: {
370+
PrettyStackTracePerformanceDiagnostics stackTrace("key path", inst);
323371
diagnose(loc, diag::performance_metadata, "using KeyPath");
324372
break;
373+
}
325374
case SILInstructionKind::AllocGlobalInst:
326-
case SILInstructionKind::GlobalValueInst:
375+
case SILInstructionKind::GlobalValueInst: {
376+
PrettyStackTracePerformanceDiagnostics stackTrace(
377+
"AllocGlobalInst | GlobalValueInst", inst);
327378
diagnose(loc, diag::performance_metadata, "global or static variables");
328379
break;
380+
}
329381
case SILInstructionKind::PartialApplyInst: {
382+
PrettyStackTracePerformanceDiagnostics stackTrace(
383+
"PartialApplyInst", inst);
330384
diagnose(loc, diag::performance_metadata,
331385
"generic closures or local functions");
332386
break;
333387
}
334388
case SILInstructionKind::ApplyInst:
335389
case SILInstructionKind::TryApplyInst:
336390
case SILInstructionKind::BeginApplyInst: {
391+
PrettyStackTracePerformanceDiagnostics stackTrace(
392+
"ApplyInst | TryApplyInst | BeginApplyInst", inst);
337393
diagnose(loc, diag::performance_metadata, "generic function calls");
338394
break;
339395
}
@@ -345,16 +401,23 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
345401
// We didn't recognize the instruction, so try to give an error message
346402
// based on the involved type.
347403
if (impactType) {
404+
PrettyStackTracePerformanceDiagnostics stackTrace(
405+
"impactType (unrecognized instruction)", inst);
348406
diagnose(loc, diag::performance_metadata_type, impactType.getASTType());
349407
break;
350408
}
351409
// The default error message.
410+
PrettyStackTracePerformanceDiagnostics stackTrace(
411+
"default error (fallthrough, unkown inst)", inst);
352412
diagnose(loc, diag::performance_metadata, "this code pattern");
353413
break;
354414
}
355415
return true;
356416
}
357417
if (impact & RuntimeEffect::Allocating) {
418+
PrettyStackTracePerformanceDiagnostics stackTrace(
419+
"found allocation effect", inst);
420+
358421
switch (inst->getKind()) {
359422
case SILInstructionKind::BeginApplyInst:
360423
// Not all begin_applys necessarily allocate. But it's difficult to
@@ -375,6 +438,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
375438
return true;
376439
}
377440
if (impact & RuntimeEffect::Deallocating) {
441+
PrettyStackTracePerformanceDiagnostics stackTrace(
442+
"found deallocation effect", inst);
443+
378444
if (impactType) {
379445
switch (inst->getKind()) {
380446
case SILInstructionKind::StoreInst:
@@ -395,6 +461,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
395461
return true;
396462
}
397463
if (impact & RuntimeEffect::ObjectiveC) {
464+
PrettyStackTracePerformanceDiagnostics stackTrace(
465+
"found objc effect", inst);
466+
398467
diagnose(loc, diag::performance_objectivec);
399468
return true;
400469
}
@@ -403,6 +472,9 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
403472
return false;
404473

405474
// Handle locking-only effects.
475+
476+
PrettyStackTracePerformanceDiagnostics stackTrace(
477+
"found locking or ref counting effect", inst);
406478

407479
if (impact & RuntimeEffect::Locking) {
408480
if (inst->getFunction()->isGlobalInit()) {
@@ -447,7 +519,7 @@ void PerformanceDiagnostics::checkNonAnnotatedFunction(SILFunction *function) {
447519
}
448520
}
449521

450-
void PerformanceDiagnostics::diagnose(LocWithParent loc, Diagnostic &&D) {
522+
void PerformanceDiagnostics::diagnose(LocWithParent loc, Diagnostic &&D) {
451523
// Start with a valid location in the call tree.
452524
LocWithParent *validLoc = &loc;
453525
while (!validLoc->loc.isValid() && validLoc->parent) {
@@ -484,6 +556,9 @@ class PerformanceDiagnosticsPass : public SILModuleTransform {
484556
// Check that @_section, @_silgen_name is only on constant globals
485557
for (SILGlobalVariable &g : module->getSILGlobals()) {
486558
if (!g.getStaticInitializerValue() && g.mustBeInitializedStatically()) {
559+
PrettyStackTraceSILGlobal stackTrace(
560+
"global inst", &g);
561+
487562
auto *decl = g.getDecl();
488563
if (g.getSectionAttr()) {
489564
module->getASTContext().Diags.diagnose(

0 commit comments

Comments
 (0)