Skip to content

Commit b9bd7f8

Browse files
committedMar 21, 2014
ProfileData: Introduce InstrProfWriter using the naive text format
This isn't a format we'll want to write out in practice, but moving it to the writer library simplifies llvm-profdata and isolates it from further changes to the format. This also allows us to update the tests to not rely on the text output format. llvm-svn: 204489
1 parent c07cc8f commit b9bd7f8

File tree

8 files changed

+205
-81
lines changed

8 files changed

+205
-81
lines changed
 

‎llvm/include/llvm/ProfileData/InstrProf.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ struct instrprof_error {
3131
too_large,
3232
truncated,
3333
malformed,
34-
unknown_function
34+
unknown_function,
35+
hash_mismatch,
36+
count_mismatch,
37+
counter_overflow
3538
};
3639
ErrorType V;
3740

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//=-- InstrProfWriter.h - Instrumented profiling writer -----------*- C++ -*-=//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file contains support for writing profiling data for instrumentation
11+
// based PGO and coverage.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_PROFILEDATA_INSTRPROF_WRITER_H__
16+
#define LLVM_PROFILEDATA_INSTRPROF_WRITER_H__
17+
18+
#include "llvm/ADT/ArrayRef.h"
19+
#include "llvm/ADT/StringMap.h"
20+
#include "llvm/ProfileData/InstrProf.h"
21+
#include "llvm/Support/DataTypes.h"
22+
#include "llvm/Support/raw_ostream.h"
23+
24+
#include <vector>
25+
26+
namespace llvm {
27+
28+
/// Writer for instrumentation based profile data.
29+
class InstrProfWriter {
30+
public:
31+
struct CounterData {
32+
uint64_t Hash;
33+
std::vector<uint64_t> Counts;
34+
};
35+
private:
36+
StringMap<CounterData> FunctionData;
37+
public:
38+
/// Add function counts for the given function. If there are already counts
39+
/// for this function and the hash and number of counts match, each counter is
40+
/// summed.
41+
error_code addFunctionCounts(StringRef FunctionName, uint64_t FunctionHash,
42+
ArrayRef<uint64_t> Counters);
43+
/// Ensure that all data is written to disk.
44+
void write(raw_ostream &OS);
45+
};
46+
47+
} // end namespace llvm
48+
49+
#endif // LLVM_PROFILE_INSTRPROF_WRITER_H__

‎llvm/lib/ProfileData/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_llvm_library(LLVMProfileData
22
InstrProf.cpp
33
InstrProfReader.cpp
4+
InstrProfWriter.cpp
45

56
LINK_LIBS
67
LLVMSupport

‎llvm/lib/ProfileData/InstrProf.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class InstrProfErrorCategoryType : public error_category {
3939
return "Malformed profile data";
4040
case instrprof_error::unknown_function:
4141
return "No profile data available for function";
42+
case instrprof_error::hash_mismatch:
43+
return "Function hash mismatch";
44+
case instrprof_error::count_mismatch:
45+
return "Function count mismatch";
46+
case instrprof_error::counter_overflow:
47+
return "Counter overflow";
4248
}
4349
llvm_unreachable("A value of instrprof_error has no message.");
4450
}
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//=-- InstrProfWriter.cpp - Instrumented profiling writer -------------------=//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file contains support for writing profiling data for clang's
11+
// instrumentation based PGO and coverage.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "llvm/ProfileData/InstrProfWriter.h"
16+
#include "llvm/Support/Endian.h"
17+
18+
using namespace llvm;
19+
20+
error_code InstrProfWriter::addFunctionCounts(StringRef FunctionName,
21+
uint64_t FunctionHash,
22+
ArrayRef<uint64_t> Counters) {
23+
auto Where = FunctionData.find(FunctionName);
24+
if (Where == FunctionData.end()) {
25+
// If this is the first time we've seen this function, just add it.
26+
FunctionData[FunctionName] = {FunctionHash, Counters};
27+
return instrprof_error::success;;
28+
}
29+
30+
auto &Data = Where->getValue();
31+
// We can only add to existing functions if they match, so we check the hash
32+
// and number of counters.
33+
if (Data.Hash != FunctionHash)
34+
return instrprof_error::hash_mismatch;
35+
if (Data.Counts.size() != Counters.size())
36+
return instrprof_error::count_mismatch;
37+
// These match, add up the counters.
38+
for (size_t I = 0, E = Counters.size(); I < E; ++I) {
39+
if (Data.Counts[I] + Counters[I] < Data.Counts[I])
40+
return instrprof_error::counter_overflow;
41+
Data.Counts[I] += Counters[I];
42+
}
43+
return instrprof_error::success;
44+
}
45+
46+
void InstrProfWriter::write(raw_ostream &OS) {
47+
// Write out the counts for each function.
48+
for (const auto &I : FunctionData) {
49+
StringRef Name = I.getKey();
50+
uint64_t Hash = I.getValue().Hash;
51+
const std::vector<uint64_t> &Counts = I.getValue().Counts;
52+
53+
OS << Name << "\n" << Hash << "\n" << Counts.size() << "\n";
54+
for (uint64_t Count : Counts)
55+
OS << Count << "\n";
56+
OS << "\n";
57+
}
58+
}
+6-14
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
1-
RUN: not llvm-profdata merge %p/Inputs/empty.profdata %p/Inputs/foo3-1.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
2-
RUN: not llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo3bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
3-
RUN: not llvm-profdata merge %p/Inputs/foo4-1.profdata %p/Inputs/empty.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
4-
LENGTH: error: Number of instrumented functions differ
1+
RUN: llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo4-1.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=HASH
2+
HASH: foo4-1.profdata: foo: Function hash mismatch
53

6-
RUN: not llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=NAME
7-
NAME: error: Function name mismatch, foo != bar
8-
9-
RUN: not llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo4-1.profdata 2>&1 | FileCheck %s --check-prefix=HASH
10-
HASH: error: Function hash mismatch for foo
11-
12-
RUN: not llvm-profdata merge %p/Inputs/overflow.profdata %p/Inputs/overflow.profdata 2>&1 | FileCheck %s --check-prefix=OVERFLOW
13-
OVERFLOW: error: Counter overflow for overflow
4+
RUN: llvm-profdata merge %p/Inputs/overflow.profdata %p/Inputs/overflow.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW
5+
OVERFLOW: overflow.profdata: overflow: Counter overflow
146

157
RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.profdata %p/Inputs/invalid-count-later.profdata 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
16-
INVALID-COUNT-LATER: error: {{.*}}: Malformed profile data
8+
INVALID-COUNT-LATER: error: {{.*}}invalid-count-later.profdata: Malformed profile data
179

1810
RUN: not llvm-profdata merge %p/Inputs/bad-hash.profdata %p/Inputs/bad-hash.profdata 2>&1 | FileCheck %s --check-prefix=BAD-HASH
19-
BAD-HASH: error: {{.*}}: Malformed profile data
11+
BAD-HASH: error: {{.*}}bad-hash.profdata: Malformed profile data
+66-31
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,68 @@
1-
RUN: llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo3-2.profdata 2>&1 | FileCheck %s --check-prefix=FOO3
2-
RUN: llvm-profdata merge %p/Inputs/foo3-2.profdata %p/Inputs/foo3-1.profdata 2>&1 | FileCheck %s --check-prefix=FOO3
3-
FOO3: {{^foo$}}
4-
FOO3-NEXT: {{^3$}}
5-
FOO3-NEXT: {{^3$}}
6-
FOO3-NEXT: {{^8$}}
7-
FOO3-NEXT: {{^7$}}
8-
FOO3-NEXT: {{^6$}}
1+
RUN: llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo3-2.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO3
2+
RUN: llvm-profdata merge %p/Inputs/foo3-2.profdata %p/Inputs/foo3-1.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO3
3+
FOO3: foo:
4+
FOO3: Counters: 3
5+
FOO3: Function count: 8
6+
FOO3: Block counts: [7, 6]
7+
FOO3: Total functions: 1
8+
FOO3: Maximum function count: 8
9+
FOO3: Maximum internal block count: 7
910

10-
RUN: llvm-profdata merge %p/Inputs/foo4-1.profdata %p/Inputs/foo4-2.profdata 2>&1 | FileCheck %s --check-prefix=FOO4
11-
RUN: llvm-profdata merge %p/Inputs/foo4-2.profdata %p/Inputs/foo4-1.profdata 2>&1 | FileCheck %s --check-prefix=FOO4
12-
FOO4: {{^foo$}}
13-
FOO4-NEXT: {{^4$}}
14-
FOO4-NEXT: {{^4$}}
15-
FOO4-NEXT: {{^18$}}
16-
FOO4-NEXT: {{^28$}}
17-
FOO4-NEXT: {{^38$}}
18-
FOO4-NEXT: {{^48$}}
11+
RUN: llvm-profdata merge %p/Inputs/foo4-1.profdata %p/Inputs/foo4-2.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO4
12+
RUN: llvm-profdata merge %p/Inputs/foo4-2.profdata %p/Inputs/foo4-1.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO4
13+
FOO4: foo:
14+
FOO4: Counters: 4
15+
FOO4: Function count: 18
16+
FOO4: Block counts: [28, 38, 48]
17+
FOO4: Total functions: 1
18+
FOO4: Maximum function count: 18
19+
FOO4: Maximum internal block count: 48
1920

20-
RUN: llvm-profdata merge %p/Inputs/foo3bar3-1.profdata %p/Inputs/foo3bar3-2.profdata 2>&1 | FileCheck %s --check-prefix=FOO3BAR3
21-
RUN: llvm-profdata merge %p/Inputs/foo3bar3-2.profdata %p/Inputs/foo3bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=FOO3BAR3
22-
FOO3BAR3: {{^foo$}}
23-
FOO3BAR3-NEXT: {{^3$}}
24-
FOO3BAR3-NEXT: {{^3$}}
25-
FOO3BAR3-NEXT: {{^19$}}
26-
FOO3BAR3-NEXT: {{^22$}}
27-
FOO3BAR3-NEXT: {{^28$}}
28-
FOO3BAR3: {{^bar$}}
29-
FOO3BAR3-NEXT: {{^3$}}
30-
FOO3BAR3-NEXT: {{^3$}}
31-
FOO3BAR3-NEXT: {{^36$}}
32-
FOO3BAR3-NEXT: {{^42$}}
33-
FOO3BAR3-NEXT: {{^50$}}
21+
RUN: llvm-profdata merge %p/Inputs/foo3bar3-1.profdata %p/Inputs/foo3bar3-2.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO3BAR3
22+
RUN: llvm-profdata merge %p/Inputs/foo3bar3-2.profdata %p/Inputs/foo3bar3-1.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO3BAR3
23+
FOO3BAR3: foo:
24+
FOO3BAR3: Counters: 3
25+
FOO3BAR3: Function count: 19
26+
FOO3BAR3: Block counts: [22, 28]
27+
FOO3BAR3: bar:
28+
FOO3BAR3: Counters: 3
29+
FOO3BAR3: Function count: 36
30+
FOO3BAR3: Block counts: [42, 50]
31+
FOO3BAR3: Total functions: 2
32+
FOO3BAR3: Maximum function count: 36
33+
FOO3BAR3: Maximum internal block count: 50
34+
35+
RUN: llvm-profdata merge %p/Inputs/empty.profdata %p/Inputs/foo3-1.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO3EMPTY
36+
FOO3EMPTY: foo:
37+
FOO3EMPTY: Counters: 3
38+
FOO3EMPTY: Function count: 1
39+
FOO3EMPTY: Block counts: [2, 3]
40+
FOO3EMPTY: Total functions: 1
41+
FOO3EMPTY: Maximum function count: 1
42+
FOO3EMPTY: Maximum internal block count: 3
43+
44+
RUN: llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/foo3bar3-1.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=FOO3FOO3BAR3
45+
FOO3FOO3BAR3: foo:
46+
FOO3FOO3BAR3: Counters: 3
47+
FOO3FOO3BAR3: Function count: 3
48+
FOO3FOO3BAR3: Block counts: [5, 8]
49+
FOO3FOO3BAR3: bar:
50+
FOO3FOO3BAR3: Counters: 3
51+
FOO3FOO3BAR3: Function count: 7
52+
FOO3FOO3BAR3: Block counts: [11, 13]
53+
FOO3FOO3BAR3: Total functions: 2
54+
FOO3FOO3BAR3: Maximum function count: 7
55+
FOO3FOO3BAR3: Maximum internal block count: 13
56+
57+
RUN: llvm-profdata merge %p/Inputs/foo3-1.profdata %p/Inputs/bar3-1.profdata 2>&1 | llvm-profdata show - -all-functions -counts | FileCheck %s --check-prefix=DISJOINT
58+
DISJOINT: foo:
59+
DISJOINT: Counters: 3
60+
DISJOINT: Function count: 1
61+
DISJOINT: Block counts: [2, 3]
62+
DISJOINT: bar:
63+
DISJOINT: Counters: 3
64+
DISJOINT: Function count: 1
65+
DISJOINT: Block counts: [2, 3]
66+
DISJOINT: Total functions: 2
67+
DISJOINT: Maximum function count: 1
68+
DISJOINT: Maximum internal block count: 3

‎llvm/tools/llvm-profdata/llvm-profdata.cpp

+15-35
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "llvm/ADT/StringRef.h"
1515
#include "llvm/ProfileData/InstrProfReader.h"
16+
#include "llvm/ProfileData/InstrProfWriter.h"
1617
#include "llvm/Support/CommandLine.h"
1718
#include "llvm/Support/ManagedStatic.h"
1819
#include "llvm/Support/MemoryBuffer.h"
@@ -31,10 +32,8 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") {
3132
}
3233

3334
int merge_main(int argc, const char *argv[]) {
34-
cl::opt<std::string> Filename1(cl::Positional, cl::Required,
35-
cl::desc("file1"));
36-
cl::opt<std::string> Filename2(cl::Positional, cl::Required,
37-
cl::desc("file2"));
35+
cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
36+
cl::desc("<filenames...>"));
3837

3938
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
4039
cl::init("-"),
@@ -44,12 +43,6 @@ int merge_main(int argc, const char *argv[]) {
4443

4544
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
4645

47-
std::unique_ptr<InstrProfReader> Reader1, Reader2;
48-
if (error_code ec = InstrProfReader::create(Filename1, Reader1))
49-
exitWithError(ec.message(), Filename1);
50-
if (error_code ec = InstrProfReader::create(Filename2, Reader2))
51-
exitWithError(ec.message(), Filename2);
52-
5346
if (OutputFilename.empty())
5447
OutputFilename = "-";
5548

@@ -58,32 +51,19 @@ int merge_main(int argc, const char *argv[]) {
5851
if (!ErrorInfo.empty())
5952
exitWithError(ErrorInfo, OutputFilename);
6053

61-
for (InstrProfIterator I1 = Reader1->begin(), E1 = Reader1->end(),
62-
I2 = Reader2->begin(), E2 = Reader2->end();
63-
I1 != E1 && I2 != E2; ++I1, ++I2) {
64-
if (I1->Name != I2->Name)
65-
exitWithError("Function name mismatch, " + I1->Name + " != " + I2->Name);
66-
if (I1->Hash != I2->Hash)
67-
exitWithError("Function hash mismatch for " + I1->Name);
68-
if (I1->Counts.size() != I2->Counts.size())
69-
exitWithError("Function count mismatch for " + I1->Name);
70-
71-
Output << I1->Name << "\n" << I1->Hash << "\n" << I1->Counts.size() << "\n";
72-
73-
for (size_t II = 0, EE = I1->Counts.size(); II < EE; ++II) {
74-
uint64_t Sum = I1->Counts[II] + I2->Counts[II];
75-
if (Sum < I1->Counts[II])
76-
exitWithError("Counter overflow for " + I1->Name);
77-
Output << Sum << "\n";
78-
}
79-
Output << "\n";
54+
InstrProfWriter Writer;
55+
for (const auto &Filename : Inputs) {
56+
std::unique_ptr<InstrProfReader> Reader;
57+
if (error_code ec = InstrProfReader::create(Filename, Reader))
58+
exitWithError(ec.message(), Filename);
59+
60+
for (const auto &I : *Reader)
61+
if (error_code EC = Writer.addFunctionCounts(I.Name, I.Hash, I.Counts))
62+
errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n";
63+
if (Reader->hasError())
64+
exitWithError(Reader->getError().message(), Filename);
8065
}
81-
if (Reader1->hasError())
82-
exitWithError(Reader1->getError().message(), Filename1);
83-
if (Reader2->hasError())
84-
exitWithError(Reader2->getError().message(), Filename2);
85-
if (!Reader1->isEOF() || !Reader2->isEOF())
86-
exitWithError("Number of instrumented functions differ.");
66+
Writer.write(Output);
8767

8868
return 0;
8969
}

0 commit comments

Comments
 (0)
Please sign in to comment.