Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ set(LLVM_TEST_DEPENDS
llvm-cfi-verify
llvm-config
llvm-cov
llvm-ctxprof-util
llvm-cvtres
llvm-cxxdump
llvm-cxxfilt
Expand Down
1 change: 1 addition & 0 deletions llvm/test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def get_asan_rtlib():
"llvm-bitcode-strip",
"llvm-config",
"llvm-cov",
"llvm-ctxprof-util",
"llvm-cxxdump",
"llvm-cvtres",
"llvm-debuginfod-find",
Expand Down
1 change: 1 addition & 0 deletions llvm/test/tools/llvm-ctxprof-util/Inputs/bad.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{]
1 change: 1 addition & 0 deletions llvm/test/tools/llvm-ctxprof-util/Inputs/empty.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[{
"Guid": 123,
"Counters": [1, 2],
"Callsites":
[
{"Guid": 1}
]
}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{
"Guid": 1231
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{}]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
29 changes: 29 additions & 0 deletions llvm/test/tools/llvm-ctxprof-util/Inputs/valid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[
{
"Guid": 1000,
"Counters": [1, 2, 3],
"Callsites": [
[],
[
{
"Guid": 2000,
"Counters": [4, 5]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see these counter values in the tested output

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only tested the values for a context, switching to testing the whole output.

},
{
"Guid": 18446744073709551613,
"Counters": [6, 7, 8]
}
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, can you align the matching brackets?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed - the reference file is indented.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is github that is making the spacing look off then. Because the end bracket here on line 16 looks to my eyes unaligned with the corresponding open bracket on line 7?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh you meant the json not the xml output. sorry. Misread.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used a formatter this time.

[
{
"Guid": 3000,
"Counters": [40, 50]
}
]
]
},
{
"Guid": 18446744073709551612,
"Counters": [5, 9, 10]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see these counter values in the tested output

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

}
]
20 changes: 20 additions & 0 deletions llvm/test/tools/llvm-ctxprof-util/llvm-ctxprof-util-negative.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: not llvm-ctxprof-util nofile.json 2>&1 | FileCheck %s --check-prefix=NO_CMD
; RUN: not llvm-ctxprof-util fromJSON nofile.json 2>&1 | FileCheck %s --check-prefix=NO_FLAG
; RUN: not llvm-ctxprof-util fromJSON --input nofile.json 2>&1 | FileCheck %s --check-prefix=NO_FILE
; RUN: not llvm-ctxprof-util fromJSON --input %S/Inputs/bad.json 2>&1 | FileCheck %s --check-prefix=BAD_JSON
; RUN: not llvm-ctxprof-util fromJSON --input %S/Inputs/invalid-no-vector.json 2>&1 | FileCheck %s --check-prefix=NO_VECTOR
; RUN: not llvm-ctxprof-util fromJSON --input %S/Inputs/invalid-no-ctx.json 2>&1 | FileCheck %s --check-prefix=NO_CTX
; RUN: not llvm-ctxprof-util fromJSON --input %S/Inputs/invalid-no-counters.json 2>&1 | FileCheck %s --check-prefix=NO_COUNTERS
; RUN: not llvm-ctxprof-util fromJSON --input %S/Inputs/invalid-bad-subctx.json 2>&1 | FileCheck %s --check-prefix=BAD_SUBCTX
; RUN: rm -rf %t
; RUN: not llvm-ctxprof-util fromJSON --input %S/Inputs/valid.json --output %t/output.bitstream 2>&1 | FileCheck %s --check-prefix=NO_DIR

; NO_CMD: Unknown subcommand 'nofile.json'
; NO_FLAG: Unknown command line argument 'nofile.json'.
; NO_FILE: 'nofile.json': No such file or directory
; BAD_JSON: Expected object key
; NO_VECTOR: expected array
; NO_CTX: missing value at (root)[0].Guid
; NO_COUNTERS: missing value at (root)[0].Counters
; BAD_SUBCTX: expected array at (root)[0].Callsites[0]
; NO_DIR: failed to open output
39 changes: 39 additions & 0 deletions llvm/test/tools/llvm-ctxprof-util/llvm-ctxprof-util.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; RUN: mkdir -p %t
; RUN: llvm-ctxprof-util fromJSON --input %S/Inputs/empty.json -output %t/empty.bitstream
; RUN: llvm-bcanalyzer --dump %t/empty.bitstream | FileCheck %s --check-prefix=EMPTY

; RUN: llvm-ctxprof-util fromJSON --input %S/Inputs/valid.json -output %t/valid.bitstream
; RUN: llvm-bcanalyzer --dump %t/valid.bitstream | FileCheck %s --check-prefix=VALID

; EMPTY: <BLOCKINFO_BLOCK/>
; EMPTY-NEXT: <Metadata NumWords=1 BlockCodeSize=2>
; EMPTY-NEXT: <Version op0=1/>
; EMPTY-NEXT: </Metadata>

; Note that uin64_t are printed as signed values by llvm-bcanalyzer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo "uin64_t"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


; VALID: <BLOCKINFO_BLOCK/>
; VALID: <Context
; VALID-NEXT: <GUID op0=1000/>
; VALID-NEXT: <Counters op0=1 op1=2 op2=3/>
; VALID-NEXT: <Context

; We have no callee/context at index 0, 2 callsites for index 1, and one for
; index 2

; VALID-NEXT: <GUID op0=-3/>
; VALID-NEXT: <CalleeIndex op0=1/>
; VALID-NEXT: <Counters op0=6 op1=7 op2=8/>
; VALID: </Context>
; VALID-NEXT: <Context
; VALID-NEXT: <GUID op0=2000/>
; VALID-NEXT: <CalleeIndex op0=1/>
; VALID: </Context>
; VALID-NEXT: <Context
; VALID-NEXT: <GUID op0=3000/>
; VALID-NEXT: <CalleeIndex op0=2/>
; VALID-NEXT: <Counters op0=40 op1=50/>
; VALID-NEXT: </Context>
; VALID-NEXT: </Context>
; VALID-NEXT: <Context
; VALID-NEXT: <GUID op0=-4/>
1 change: 1 addition & 0 deletions llvm/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ add_llvm_tool_subdirectory(lto)
add_llvm_tool_subdirectory(gold)
add_llvm_tool_subdirectory(llvm-ar)
add_llvm_tool_subdirectory(llvm-config)
add_llvm_tool_subdirectory(llvm-ctxprof-util)
add_llvm_tool_subdirectory(llvm-lto)
add_llvm_tool_subdirectory(llvm-profdata)

Expand Down
14 changes: 14 additions & 0 deletions llvm/tools/llvm-ctxprof-util/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
set(LLVM_LINK_COMPONENTS
Core
Object
ProfileData
Support
)

add_llvm_tool(llvm-ctxprof-util
llvm-ctxprof-util.cpp

DEPENDS
intrinsics_gen
GENERATE_DRIVER
)
148 changes: 148 additions & 0 deletions llvm/tools/llvm-ctxprof-util/llvm-ctxprof-util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//===--- PGOCtxProfJSONReader.h - JSON format ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// JSON format for the contextual profile for testing.
///
//===----------------------------------------------------------------------===//

#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/ProfileData/CtxInstrContextNode.h"
#include "llvm/ProfileData/PGOCtxProfWriter.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

static cl::SubCommand FromJSON("fromJSON", "Convert from json");

static cl::opt<std::string> InputFilename(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in #89884 (comment) , cl:: is incompatible with GENERATE_DRIVER. Either remove GENERATE_DRIVER, or move this to Opt.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack, I'll take care of of it. Thanks.

"input", cl::value_desc("input"), cl::init("-"),
cl::desc(
"Input file. The format is an array of contexts.\n"
"Each context is a dictionary with the following keys:\n"
"'Guid', mandatory. The value is a 64-bit integer.\n"
"'Counters', mandatory. An array of 32-bit ints. These are the "
"counter values.\n"
"'Contexts', optional. An array containing arrays of contexts. The "
"context array at a position 'i' is the set of callees at that "
"callsite index. Use an empty array to indicate no callees."),
cl::sub(FromJSON));

static cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
cl::init("-"),
cl::desc("Output file"),
cl::sub(FromJSON));

namespace {
// A structural representation of the JSON input.
struct DeserializableCtx {
GlobalValue::GUID Guid = 0;
std::vector<uint64_t> Counters;
std::vector<std::vector<DeserializableCtx>> Callsites;
};

ctx_profile::ContextNode *
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
const std::vector<DeserializableCtx> &DCList);

// Convert a DeserializableCtx into a ContextNode, potentially linking it to
// its sibling (e.g. callee at same callsite) "Next".
ctx_profile::ContextNode *
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
const DeserializableCtx &DC,
ctx_profile::ContextNode *Next = nullptr) {
auto AllocSize = ctx_profile::ContextNode::getAllocSize(DC.Counters.size(),
DC.Callsites.size());
auto *Mem = Nodes.emplace_back(std::make_unique<char[]>(AllocSize)).get();
std::memset(Mem, 0, AllocSize);
auto *Ret = new (Mem) ctx_profile::ContextNode(DC.Guid, DC.Counters.size(),
DC.Callsites.size(), Next);
std::memcpy(Ret->counters(), DC.Counters.data(),
sizeof(uint64_t) * DC.Counters.size());
for (const auto &[I, DCList] : llvm::enumerate(DC.Callsites))
Ret->subContexts()[I] = createNode(Nodes, DCList);
return Ret;
}

// Convert a list of DeserializableCtx into a linked list of ContextNodes.
ctx_profile::ContextNode *
createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
const std::vector<DeserializableCtx> &DCList) {
ctx_profile::ContextNode *List = nullptr;
for (const auto &DC : DCList)
List = createNode(Nodes, DC, List);
return List;
}
} // namespace

namespace llvm {
namespace json {
// Hook into the JSON deserialization.
bool fromJSON(const Value &E, DeserializableCtx &R, Path P) {
json::ObjectMapper Mapper(E, P);
return Mapper && Mapper.map("Guid", R.Guid) &&
Mapper.map("Counters", R.Counters) &&
Mapper.mapOptional("Callsites", R.Callsites);
}
} // namespace json
} // namespace llvm

// Save the bitstream profile from the JSON representation.
Error convertFromJSON() {
auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFilename);
if (!BufOrError)
return createFileError(InputFilename, BufOrError.getError());
auto P = json::parse(BufOrError.get()->getBuffer());
if (!P)
return P.takeError();

std::vector<DeserializableCtx> DCList;
json::Path::Root R("");
if (!fromJSON(*P, DCList, R))
return R.getError();
// Nodes provides memory backing for the ContextualNodes.
std::vector<std::unique_ptr<char[]>> Nodes;
std::error_code EC;
raw_fd_stream Out(OutputFilename, EC);
if (EC)
return createStringError(EC, "failed to open output");
PGOCtxProfileWriter Writer(Out);
for (const auto &DC : DCList) {
auto *TopList = createNode(Nodes, DC);
if (!TopList)
return createStringError(
"Unexpected error converting internal structure to ctx profile");
Writer.write(*TopList);
}
if (EC)
return createStringError(EC, "failed to write output");
return Error::success();
}

int llvm_ctxprof_util_main(int argc, char **argv, const llvm::ToolContext &) {
cl::ParseCommandLineOptions(argc, argv, "LLVM Contextual Profile Utils\n");
ExitOnError ExitOnErr("llvm-ctxprof-util: ");
if (FromJSON) {
if (auto E = convertFromJSON()) {
handleAllErrors(std::move(E), [&](const ErrorInfoBase &E) {
E.log(errs());
errs() << "\n";
});
return 1;
}
return 0;
}
return 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want to emit an error if it isn't FromJSON

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the flag mechanism takes care of that, added a test though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably this should be llvm_unreachable then, or have an assert?

}