Skip to content

Commit 1c42337

Browse files
authored
Merge pull request #13597 from vedantk/master
[Coverage] Refactor SIL generation for profiling
2 parents b5fca0e + aba9d53 commit 1c42337

21 files changed

+333
-233
lines changed

include/swift/SIL/SILCoverageMap.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class SILCoverageMap : public llvm::ilist_node<SILCoverageMap>,
7373
// Tail-allocated expression list.
7474
MutableArrayRef<llvm::coverage::CounterExpression> Expressions;
7575

76+
// Whether the coverage mapping's name data is in the profile symbol table.
77+
bool HasSymtabEntry;
78+
7679
// Disallow copying into temporary objects.
7780
SILCoverageMap(const SILCoverageMap &other) = delete;
7881
SILCoverageMap &operator=(const SILCoverageMap &) = delete;
@@ -108,6 +111,14 @@ class SILCoverageMap : public llvm::ilist_node<SILCoverageMap>,
108111
return Expressions;
109112
}
110113

114+
/// Check whether this coverage mapping can reference its name data within
115+
/// the profile symbol table.
116+
bool hasSymtabEntry() const { return HasSymtabEntry; }
117+
118+
/// Guarantee that this coverage mapping can reference its name data within
119+
/// the profile symbol table.
120+
void setSymtabEntryGuaranteed() { HasSymtabEntry = true; }
121+
111122
void printCounter(llvm::raw_ostream &OS, llvm::coverage::Counter C) const;
112123

113124
/// Print the coverage map.

include/swift/SIL/SILFunction.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/SIL/SILDebugScope.h"
2424
#include "swift/SIL/SILLinkage.h"
2525
#include "swift/SIL/SILPrintContext.h"
26+
#include "swift/SIL/SILProfiler.h"
2627
#include "llvm/ADT/StringMap.h"
2728

2829
/// The symbol name used for the program entry point function.
@@ -132,6 +133,10 @@ class SILFunction
132133
/// The source location and scope of the function.
133134
const SILDebugScope *DebugScope;
134135

136+
/// The profiler for instrumentation based profiling, or null if profiling is
137+
/// disabled.
138+
SILProfiler *Profiler = nullptr;
139+
135140
/// The function's bare attribute. Bare means that the function is SIL-only
136141
/// and does not require debug info.
137142
unsigned Bare : 1;
@@ -251,8 +256,24 @@ class SILFunction
251256
return SILFunctionConventions(LoweredType, getModule());
252257
}
253258

259+
SILProfiler *getProfiler() const { return Profiler; }
260+
261+
void setProfiler(SILProfiler *InheritedProfiler) {
262+
assert(!Profiler && "Function already has a profiler");
263+
Profiler = InheritedProfiler;
264+
}
265+
266+
void createProfiler(Decl *D) {
267+
assert(!Profiler && "Function already has a profiler");
268+
Profiler = SILProfiler::create(Module, D);
269+
}
270+
271+
void discardProfiler() { Profiler = nullptr; }
272+
254273
ProfileCounter getEntryCount() const { return EntryCount; }
255274

275+
void setEntryCount(ProfileCounter Count) { EntryCount = Count; }
276+
256277
bool isNoReturnFunction() const;
257278

258279
/// Unsafely rewrite the lowered type of this function.

include/swift/SIL/SILModule.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "llvm/ADT/PointerIntPair.h"
4343
#include "llvm/ADT/SetVector.h"
4444
#include "llvm/ADT/ilist.h"
45+
#include "llvm/ProfileData/InstrProfReader.h"
4546
#include "llvm/Support/Allocator.h"
4647
#include "llvm/Support/raw_ostream.h"
4748
#include <functional>
@@ -220,7 +221,10 @@ class SILModule {
220221
/// constructed. In certain cases this was before all Modules had been loaded
221222
/// causing us to not
222223
std::unique_ptr<SerializedSILLoader> SILLoader;
223-
224+
225+
/// The indexed profile data to be used for PGO, or nullptr.
226+
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
227+
224228
/// True if this SILModule really contains the whole module, i.e.
225229
/// optimizations can assume that they see the whole module.
226230
bool wholeModule;
@@ -626,6 +630,12 @@ class SILModule {
626630
Stage = s;
627631
}
628632

633+
llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
634+
635+
void setPGOReader(std::unique_ptr<llvm::IndexedInstrProfReader> IPR) {
636+
PGOReader = std::move(IPR);
637+
}
638+
629639
/// \brief Run the SIL verifier to make sure that all Functions follow
630640
/// invariants.
631641
void verify() const;

include/swift/SIL/SILProfiler.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//===--- SILProfiler.h - Instrumentation based profiling ===-----*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines SILProfiler, which contains the profiling state for one
14+
// function. It's used to drive PGO and generate code coverage reports.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_SIL_PROFILER_H
19+
#define SWIFT_SIL_PROFILER_H
20+
21+
#include "swift/AST/ASTNode.h"
22+
#include "swift/AST/Stmt.h"
23+
#include "swift/Basic/ProfileCounter.h"
24+
#include "swift/SIL/FormalLinkage.h"
25+
#include "llvm/ADT/DenseMap.h"
26+
27+
namespace swift {
28+
29+
class AbstractFunctionDecl;
30+
class SILCoverageMap;
31+
class SILModule;
32+
33+
/// SILProfiler - Maps AST nodes to profile counters.
34+
class SILProfiler : public SILAllocated<SILProfiler> {
35+
private:
36+
SILModule &M;
37+
38+
Decl *Root;
39+
40+
bool EmitCoverageMapping;
41+
42+
SILCoverageMap *CovMap = nullptr;
43+
44+
StringRef CurrentFileName;
45+
46+
std::string PGOFuncName;
47+
48+
uint64_t FunctionHash = 0;
49+
50+
unsigned NumRegionCounters = 0;
51+
52+
llvm::DenseMap<ASTNode, unsigned> RegionCounterMap;
53+
54+
llvm::DenseMap<ASTNode, ProfileCounter> PGORegionLoadedCounterMap;
55+
56+
llvm::DenseMap<ASTNode, ASTNode> PGORegionCondToParentMap;
57+
58+
std::vector<std::tuple<std::string, uint64_t, std::string>> CoverageData;
59+
60+
SILProfiler(SILModule &M, Decl *D, bool EmitCoverageMapping)
61+
: M(M), Root(D), EmitCoverageMapping(EmitCoverageMapping) {}
62+
63+
public:
64+
static SILProfiler *create(SILModule &M, Decl *D);
65+
66+
/// Check if the function is set up for profiling.
67+
bool hasRegionCounters() const { return NumRegionCounters != 0; }
68+
69+
/// Get the execution count corresponding to \p Node from a profile, if one
70+
/// is available.
71+
ProfileCounter getExecutionCount(ASTNode Node);
72+
73+
/// Get the node's parent ASTNode (e.g to get the parent IfStmt or IfCond of
74+
/// a condition), if one is available.
75+
Optional<ASTNode> getPGOParent(ASTNode Node);
76+
77+
/// Get the function name mangled for use with PGO.
78+
StringRef getPGOFuncName() const { return PGOFuncName; }
79+
80+
/// Get the function hash.
81+
uint64_t getPGOFuncHash() const { return FunctionHash; }
82+
83+
/// Get the number of region counters.
84+
unsigned getNumRegionCounters() const { return NumRegionCounters; }
85+
86+
/// Get the mapping from \c ASTNode to its corresponding profile counter.
87+
const llvm::DenseMap<ASTNode, unsigned> &getRegionCounterMap() const {
88+
return RegionCounterMap;
89+
}
90+
91+
/// Increment the number of counter updates associated with this profiler.
92+
void recordCounterUpdate();
93+
94+
private:
95+
/// Map counters to ASTNodes and set them up for profiling the function.
96+
void assignRegionCounters();
97+
};
98+
99+
} // end namespace swift
100+
101+
#endif // SWIFT_SIL_PROFILER_H

lib/IRGen/GenCoverage.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ void IRGenModule::emitCoverageMapping() {
4343
if (Mappings.empty())
4444
return;
4545

46+
assert(std::all_of(Mappings.begin(), Mappings.end(),
47+
[](const SILCoverageMap &M) {
48+
// TODO: We should use this check defensively s.t we
49+
// never emit malformed coverage data, instead of just
50+
// using it as a debugging tool.
51+
return M.hasSymtabEntry();
52+
}) &&
53+
"Missing symtab entry for coverage mapping");
54+
4655
std::vector<StringRef> Files;
4756
for (const auto &M : Mappings)
4857
if (std::find(Files.begin(), Files.end(), M.getFile()) == Files.end())

lib/SIL/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_swift_library(swiftSIL STATIC
2727
SILModule.cpp
2828
SILOpenedArchetypesTracker.cpp
2929
SILPrinter.cpp
30+
SILProfiler.cpp
3031
SILSuccessor.cpp
3132
SILType.cpp
3233
SILValue.cpp

lib/SIL/SILCoverageMap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ SILCoverageMap::create(SILModule &M, StringRef Filename, StringRef Name,
4444
}
4545

4646
SILCoverageMap::SILCoverageMap(uint64_t Hash, bool External)
47-
: External(External), Hash(Hash) {}
47+
: External(External), Hash(Hash), HasSymtabEntry(false) {}
4848

4949
SILCoverageMap::~SILCoverageMap() {}
5050

0 commit comments

Comments
 (0)