Skip to content

Add support for SamplePGO #76532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,13 @@ class IRGenOptions {
/// Path to the profdata file to be used for PGO, or the empty string.
std::string UseProfile = "";

/// Path to the data file to be used for sampling-based PGO,
/// or the empty string.
std::string UseSampleProfile = "";

/// Controls whether DWARF discriminators are added to the IR.
unsigned DebugInfoForProfiling : 1;

/// List of backend command-line options for -embed-bitcode.
std::vector<uint8_t> CmdArgs;

Expand Down Expand Up @@ -584,7 +591,8 @@ class IRGenOptions {
ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false),
UseFragileResilientProtocolWitnesses(false), EnableHotColdSplit(false),
EmitAsyncFramePushPopMetadata(false), EmitYieldOnce2AsYieldOnce(true),
AsyncFramePointerAll(false), UseProfilingMarkerThunks(false), CmdArgs(),
AsyncFramePointerAll(false), UseProfilingMarkerThunks(false),
DebugInfoForProfiling(false), CmdArgs(),
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
TypeInfoFilter(TypeInfoDumpFilter::All),
PlatformCCallingConvention(llvm::CallingConv::C), UseCASBackend(false),
Expand Down
9 changes: 9 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,10 @@ def profile_generate : Flag<["-"], "profile-generate">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Generate instrumented code to collect execution counts">;

def debug_info_for_profiling : Flag<["-"], "debug-info-for-profiling">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Emit extra debug info (DWARF discriminators) to make sampling-based profiling more accurate">;

def profile_use : CommaJoined<["-"], "profile-use=">,
Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
MetaVarName<"<profdata>">,
Expand All @@ -1486,6 +1490,11 @@ def profile_coverage_mapping : Flag<["-"], "profile-coverage-mapping">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Generate coverage data for use with profiled execution counts">;

def profile_sample_use : CommaJoined<["-"], "profile-sample-use=">,
Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
MetaVarName<"<profile data>">,
HelpText<"Supply sampling-based profiling data from llvm-profdata to enable profile-guided optimization">;

def embed_bitcode : Flag<["-"], "embed-bitcode">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Embed LLVM IR bitcode as data">;
Expand Down
5 changes: 5 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3177,6 +3177,11 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
const Arg *ProfileUse = Args.getLastArg(OPT_profile_use);
Opts.UseProfile = ProfileUse ? ProfileUse->getValue() : "";

const Arg *ProfileSampleUse = Args.getLastArg(OPT_profile_sample_use);
Opts.UseSampleProfile = ProfileSampleUse ? ProfileSampleUse->getValue() : "";

Opts.DebugInfoForProfiling |= Args.hasArg(OPT_debug_info_for_profiling);

Opts.PrintInlineTree |= Args.hasArg(OPT_print_llvm_inline_tree);
// Always producing all outputs when caching is enabled.
Opts.AlwaysCompile |= Args.hasArg(OPT_always_compile_output_files) ||
Expand Down
34 changes: 34 additions & 0 deletions lib/IRGen/IRGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,45 @@ static void align(llvm::Module *Module) {
}
}

static void populatePGOOptions(std::optional<PGOOptions> &Out,
const IRGenOptions &Opts) {
if (!Opts.UseSampleProfile.empty()) {
Out = PGOOptions(
/*ProfileFile=*/ Opts.UseSampleProfile,
/*CSProfileGenFile=*/ "",
/*ProfileRemappingFile=*/ "",
/*MemoryProfile=*/ "",
/*FS=*/ llvm::vfs::getRealFileSystem(), // TODO: is this fine?
/*Action=*/ PGOOptions::SampleUse,
/*CSPGOAction=*/ PGOOptions::NoCSAction,
/*ColdType=*/ PGOOptions::ColdFuncOpt::Default,
/*DebugInfoForProfiling=*/ Opts.DebugInfoForProfiling
);
return;
}

if (Opts.DebugInfoForProfiling) {
Out = PGOOptions(
/*ProfileFile=*/ "",
/*CSProfileGenFile=*/ "",
/*ProfileRemappingFile=*/ "",
/*MemoryProfile=*/ "",
/*FS=*/ nullptr,
/*Action=*/ PGOOptions::NoAction,
/*CSPGOAction=*/ PGOOptions::NoCSAction,
/*ColdType=*/ PGOOptions::ColdFuncOpt::Default,
/*DebugInfoForProfiling=*/ true
);
return;
}
}

void swift::performLLVMOptimizations(const IRGenOptions &Opts,
llvm::Module *Module,
llvm::TargetMachine *TargetMachine,
llvm::raw_pwrite_stream *out) {
std::optional<PGOOptions> PGOOpt;
populatePGOOptions(PGOOpt, Opts);

PipelineTuningOptions PTO;

Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
TheCU->getProducer(), true, StringRef(), 0,
RemappedASTFile, llvm::DICompileUnit::FullDebug,
Signature);
// NOTE: not setting DebugInfoForProfiling here
DIB.finalize();
}
}
Expand Down Expand Up @@ -2504,7 +2505,7 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,
? llvm::DICompileUnit::FullDebug
: llvm::DICompileUnit::LineTablesOnly,
/* DWOId */ 0, /* SplitDebugInlining */ true,
/* DebugInfoForProfiling */ false,
/* DebugInfoForProfiling */ Opts.DebugInfoForProfiling,
llvm::DICompileUnit::DebugNameTableKind::Default,
/* RangesBaseAddress */ false, DebugPrefixMap.remapPath(Sysroot), SDK);

Expand Down
5 changes: 5 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,11 @@ IRGenSILFunction::IRGenSILFunction(IRGenModule &IGM, SILFunction *f)
// LLVM doesn't have an attribute for -O
}

if (!IGM.IRGen.Opts.UseSampleProfile.empty()) {
// This attribute helps in LTO situations: https://reviews.llvm.org/D79959
CurFn->addFnAttr("use-sample-profile");
}

// Emit the thunk that calls the previous implementation if this is a dynamic
// replacement.
if (f->getDynamicallyReplacedFunction()) {
Expand Down
16 changes: 16 additions & 0 deletions test/DebugInfo/discriminators_for_profiling.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %target-swift-frontend %s -emit-ir -g -debug-info-for-profiling -o - | %FileCheck %s

// CHECK: distinct !DICompileUnit(language: DW_LANG_Swift
// CHECK-SAME: debugInfoForProfiling: true

// CHECK: !DILexicalBlockFile({{.*}} discriminator: 2)

public func lobster(_ n: Int) -> Bool {
guard n > 0 else { fatalError("too cold!") }

if n > 100 {
print("warm but ok")
}

return n < 120
}
43 changes: 43 additions & 0 deletions test/Profiler/samplepgo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t

// ----------------------------------------
// Test the -profile-sample-use= flag using bogus data, to ensure it's actually
// reaching LLVM in the expected way.

// RUN: %target-swift-frontend %t/program.swift -module-name test -emit-ir \
// RUN: -O -profile-sample-use=%t/profile.txt -o %t/has-data.ll

// RUN: %FileCheck %s < %t/has-data.ll

// CHECK: define{{.*}} @"$s4test8anythingyyF"() #[[ATTRID:[0-9]+]]
// CHECK: attributes #[[ATTRID]] = {{.*}} "use-sample-profile"

// CHECK-LABEL: !llvm.module.flags
// CHECK: !{!"ProfileFormat", !"SampleProfile"}
// CHECK: !{!"TotalCount", i64 2001}

// ----------------------------------------
// Now, test cases where there there should not be any profile metadata,
// such as when no data is provided

// RUN: %target-swift-frontend %t/program.swift -module-name test -emit-ir \
// RUN: -O -o %t/no-data.ll

// RUN: %FileCheck --check-prefix CHECK-NODATA %s < %t/no-data.ll


// CHECK-NODATA: define{{.*}} @"$s4test8anythingyyF"() #[[ATTRID:[0-9]+]]
// CHECK-NODATA-NOT: attributes #[[ATTRID]] = {{.*}} "use-sample-profile"

// CHECK-NODATA-LABEL: !llvm.module.flags
// CHECK-NODATA-NOT: Profile


//--- program.swift
public func anything() {}


//--- profile.txt
bar:100:100
1: 2001