-
Notifications
You must be signed in to change notification settings - Fork 16k
[ctx_prof] test tool: generate ctxprof bistream from json #100379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
5f7ff32
6400f05
b26498e
fa68caa
796ff2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 @@ | ||
| [] |
| 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 @@ | ||
| {} |
| 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] | ||
| }, | ||
| { | ||
| "Guid": 18446744073709551613, | ||
| "Counters": [6, 7, 8] | ||
| } | ||
| ], | ||
|
||
| [ | ||
| { | ||
| "Guid": 3000, | ||
| "Counters": [40, 50] | ||
| } | ||
| ] | ||
| ] | ||
| }, | ||
| { | ||
| "Guid": 18446744073709551612, | ||
| "Counters": [5, 9, 10] | ||
|
||
| } | ||
| ] | ||
| 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 |
| 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 | ||
|
||
|
|
||
| ; 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/> | ||
| 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 | ||
| ) |
| 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( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
||
| } | ||
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.