aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ProfileData/SampleProfReader.cpp
diff options
context:
space:
mode:
authorKazu Hirata <kazu@google.com>2022-08-09 16:24:53 -0700
committerKazu Hirata <kazu@google.com>2022-08-09 16:24:53 -0700
commita044d0491efeb821f1f23a935515692984b21ad5 (patch)
treea98da0b39e8c4fb6ff95383d5504fa4de58c32ed /llvm/lib/ProfileData/SampleProfReader.cpp
parentdf9a23e2feda18f0308b6d4dbd591ebe6b605aa4 (diff)
downloadllvm-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.cpp74
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,