LLVM 20.0.0git
PGOCtxProfWriter.cpp
Go to the documentation of this file.
1//===- PGOCtxProfWriter.cpp - Contextual Instrumentation profile writer ---===//
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// Write a contextual profile to bitstream.
10//
11//===----------------------------------------------------------------------===//
12
16#include "llvm/Support/JSON.h"
17
18using namespace llvm;
19using namespace llvm::ctx_profile;
20
22 raw_ostream &Out, std::optional<unsigned> VersionOverride)
23 : Writer(Out, 0) {
24 static_assert(ContainerMagic.size() == 4);
26 Writer.EnterBlockInfoBlock();
27 {
28 auto DescribeBlock = [&](unsigned ID, StringRef Name) {
32 llvm::arrayRefFromStringRef(Name));
33 };
35 auto DescribeRecord = [&](unsigned RecordID, StringRef Name) {
36 Data.clear();
37 Data.push_back(RecordID);
40 };
41 DescribeBlock(PGOCtxProfileBlockIDs::ProfileMetadataBlockID, "Metadata");
42 DescribeRecord(PGOCtxProfileRecords::Version, "Version");
43 DescribeBlock(PGOCtxProfileBlockIDs::ContextNodeBlockID, "Context");
44 DescribeRecord(PGOCtxProfileRecords::Guid, "GUID");
45 DescribeRecord(PGOCtxProfileRecords::CalleeIndex, "CalleeIndex");
46 DescribeRecord(PGOCtxProfileRecords::Counters, "Counters");
47 }
48 Writer.ExitBlock();
50 const auto Version = VersionOverride.value_or(CurrentVersion);
53}
54
55void PGOCtxProfileWriter::writeCounters(const ContextNode &Node) {
58 Writer.EmitVBR(Node.counters_size(), VBREncodingBits);
59 for (uint32_t I = 0U; I < Node.counters_size(); ++I)
60 Writer.EmitVBR64(Node.counters()[I], VBREncodingBits);
61}
62
63// recursively write all the subcontexts. We do need to traverse depth first to
64// model the context->subcontext implicitly, and since this captures call
65// stacks, we don't really need to be worried about stack overflow and we can
66// keep the implementation simple.
67void PGOCtxProfileWriter::writeImpl(std::optional<uint32_t> CallerIndex,
68 const ContextNode &Node) {
72 if (CallerIndex)
74 SmallVector<uint64_t, 1>{*CallerIndex});
75 writeCounters(Node);
76 for (uint32_t I = 0U; I < Node.callsites_size(); ++I)
77 for (const auto *Subcontext = Node.subContexts()[I]; Subcontext;
78 Subcontext = Subcontext->next())
79 writeImpl(I, *Subcontext);
80 Writer.ExitBlock();
81}
82
84 writeImpl(std::nullopt, RootNode);
85}
86
87namespace {
88// A structural representation of the JSON input.
89struct DeserializableCtx {
91 std::vector<uint64_t> Counters;
92 std::vector<std::vector<DeserializableCtx>> Callsites;
93};
94
96createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
97 const std::vector<DeserializableCtx> &DCList);
98
99// Convert a DeserializableCtx into a ContextNode, potentially linking it to
100// its sibling (e.g. callee at same callsite) "Next".
102createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
103 const DeserializableCtx &DC,
104 ctx_profile::ContextNode *Next = nullptr) {
105 auto AllocSize = ctx_profile::ContextNode::getAllocSize(DC.Counters.size(),
106 DC.Callsites.size());
107 auto *Mem = Nodes.emplace_back(std::make_unique<char[]>(AllocSize)).get();
108 std::memset(Mem, 0, AllocSize);
109 auto *Ret = new (Mem) ctx_profile::ContextNode(DC.Guid, DC.Counters.size(),
110 DC.Callsites.size(), Next);
111 std::memcpy(Ret->counters(), DC.Counters.data(),
112 sizeof(uint64_t) * DC.Counters.size());
113 for (const auto &[I, DCList] : llvm::enumerate(DC.Callsites))
114 Ret->subContexts()[I] = createNode(Nodes, DCList);
115 return Ret;
116}
117
118// Convert a list of DeserializableCtx into a linked list of ContextNodes.
120createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
121 const std::vector<DeserializableCtx> &DCList) {
123 for (const auto &DC : DCList)
124 List = createNode(Nodes, DC, List);
125 return List;
126}
127} // namespace
128
129namespace llvm {
130namespace json {
131bool fromJSON(const Value &E, DeserializableCtx &R, Path P) {
132 json::ObjectMapper Mapper(E, P);
133 return Mapper && Mapper.map("Guid", R.Guid) &&
134 Mapper.map("Counters", R.Counters) &&
135 Mapper.mapOptional("Callsites", R.Callsites);
136}
137} // namespace json
138} // namespace llvm
139
141 auto P = json::parse(Profile);
142 if (!P)
143 return P.takeError();
144
145 json::Path::Root R("");
146 std::vector<DeserializableCtx> DCList;
147 if (!fromJSON(*P, DCList, R))
148 return R.getError();
149 // Nodes provides memory backing for the ContextualNodes.
150 std::vector<std::unique_ptr<char[]>> Nodes;
151 std::error_code EC;
152 if (EC)
153 return createStringError(EC, "failed to open output");
154 PGOCtxProfileWriter Writer(Out);
155 for (const auto &DC : DCList) {
156 auto *TopList = createNode(Nodes, DC);
157 if (!TopList)
158 return createStringError(
159 "Unexpected error converting internal structure to ctx profile");
160 Writer.write(*TopList);
161 }
162 if (EC)
163 return createStringError(EC, "failed to write output");
164 return Error::success();
165}
std::string Name
This file supports working with JSON data.
#define I(x, y, z)
Definition: MD5.cpp:58
Load MIR Sample Profile
#define P(N)
void EmitRecord(unsigned Code, const Container &Vals, unsigned Abbrev=0)
EmitRecord - Emit the specified record to the stream, using an abbrev if we have one to compress the ...
void EmitCode(unsigned Val)
EmitCode - Emit the specified code.
void EmitVBR64(uint64_t Val, unsigned NumBits)
void EnterBlockInfoBlock()
EnterBlockInfoBlock - Start emitting the BLOCKINFO_BLOCK.
void EmitVBR(uint32_t Val, unsigned NumBits)
void EnterSubblock(unsigned BlockID, unsigned CodeLen)
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Write one or more ContextNodes to the provided raw_fd_stream.
static constexpr unsigned VBREncodingBits
static constexpr uint32_t CurrentVersion
static constexpr StringRef ContainerMagic
PGOCtxProfileWriter(raw_ostream &Out, std::optional< unsigned > VersionOverride=std::nullopt)
void write(const ctx_profile::ContextNode &)
static constexpr unsigned CodeLen
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:150
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:144
static size_t getAllocSize(uint32_t NumCounters, uint32_t NumCallsites)
Helper for mapping JSON objects onto protocol structs.
Definition: JSON.h:842
bool map(StringLiteral Prop, T &Out)
Maps a property to a field.
Definition: JSON.h:856
bool mapOptional(StringLiteral Prop, T &Out)
Maps a property to a field, if it exists.
Definition: JSON.h:878
The root is the trivial Path to the root value.
Definition: JSON.h:702
A "cursor" marking a position within a Value.
Definition: JSON.h:655
A Value is an JSON value of unknown type.
Definition: JSON.h:288
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
raw_ostream & write(unsigned char C)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ BLOCKINFO_CODE_BLOCKNAME
Definition: BitCodeEnums.h:82
@ BLOCKINFO_CODE_SETRECORDNAME
Definition: BitCodeEnums.h:83
@ BLOCKINFO_CODE_SETBID
Definition: BitCodeEnums.h:81
llvm::Expected< Value > parse(llvm::StringRef JSON)
Parses the provided JSON source, or returns a ParseError.
Definition: JSON.cpp:682
bool fromJSON(const Value &E, std::string &Out, Path P)
Definition: JSON.h:731
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition: STLExtras.h:2448
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition: STLExtras.h:2115
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1291
Error createCtxProfFromJSON(StringRef Profile, raw_ostream &Out)
@ ContextNodeBlockID
@ ProfileMetadataBlockID