Skip to content

Commit 52cf071

Browse files
authored
[BOLT][NFC] Log through JournalingStreams (llvm#81524)
Make core BOLT functionality more friendly to being used as a library instead of in our standalone driver llvm-bolt. To accomplish this, we augment BinaryContext with journaling streams that are to be used by most BOLT code whenever something needs to be logged to the screen. Users of the library can decide if logs should be printed to a file, no file or to the screen, as before. To illustrate this, this patch adds a new option `--log-file` that allows the user to redirect BOLT logging to a file on disk or completely hide it by using `--log-file=/dev/null`. Future BOLT code should now use `BinaryContext::outs()` for printing important messages instead of `llvm::outs()`. A new test log.test enforces this by verifying that no strings are print to screen once the `--log-file` option is used. In previous patches we also added a new BOLTError class to report common and fatal errors, so code shouldn't call exit(1) now. To easily handle problems as before (by quitting with exit(1)), callers can now use `BinaryContext::logBOLTErrorsAndQuitOnFatal(Error)` whenever code needs to deal with BOLT errors. To test this, we have fatal.s that checks we are correctly quitting and printing a fatal error to the screen. Because this is a significant change by itself, not all code was yet ported. Code from Profiler libs (DataAggregator and friends) still print errors directly to screen. Co-authored-by: Rafael Auler <rafaelauler@fb.com> Test Plan: NFC
1 parent 93cdd1b commit 52cf071

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1344
-1121
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ class BOLTError : public ErrorInfo<BOLTError> {
165165
std::string Msg;
166166
};
167167

168+
/// Streams used by BOLT to log regular or error events
169+
struct JournalingStreams {
170+
raw_ostream &Out;
171+
raw_ostream &Err;
172+
};
173+
168174
Error createNonFatalBOLTError(const Twine &S);
169175
Error createFatalBOLTError(const Twine &S);
170176

@@ -260,7 +266,8 @@ class BinaryContext {
260266
public:
261267
static Expected<std::unique_ptr<BinaryContext>>
262268
createBinaryContext(const ObjectFile *File, bool IsPIC,
263-
std::unique_ptr<DWARFContext> DwCtx);
269+
std::unique_ptr<DWARFContext> DwCtx,
270+
JournalingStreams Logger);
264271

265272
/// Superset of compiler units that will contain overwritten code that needs
266273
/// new debug info. In a few cases, functions may end up not being
@@ -628,6 +635,10 @@ class BinaryContext {
628635

629636
std::unique_ptr<MCAsmBackend> MAB;
630637

638+
/// Allows BOLT to print to log whenever it is necessary (with or without
639+
/// const references)
640+
mutable JournalingStreams Logger;
641+
631642
/// Indicates if the binary is Linux kernel.
632643
bool IsLinuxKernel{false};
633644

@@ -760,7 +771,8 @@ class BinaryContext {
760771
std::unique_ptr<const MCInstrAnalysis> MIA,
761772
std::unique_ptr<MCPlusBuilder> MIB,
762773
std::unique_ptr<const MCRegisterInfo> MRI,
763-
std::unique_ptr<MCDisassembler> DisAsm);
774+
std::unique_ptr<MCDisassembler> DisAsm,
775+
JournalingStreams Logger);
764776

765777
~BinaryContext();
766778

@@ -1372,8 +1384,12 @@ class BinaryContext {
13721384
return Offset;
13731385
}
13741386

1375-
void exitWithBugReport(StringRef Message,
1376-
const BinaryFunction &Function) const;
1387+
/// Log BOLT errors to journaling streams and quit process with non-zero error
1388+
/// code 1 if error is fatal.
1389+
void logBOLTErrorsAndQuitOnFatal(Error E);
1390+
1391+
std::string generateBugReportMessage(StringRef Message,
1392+
const BinaryFunction &Function) const;
13771393

13781394
struct IndependentCodeEmitter {
13791395
std::unique_ptr<MCObjectFileInfo> LocalMOFI;
@@ -1421,6 +1437,10 @@ class BinaryContext {
14211437
assert(IOAddressMap && "Address map not set yet");
14221438
return *IOAddressMap;
14231439
}
1440+
1441+
raw_ostream &outs() const { return Logger.Out; }
1442+
1443+
raw_ostream &errs() const { return Logger.Err; }
14241444
};
14251445

14261446
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>

bolt/include/bolt/Core/DIEBuilder.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef BOLT_CORE_DIE_BUILDER_H
1616
#define BOLT_CORE_DIE_BUILDER_H
1717

18+
#include "bolt/Core/BinaryContext.h"
1819
#include "llvm/CodeGen/DIE.h"
1920
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
2021
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
@@ -32,6 +33,7 @@
3233
namespace llvm {
3334

3435
namespace bolt {
36+
3537
class DIEStreamer;
3638
class DebugStrOffsetsWriter;
3739

@@ -120,6 +122,7 @@ class DIEBuilder {
120122
std::unique_ptr<State> BuilderState;
121123
FoldingSet<DIEAbbrev> AbbreviationsSet;
122124
std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
125+
BinaryContext &BC;
123126
DWARFContext *DwarfContext{nullptr};
124127
bool IsDWO{false};
125128
uint64_t UnitSize{0};
@@ -219,9 +222,10 @@ class DIEBuilder {
219222
if (getState().CloneUnitCtxMap[UnitId].DieInfoVector.size() > DIEId)
220223
return *getState().CloneUnitCtxMap[UnitId].DieInfoVector[DIEId].get();
221224

222-
errs() << "BOLT-WARNING: [internal-dwarf-error]: The DIE is not allocated "
223-
"before looking up, some"
224-
<< "unexpected corner cases happened.\n";
225+
BC.errs()
226+
<< "BOLT-WARNING: [internal-dwarf-error]: The DIE is not allocated "
227+
"before looking up, some"
228+
<< "unexpected corner cases happened.\n";
225229
return *getState().CloneUnitCtxMap[UnitId].DieInfoVector.front().get();
226230
}
227231

@@ -261,7 +265,7 @@ class DIEBuilder {
261265
DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId);
262266

263267
public:
264-
DIEBuilder(DWARFContext *DwarfContext, bool IsDWO = false);
268+
DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext, bool IsDWO = false);
265269

266270
/// Returns enum to what we are currently processing.
267271
ProcessingType getCurrentProcessingState() { return getState().Type; }
@@ -295,8 +299,9 @@ class DIEBuilder {
295299
if (getState().TypeDIEMap.count(&DU))
296300
return getState().TypeDIEMap[&DU];
297301

298-
errs() << "BOLT-ERROR: unable to find TypeUnit for Type Unit at offset 0x"
299-
<< DU.getOffset() << "\n";
302+
BC.errs()
303+
<< "BOLT-ERROR: unable to find TypeUnit for Type Unit at offset 0x"
304+
<< DU.getOffset() << "\n";
300305
return nullptr;
301306
}
302307

bolt/include/bolt/Core/DynoStats.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,9 @@ inline DynoStats getDynoStats(FuncsType &Funcs, bool IsAArch64) {
159159

160160
/// Call a function with optional before and after dynostats printing.
161161
template <typename FnType, typename FuncsType>
162-
inline void callWithDynoStats(FnType &&Func, FuncsType &Funcs, StringRef Phase,
163-
const bool Flag, bool IsAArch64) {
162+
inline void callWithDynoStats(raw_ostream &OS, FnType &&Func, FuncsType &Funcs,
163+
StringRef Phase, const bool Flag,
164+
bool IsAArch64) {
164165
DynoStats DynoStatsBefore(IsAArch64);
165166
if (Flag)
166167
DynoStatsBefore = getDynoStats(Funcs, IsAArch64);
@@ -170,12 +171,12 @@ inline void callWithDynoStats(FnType &&Func, FuncsType &Funcs, StringRef Phase,
170171
if (Flag) {
171172
const DynoStats DynoStatsAfter = getDynoStats(Funcs, IsAArch64);
172173
const bool Changed = (DynoStatsAfter != DynoStatsBefore);
173-
outs() << "BOLT-INFO: program-wide dynostats after running " << Phase
174-
<< (Changed ? "" : " (no change)") << ":\n\n"
175-
<< DynoStatsBefore << '\n';
174+
OS << "BOLT-INFO: program-wide dynostats after running " << Phase
175+
<< (Changed ? "" : " (no change)") << ":\n\n"
176+
<< DynoStatsBefore << '\n';
176177
if (Changed)
177-
DynoStatsAfter.print(outs(), &DynoStatsBefore);
178-
outs() << '\n';
178+
DynoStatsAfter.print(OS, &DynoStatsBefore);
179+
OS << '\n';
179180
}
180181
}
181182

bolt/include/bolt/Core/Exceptions.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ class FDE;
3030

3131
namespace bolt {
3232

33+
class BinaryContext;
3334
class BinaryFunction;
3435

3536
/// \brief Wraps up information to read all CFI instructions and feed them to a
3637
/// BinaryFunction, as well as rewriting CFI sections.
3738
class CFIReaderWriter {
3839
public:
39-
explicit CFIReaderWriter(const DWARFDebugFrame &EHFrame);
40+
explicit CFIReaderWriter(BinaryContext &BC, const DWARFDebugFrame &EHFrame);
4041

4142
bool fillCFIInfoFor(BinaryFunction &Function) const;
4243

@@ -59,6 +60,7 @@ class CFIReaderWriter {
5960
const FDEsMap &getFDEs() const { return FDEs; }
6061

6162
private:
63+
BinaryContext &BC;
6264
FDEsMap FDEs;
6365
};
6466

bolt/include/bolt/Passes/BinaryPasses.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ class BinaryFunctionPass {
5050
/// this pass is completed (printPass() must have returned true).
5151
virtual bool shouldPrint(const BinaryFunction &BF) const;
5252

53-
/// Execute this pass on the given functions.
5453
virtual Error runOnFunctions(BinaryContext &BC) = 0;
5554
};
5655

@@ -74,14 +73,14 @@ class DynoStatsPrintPass : public BinaryFunctionPass {
7473
const DynoStats NewDynoStats =
7574
getDynoStats(BC.getBinaryFunctions(), BC.isAArch64());
7675
const bool Changed = (NewDynoStats != PrevDynoStats);
77-
outs() << "BOLT-INFO: program-wide dynostats " << Title
78-
<< (Changed ? "" : " (no change)") << ":\n\n"
79-
<< PrevDynoStats;
76+
BC.outs() << "BOLT-INFO: program-wide dynostats " << Title
77+
<< (Changed ? "" : " (no change)") << ":\n\n"
78+
<< PrevDynoStats;
8079
if (Changed) {
81-
outs() << '\n';
82-
NewDynoStats.print(outs(), &PrevDynoStats, BC.InstPrinter.get());
80+
BC.outs() << '\n';
81+
NewDynoStats.print(BC.outs(), &PrevDynoStats, BC.InstPrinter.get());
8382
}
84-
outs() << '\n';
83+
BC.outs() << '\n';
8584
return Error::success();
8685
}
8786
};

bolt/include/bolt/Passes/CMOVConversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class CMOVConversion : public BinaryFunctionPass {
6464
}
6565
double getMPRatio() { return (double)RemovedMP / PossibleMP; }
6666

67-
void dump();
67+
void dumpTo(raw_ostream &OS);
6868
};
6969
// BinaryContext-wide stats
7070
Stats Global;

bolt/include/bolt/Passes/CacheMetrics.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717
#include <vector>
1818

1919
namespace llvm {
20+
21+
class raw_ostream;
22+
2023
namespace bolt {
2124
class BinaryFunction;
2225
namespace CacheMetrics {
2326

2427
/// Calculate and print various metrics related to instruction cache performance
25-
void printAll(const std::vector<BinaryFunction *> &BinaryFunctions);
28+
void printAll(raw_ostream &OS,
29+
const std::vector<BinaryFunction *> &BinaryFunctions);
2630

2731
} // namespace CacheMetrics
2832
} // namespace bolt

bolt/include/bolt/Passes/ReorderData.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class ReorderData : public BinaryFunctionPass {
3535
sortedByFunc(BinaryContext &BC, const BinarySection &Section,
3636
std::map<uint64_t, BinaryFunction> &BFs) const;
3737

38-
void printOrder(const BinarySection &Section, DataOrder::const_iterator Begin,
38+
void printOrder(BinaryContext &BC, const BinarySection &Section,
39+
DataOrder::const_iterator Begin,
3940
DataOrder::const_iterator End) const;
4041

4142
/// Set the ordering of the section with \p SectionName. \p NewOrder is a

bolt/include/bolt/Passes/ReorderFunctions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ class Cluster;
2020
class ReorderFunctions : public BinaryFunctionPass {
2121
BinaryFunctionCallGraph Cg;
2222

23-
void reorder(std::vector<Cluster> &&Clusters,
23+
void reorder(BinaryContext &BC, std::vector<Cluster> &&Clusters,
2424
std::map<uint64_t, BinaryFunction> &BFs);
2525

26-
void printStats(const std::vector<Cluster> &Clusters,
26+
void printStats(BinaryContext &BC, const std::vector<Cluster> &Clusters,
2727
const std::vector<uint64_t> &FuncAddr);
2828

2929
public:

bolt/include/bolt/Passes/ShrinkWrapping.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ class ShrinkWrapping {
523523

524524
Expected<bool> perform(bool HotOnly = false);
525525

526-
static void printStats();
526+
static void printStats(BinaryContext &BC);
527527
};
528528

529529
} // end namespace bolt

bolt/include/bolt/Profile/BoltAddressTranslation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class BoltAddressTranslation {
8585

8686
/// Read the serialized address translation tables and load them internally
8787
/// in memory. Return a parse error if failed.
88-
std::error_code parse(StringRef Buf);
88+
std::error_code parse(raw_ostream &OS, StringRef Buf);
8989

9090
/// Dump the parsed address translation tables
9191
void dump(raw_ostream &OS);

bolt/include/bolt/Rewrite/RewriteInstance.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,14 @@ class RewriteInstance {
4747
// construction. Constructors can’t return errors, so clients must test \p Err
4848
// after the object is constructed. Use `create` method instead.
4949
RewriteInstance(llvm::object::ELFObjectFileBase *File, const int Argc,
50-
const char *const *Argv, StringRef ToolPath, Error &Err);
50+
const char *const *Argv, StringRef ToolPath,
51+
raw_ostream &Stdout, raw_ostream &Stderr, Error &Err);
5152

5253
static Expected<std::unique_ptr<RewriteInstance>>
5354
create(llvm::object::ELFObjectFileBase *File, const int Argc,
54-
const char *const *Argv, StringRef ToolPath);
55+
const char *const *Argv, StringRef ToolPath,
56+
raw_ostream &Stdout = llvm::outs(),
57+
raw_ostream &Stderr = llvm::errs());
5558
~RewriteInstance();
5659

5760
/// Assign profile from \p Filename to this instance.

bolt/lib/Core/BinaryBasicBlock.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ bool BinaryBasicBlock::validateSuccessorInvariants() {
9292
// Work on the assumption that jump table blocks don't
9393
// have a conditional successor.
9494
Valid = false;
95-
errs() << "BOLT-WARNING: Jump table successor " << Succ->getName()
96-
<< " not contained in the jump table.\n";
95+
BC.errs() << "BOLT-WARNING: Jump table successor " << Succ->getName()
96+
<< " not contained in the jump table.\n";
9797
}
9898
}
9999
// If there are any leftover entries in the jump table, they
@@ -103,8 +103,8 @@ bool BinaryBasicBlock::validateSuccessorInvariants() {
103103
Valid &= (Sym == Function->getFunctionEndLabel() ||
104104
Sym == Function->getFunctionEndLabel(getFragmentNum()));
105105
if (!Valid) {
106-
errs() << "BOLT-WARNING: Jump table contains illegal entry: "
107-
<< Sym->getName() << "\n";
106+
BC.errs() << "BOLT-WARNING: Jump table contains illegal entry: "
107+
<< Sym->getName() << "\n";
108108
}
109109
}
110110
}
@@ -141,11 +141,11 @@ bool BinaryBasicBlock::validateSuccessorInvariants() {
141141
}
142142
}
143143
if (!Valid) {
144-
errs() << "BOLT-WARNING: CFG invalid in " << *getFunction() << " @ "
145-
<< getName() << "\n";
144+
BC.errs() << "BOLT-WARNING: CFG invalid in " << *getFunction() << " @ "
145+
<< getName() << "\n";
146146
if (JT) {
147-
errs() << "Jump Table instruction addr = 0x"
148-
<< Twine::utohexstr(BC.MIB->getJumpTable(*Inst)) << "\n";
147+
BC.errs() << "Jump Table instruction addr = 0x"
148+
<< Twine::utohexstr(BC.MIB->getJumpTable(*Inst)) << "\n";
149149
JT->print(errs());
150150
}
151151
getFunction()->dump();
@@ -520,9 +520,9 @@ uint32_t BinaryBasicBlock::getNumPseudos() const {
520520
++N;
521521

522522
if (N != NumPseudos) {
523-
errs() << "BOLT-ERROR: instructions for basic block " << getName()
524-
<< " in function " << *Function << ": calculated pseudos " << N
525-
<< ", set pseudos " << NumPseudos << ", size " << size() << '\n';
523+
BC.errs() << "BOLT-ERROR: instructions for basic block " << getName()
524+
<< " in function " << *Function << ": calculated pseudos " << N
525+
<< ", set pseudos " << NumPseudos << ", size " << size() << '\n';
526526
llvm_unreachable("pseudos mismatch");
527527
}
528528
#endif
@@ -559,18 +559,18 @@ BinaryBasicBlock::getBranchStats(const BinaryBasicBlock *Succ) const {
559559
void BinaryBasicBlock::dump() const {
560560
BinaryContext &BC = Function->getBinaryContext();
561561
if (Label)
562-
outs() << Label->getName() << ":\n";
563-
BC.printInstructions(outs(), Instructions.begin(), Instructions.end(),
562+
BC.outs() << Label->getName() << ":\n";
563+
BC.printInstructions(BC.outs(), Instructions.begin(), Instructions.end(),
564564
getOffset(), Function);
565-
outs() << "preds:";
565+
BC.outs() << "preds:";
566566
for (auto itr = pred_begin(); itr != pred_end(); ++itr) {
567-
outs() << " " << (*itr)->getName();
567+
BC.outs() << " " << (*itr)->getName();
568568
}
569-
outs() << "\nsuccs:";
569+
BC.outs() << "\nsuccs:";
570570
for (auto itr = succ_begin(); itr != succ_end(); ++itr) {
571-
outs() << " " << (*itr)->getName();
571+
BC.outs() << " " << (*itr)->getName();
572572
}
573-
outs() << "\n";
573+
BC.outs() << "\n";
574574
}
575575

576576
uint64_t BinaryBasicBlock::estimateSize(const MCCodeEmitter *Emitter) const {

0 commit comments

Comments
 (0)