Skip to content

Commit f03c00c

Browse files
committed
Add llvm-mipdata tool
The `llvm-mipdata` tool is used to create, merge, and show machine profiles. Usage: The compiler provides us with a map file `default.mipmap` at build time which we need to convert to a profile. ``` $ llvm-mipdata create -p default.mip default.mipmap ``` When we run the instrumented binary, it will produce a raw file `default.mipraw` that we can merge into our profile. ``` $ llvm-mipdata merge -p default.mip default.mipraw ``` Then we view the contents of the profile. If we have debug info, we can also view source info from the profile. ``` $ llvm-mipdata show -p default.mip --debug a.out _Z3fooi Source Info: /home/main.cpp:9 Call Count: 0 Block Coverage: COLD COLD COLD COLD HOT _Z3bari Source Info: /home/main.cpp:16 Call Count: 1 Block Coverage: HOT HOT COLD HOT HOT ``` Differential Revision: https://reviews.llvm.org/D104087
1 parent ae9f5e4 commit f03c00c

File tree

19 files changed

+1539
-0
lines changed

19 files changed

+1539
-0
lines changed

llvm/include/llvm/CodeGen/MIPReader.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===---- MIPReader.h -------------------------------------------*- 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+
//===----------------------------------------------------------------------===//
11+
12+
#ifndef LLVM_CODEGEN_MIP_READER_H
13+
#define LLVM_CODEGEN_MIP_READER_H
14+
15+
#include "llvm/CodeGen/MachineFunction.h"
16+
#include "llvm/MIP/MIP.h"
17+
#include "llvm/Support/EndianStream.h"
18+
#include "llvm/Support/MemoryBuffer.h"
19+
20+
namespace llvm {
21+
namespace MachineProfile {
22+
23+
class MIPReader {
24+
public:
25+
static ErrorOr<std::unique_ptr<MIRProfile>> read(const Twine &Filename);
26+
27+
private:
28+
static std::error_code readData(std::unique_ptr<MemoryBuffer> &Buffer,
29+
std::unique_ptr<MIRProfile> &MIP);
30+
static MFProfile readNextProfile(const char *&Data);
31+
};
32+
33+
class MIPMapReader {
34+
public:
35+
static ErrorOr<std::unique_ptr<MIRProfile>> read(const Twine &Filename);
36+
37+
private:
38+
static std::error_code readData(std::unique_ptr<MemoryBuffer> &Buffer,
39+
std::unique_ptr<MIRProfile> &MIP);
40+
static ErrorOr<std::unique_ptr<MFProfile>> readNextProfile(const char *&Data,
41+
uint16_t Version);
42+
};
43+
44+
class MIPRawReader {
45+
public:
46+
static ErrorOr<std::unique_ptr<MIRRawProfile>>
47+
read(const Twine &Filename, const std::unique_ptr<MIRProfile> &MIP);
48+
49+
private:
50+
static std::error_code readData(std::unique_ptr<MemoryBuffer> &Buffer,
51+
std::unique_ptr<MIRRawProfile> &RawMIP,
52+
const std::unique_ptr<MIRProfile> &MIP);
53+
};
54+
55+
} // namespace MachineProfile
56+
} // namespace llvm
57+
58+
#endif // LLVM_CODEGEN_MIP_READER_H

llvm/include/llvm/CodeGen/MIPWriter.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===---- MIPWriter.h -------------------------------------------*- 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+
//===----------------------------------------------------------------------===//
11+
12+
#ifndef LLVM_CODEGEN_MIP_WRITER_H
13+
#define LLVM_CODEGEN_MIP_WRITER_H
14+
15+
#include "llvm/CodeGen/MachineFunction.h"
16+
#include "llvm/MIP/MIP.h"
17+
#include "llvm/Support/EndianStream.h"
18+
#include "llvm/Support/MemoryBuffer.h"
19+
20+
namespace llvm {
21+
namespace MachineProfile {
22+
23+
class MIPWriter {
24+
public:
25+
static ErrorOr<std::unique_ptr<MIPWriter>> create(StringRef Filename);
26+
27+
void write(const std::vector<MFProfile> &Profiles, uint16_t Version,
28+
uint32_t ProfileType, uint32_t ModuleHash);
29+
30+
private:
31+
std::unique_ptr<raw_ostream> OutputStream;
32+
33+
MIPWriter(std::unique_ptr<raw_ostream> &OS) : OutputStream(std::move(OS)) {}
34+
35+
static std::unique_ptr<MIPWriter> create(std::unique_ptr<raw_ostream> &OS) {
36+
std::unique_ptr<MIPWriter> Writer;
37+
Writer.reset(new MIPWriter(OS));
38+
return Writer;
39+
}
40+
};
41+
42+
} // namespace MachineProfile
43+
} // namespace llvm
44+
45+
#endif // LLVM_CODEGEN_MIP_WRITER_H

llvm/include/llvm/CodeGen/MIPYaml.h

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===---- MIPYaml.h ---------------------------------------------*- 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+
//===----------------------------------------------------------------------===//
11+
12+
#ifndef LLVM_CODEGEN_MIP_YAML_H
13+
#define LLVM_CODEGEN_MIP_YAML_H
14+
15+
#include "llvm/MIP/MIP.h"
16+
#include "llvm/Support/YAMLTraits.h"
17+
18+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachineProfile::MFProfile)
19+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachineProfile::MBBProfile)
20+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachineProfile::CallEdge)
21+
22+
namespace llvm {
23+
namespace yaml {
24+
25+
// Map this value as a hex value.
26+
template <typename HexType, typename IntType>
27+
static inline void mapRequiredAsHex(IO &io, const char *Key, IntType &Value) {
28+
auto HexValue = static_cast<HexType>(Value);
29+
io.mapRequired(Key, HexValue);
30+
Value = static_cast<IntType>(HexValue);
31+
}
32+
33+
template <> struct ScalarEnumerationTraits<llvm::MachineProfile::MIPFileType> {
34+
static void enumeration(IO &io, llvm::MachineProfile::MIPFileType &FileType) {
35+
// TODO: These file formats are not supported yet.
36+
// io.enumCase(FileType, ".mipraw", MIP_FILE_TYPE_RAW);
37+
// io.enumCase(FileType, ".mipmap", MIP_FILE_TYPE_MAP);
38+
io.enumCase(FileType, ".mip", llvm::MachineProfile::MIP_FILE_TYPE_PROFILE);
39+
}
40+
};
41+
42+
template <> struct ScalarBitSetTraits<llvm::MachineProfile::MIPProfileType> {
43+
static void bitset(IO &io,
44+
llvm::MachineProfile::MIPProfileType &ProfileType) {
45+
io.bitSetCase(ProfileType, "Function Coverage",
46+
llvm::MachineProfile::MIP_PROFILE_TYPE_FUNCTION_COVERAGE);
47+
io.bitSetCase(ProfileType, "Block Coverage",
48+
llvm::MachineProfile::MIP_PROFILE_TYPE_BLOCK_COVERAGE);
49+
io.bitSetCase(ProfileType, "Function Timestamp",
50+
llvm::MachineProfile::MIP_PROFILE_TYPE_FUNCTION_TIMESTAMP);
51+
io.bitSetCase(ProfileType, "Function Call Count",
52+
llvm::MachineProfile::MIP_PROFILE_TYPE_FUNCTION_CALL_COUNT);
53+
io.bitSetCase(ProfileType, "Return Address",
54+
llvm::MachineProfile::MIP_PROFILE_TYPE_RETURN_ADDRESS);
55+
}
56+
};
57+
58+
template <> struct MappingTraits<llvm::MachineProfile::CallEdge> {
59+
static void mapping(IO &io, llvm::MachineProfile::CallEdge &Edge) {
60+
mapRequiredAsHex<Hex32>(io, "Section Relative Source Address",
61+
Edge.SectionRelativeSourceAddress);
62+
io.mapRequired("Weight", Edge.Weight);
63+
}
64+
};
65+
66+
template <> struct MappingTraits<llvm::MachineProfile::MBBProfile> {
67+
static void mapping(IO &io, llvm::MachineProfile::MBBProfile &Profile) {
68+
mapRequiredAsHex<Hex32>(io, "Offset", Profile.Offset);
69+
io.mapRequired("Covered", Profile.IsCovered);
70+
}
71+
};
72+
73+
template <> struct MappingTraits<llvm::MachineProfile::MIPHeader> {
74+
static void mapping(IO &io, llvm::MachineProfile::MIPHeader &Header) {
75+
auto FileType =
76+
static_cast<llvm::MachineProfile::MIPFileType>(Header.FileType);
77+
auto ProfileType =
78+
static_cast<llvm::MachineProfile::MIPProfileType>(Header.ProfileType);
79+
io.mapRequired("File Type", FileType);
80+
io.mapRequired("Profile Type", ProfileType);
81+
Header.FileType = FileType;
82+
Header.ProfileType = ProfileType;
83+
84+
mapRequiredAsHex<Hex32>(io, "Module Hash", Header.ModuleHash);
85+
}
86+
};
87+
88+
template <> struct MappingTraits<llvm::MachineProfile::MFProfile> {
89+
static void mapping(IO &io, llvm::MachineProfile::MFProfile &Profile) {
90+
io.mapRequired("Function Name", Profile.FunctionName);
91+
mapRequiredAsHex<Hex64>(io, "Function Signature",
92+
Profile.FunctionSignature);
93+
mapRequiredAsHex<Hex32>(io, "Raw Profile Data Address",
94+
Profile.RawProfileDataAddress);
95+
mapRequiredAsHex<Hex32>(io, "Encoded Function Address",
96+
Profile.EncodedFunctionAddress);
97+
mapRequiredAsHex<Hex32>(io, "Function Size", Profile.FunctionSize);
98+
mapRequiredAsHex<Hex32>(io, "Control Flow Graph Signature",
99+
Profile.ControlFlowGraphSignature);
100+
io.mapRequired("Raw Profile Count", Profile.RawProfileCount);
101+
io.mapRequired("Function Call Count", Profile.FunctionCallCount);
102+
io.mapRequired("Function Order Sum", Profile.FunctionOrderSum);
103+
io.mapRequired("Basic Block Profiles", Profile.BasicBlockProfiles);
104+
io.mapRequired("Call Edges", Profile.CallEdges);
105+
}
106+
};
107+
108+
template <>
109+
struct MappingTraits<std::unique_ptr<llvm::MachineProfile::MIRProfile>> {
110+
static void mapping(IO &io,
111+
std::unique_ptr<llvm::MachineProfile::MIRProfile> &MIP) {
112+
io.mapRequired("Header", MIP->Header);
113+
io.mapRequired("Profiles", MIP->Profiles);
114+
}
115+
};
116+
117+
} // namespace yaml
118+
} // namespace llvm
119+
120+
#endif // LLVM_CODEGEN_MIP_YAML_H

llvm/include/llvm/MIP/MIP.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,95 @@
99
#ifndef LLVM_MIP_MIP_H
1010
#define LLVM_MIP_MIP_H
1111

12+
#include "llvm/ADT/SmallVector.h"
13+
#include <string>
14+
#include <vector>
15+
1216
namespace llvm {
1317
namespace MachineProfile {
1418

1519
#include "llvm/MIP/MIPData.inc"
1620

21+
std::string fileTypeToString(const MIPFileType &FileType);
22+
23+
// Profile of a function call to a particular machine function
24+
struct CallEdge {
25+
// The section-relative address of the callsite
26+
uint32_t SectionRelativeSourceAddress;
27+
// The weight associated with this call edge
28+
uint32_t Weight;
29+
};
30+
31+
// Machine IR profile data of a machine basic block.
32+
struct MBBProfile {
33+
// Function-relative machine basic block offset
34+
uint32_t Offset;
35+
// True if this block was executed
36+
bool IsCovered;
37+
38+
MBBProfile() : Offset(0), IsCovered(false) {}
39+
MBBProfile(uint32_t Offset) : Offset(Offset), IsCovered(false) {}
40+
};
41+
42+
// Machine IR profile data of a machine function.
43+
struct MFProfile {
44+
std::string FunctionName;
45+
// MD5 hash of the function name
46+
uint64_t FunctionSignature;
47+
// Section-relative raw profile address
48+
uint32_t RawProfileDataAddress;
49+
// Function address offset to raw section
50+
uint32_t EncodedFunctionAddress;
51+
// Function size
52+
uint32_t FunctionSize;
53+
// MD5 hash of the control flow graph of the function
54+
uint32_t ControlFlowGraphSignature;
55+
// The number of raw profiles accumulated into this profile
56+
uint32_t RawProfileCount;
57+
// The number of times this function was called.
58+
uint64_t FunctionCallCount;
59+
// Accumulation over all raw profiles of the order index of this function
60+
uint64_t FunctionOrderSum;
61+
// Profiles of machine basic blocks
62+
SmallVector<MBBProfile, 8> BasicBlockProfiles;
63+
// Profiles of incoming machine function calls
64+
SmallVector<CallEdge, 8> CallEdges;
65+
};
66+
67+
// Machine IR profile data of a particular module.
68+
struct MIRProfile {
69+
public:
70+
MIPHeader Header;
71+
std::vector<MFProfile> Profiles;
72+
73+
void getOrderedProfiles(std::vector<MFProfile> &OrderedProfiles) const;
74+
};
75+
76+
// Machine IR raw profile data of a machine function.
77+
struct MFRawProfile {
78+
// Section-relative raw profile address
79+
uint32_t RawProfileDataAddress = 0;
80+
81+
// MIPProfileType::FUNCTION_COVERAGE
82+
bool IsFunctionCovered = 0;
83+
84+
// MIPProfileType::BLOCK_COVERAGE
85+
SmallVector<bool, 8> BasicBlockCoverage;
86+
87+
// MIPProfileType::FUNCTION_CALL_COUNT
88+
uint32_t FunctionCallCount = 0;
89+
90+
// MIPProfileType::FUNCTION_TIMESTAMP
91+
uint32_t FunctionTimestamp = 0;
92+
};
93+
94+
// Machine IR raw profile data of a module.
95+
struct MIRRawProfile {
96+
MIPHeader Header;
97+
std::vector<MFRawProfile> RawProfiles;
98+
std::vector<CallEdge_t> RawCallEdges;
99+
};
100+
17101
} // namespace MachineProfile
18102
} // namespace llvm
19103

llvm/lib/CodeGen/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@ add_llvm_component_library(LLVMCodeGen
147147
MIRNamerPass.cpp
148148
MIRCanonicalizerPass.cpp
149149
MIRInstrumentationPass.cpp
150+
MIPReader.cpp
150151
MIPSectionEmitter.cpp
152+
MIPWriter.cpp
153+
MIP.cpp
151154
RegisterUsageInfo.cpp
152155
RegUsageInfoCollector.cpp
153156
RegUsageInfoPropagate.cpp

llvm/lib/CodeGen/MIP.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===- MIP.cpp - Machine IR Profile ---------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/MIP/MIP.h"
10+
#include "llvm/ADT/Twine.h"
11+
12+
namespace llvm {
13+
namespace MachineProfile {
14+
15+
std::string fileTypeToString(const MIPFileType &FileType) {
16+
switch (FileType) {
17+
case MIP_FILE_TYPE_RAW:
18+
return "Raw";
19+
case MIP_FILE_TYPE_MAP:
20+
return "Map";
21+
case MIP_FILE_TYPE_PROFILE:
22+
return "Profile";
23+
case MIP_FILE_TYPE_CALL_EDGE_SAMPLES:
24+
return "Call Edge Samples";
25+
default:
26+
return "Unknown File Type";
27+
}
28+
}
29+
30+
void MIRProfile::getOrderedProfiles(
31+
std::vector<MFProfile> &OrderedProfiles) const {
32+
for (auto &Profile : Profiles) {
33+
if (Profile.RawProfileCount > 0) {
34+
// Only consider functions that have been profiled.
35+
OrderedProfiles.push_back(Profile);
36+
}
37+
}
38+
std::stable_sort(OrderedProfiles.begin(), OrderedProfiles.end(),
39+
[](auto &A, auto &B) {
40+
// NOTE: The equation was modified to avoid division.
41+
// A.OrderSum / A.ProfileCount < B.OrderSum /
42+
// B.ProfileCount
43+
return A.FunctionOrderSum * B.RawProfileCount <
44+
B.FunctionOrderSum * A.RawProfileCount;
45+
});
46+
}
47+
48+
} // namespace MachineProfile
49+
} // namespace llvm

0 commit comments

Comments
 (0)