diff options
author | Kazu Hirata <kazu@google.com> | 2022-08-09 16:24:53 -0700 |
---|---|---|
committer | Kazu Hirata <kazu@google.com> | 2022-08-09 16:24:53 -0700 |
commit | a044d0491efeb821f1f23a935515692984b21ad5 (patch) | |
tree | a98da0b39e8c4fb6ff95383d5504fa4de58c32ed /llvm/lib/ProfileData/SampleProfReader.cpp | |
parent | df9a23e2feda18f0308b6d4dbd591ebe6b605aa4 (diff) | |
download | llvm-a044d0491efeb821f1f23a935515692984b21ad5.zip llvm-a044d0491efeb821f1f23a935515692984b21ad5.tar.gz llvm-a044d0491efeb821f1f23a935515692984b21ad5.tar.bz2 |
[llvm-profdata] Support JSON as as an output-only format
This patch teaches llvm-profdata to output the sample profile in the
JSON format. The new option is intended to be used for research and
development purposes. For example, one can write a Python script to
take a JSON file and analyze how similar different inline instances of
a given function are to each other.
I've chosen JSON because Python can parse it reasonably fast, and it
just takes a couple of lines to read the whole data:
import json
with open ('profile.json') as f:
profile = json.load(f)
Differential Revision: https://reviews.llvm.org/D130944
Diffstat (limited to 'llvm/lib/ProfileData/SampleProfReader.cpp')
-rw-r--r-- | llvm/lib/ProfileData/SampleProfReader.cpp | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp index 204e34b..8a97697 100644 --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MD5.h" @@ -72,6 +73,79 @@ void SampleProfileReader::dump(raw_ostream &OS) { dumpFunctionProfile(I.first, OS); } +static void dumpFunctionProfileJson(const FunctionSamples &S, + json::OStream &JOS, bool TopLevel = false) { + auto DumpBody = [&](const BodySampleMap &BodySamples) { + for (const auto &I : BodySamples) { + const LineLocation &Loc = I.first; + const SampleRecord &Sample = I.second; + JOS.object([&] { + JOS.attribute("line", Loc.LineOffset); + if (Loc.Discriminator) + JOS.attribute("discriminator", Loc.Discriminator); + JOS.attribute("samples", Sample.getSamples()); + + auto CallTargets = Sample.getSortedCallTargets(); + if (!CallTargets.empty()) { + JOS.attributeArray("calls", [&] { + for (const auto &J : CallTargets) { + JOS.object([&] { + JOS.attribute("function", J.first); + JOS.attribute("samples", J.second); + }); + } + }); + } + }); + } + }; + + auto DumpCallsiteSamples = [&](const CallsiteSampleMap &CallsiteSamples) { + for (const auto &I : CallsiteSamples) + for (const auto &FS : I.second) { + const LineLocation &Loc = I.first; + const FunctionSamples &CalleeSamples = FS.second; + JOS.object([&] { + JOS.attribute("line", Loc.LineOffset); + if (Loc.Discriminator) + JOS.attribute("discriminator", Loc.Discriminator); + JOS.attributeArray( + "samples", [&] { dumpFunctionProfileJson(CalleeSamples, JOS); }); + }); + } + }; + + JOS.object([&] { + JOS.attribute("name", S.getName()); + JOS.attribute("total", S.getTotalSamples()); + if (TopLevel) + JOS.attribute("head", S.getHeadSamples()); + + const auto &BodySamples = S.getBodySamples(); + if (!BodySamples.empty()) + JOS.attributeArray("body", [&] { DumpBody(BodySamples); }); + + const auto &CallsiteSamples = S.getCallsiteSamples(); + if (!CallsiteSamples.empty()) + JOS.attributeArray("callsites", + [&] { DumpCallsiteSamples(CallsiteSamples); }); + }); +} + +/// Dump all the function profiles found on stream \p OS in the JSON format. +void SampleProfileReader::dumpJson(raw_ostream &OS) { + std::vector<NameFunctionSamples> V; + sortFuncProfiles(Profiles, V); + json::OStream JOS(OS, 2); + JOS.arrayBegin(); + for (const auto &[FC, FS] : V) + dumpFunctionProfileJson(*FS, JOS, true); + JOS.arrayEnd(); + + // Emit a newline character at the end as json::OStream doesn't emit one. + OS << "\n"; +} + /// Parse \p Input as function head. /// /// Parse one line of \p Input, and update function name in \p FName, |