Skip to content

[ctx_profile] Integration test #92456

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

Merged
merged 5 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
9 changes: 9 additions & 0 deletions compiler-rt/lib/ctx_profile/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,12 @@ append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ EXTRA_FLAGS)
if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()

add_compiler_rt_runtime(clang_rt.ctx_profile
STATIC
ARCHS ${CTX_PROFILE_SUPPORTED_ARCH}
OBJECT_LIBS RTSanitizerCommon RTSanitizerCommonLibc
CFLAGS ${EXTRA_FLAGS}
SOURCES ${CTX_PROFILE_SOURCES}
ADDITIONAL_HEADERS ${CTX_PROFILE_HEADERS}
PARENT_TARGET ctx_profile)
103 changes: 103 additions & 0 deletions compiler-rt/test/ctx_profile/TestCases/generate-context.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Simple integration test for contextual instrumentation
//
// Copy the header defining ContextNode.
// RUN: mkdir -p %t_include
// RUN: cp %llvm_src/include/llvm/ProfileData/CtxInstrContextNode.h %t_include/
//
// Compile with ctx instrumentation "on". We treat "theRoot" as callgraph root.
// RUN: %clangxx %s -lclang_rt.ctx_profile -I%t_include -O2 -o %t.bin -mllvm -profile-context-root=theRoot
//
// Run the binary, and observe the profile fetch handler's output.
// RUN: %t.bin | FileCheck %s

#include "CtxInstrContextNode.h"
#include <cstdio>
#include <iostream>

using namespace llvm::ctx_profile;
extern "C" bool __llvm_ctx_profile_fetch(void *Data,
bool (*Writer)(void *,
const ContextNode &));

// avoid name mangling
extern "C" {
__attribute__((noinline)) void someFunction(int I) {
if (I % 2)
printf("check odd\n");
else
printf("check even\n");
}

// block inlining because the pre-inliner otherwise will inline this - it's
// too small.
__attribute__((noinline)) void theRoot() {
printf("check 1\n");
someFunction(1);
#pragma nounroll
for (auto I = 0; I < 2; ++I) {
someFunction(I);
}
}
}

// Make sure the program actually ran correctly.
// CHECK: check 1
// CHECK-NEXT: check odd
// CHECK-NEXT: check even
// CHECK-NEXT: check odd

void printProfile(const ContextNode &Node, const std::string &Indent,
const std::string &Increment) {
std::cout << Indent << "Guid: " << Node.guid() << std::endl;
std::cout << Indent << "Entries: " << Node.entrycount() << std::endl;
std::cout << Indent << Node.counters_size() << " counters and "
<< Node.callsites_size() << " callsites" << std::endl;
std::cout << Indent << "Counter values: ";
for (uint32_t I = 0U; I < Node.counters_size(); ++I)
std::cout << Node.counters()[I] << " ";
std::cout << std::endl;
for (uint32_t I = 0U; I < Node.callsites_size(); ++I)
for (const auto *N = Node.subContexts()[I]; N; N = N->next()) {
std::cout << Indent << "At Index " << I << ":" << std::endl;
printProfile(*N, Indent + Increment, Increment);
}
}

// 8657661246551306189 is theRoot. We expect 2 callsites and 2 counters - one
// for the entry basic block and one for the loop.
// 6759619411192316602 is someFunction. We expect all context instances to show
// the same nr of counters and callsites, but the counters will be different.
// The first context is for the first callsite with theRoot as parent, and the
// second counter in someFunction will be 0 (we pass an odd nr, and the other
// path gets instrumented).
// The second context is in the loop. We expect 2 entries and each of the
// branches would be taken once, so the second counter is 1.
// CHECK-NEXT: Guid: 8657661246551306189
// CHECK-NEXT: Entries: 1
// CHECK-NEXT: 2 counters and 3 callsites
// CHECK-NEXT: Counter values: 1 2
// CHECK-NEXT: At Index 1:
// CHECK-NEXT: Guid: 6759619411192316602
// CHECK-NEXT: Entries: 1
// CHECK-NEXT: 2 counters and 2 callsites
// CHECK-NEXT: Counter values: 1 0
// CHECK-NEXT: At Index 2:
// CHECK-NEXT: Guid: 6759619411192316602
// CHECK-NEXT: Entries: 2
// CHECK-NEXT: 2 counters and 2 callsites
// CHECK-NEXT: Counter values: 2 1

bool profileWriter() {
return __llvm_ctx_profile_fetch(
nullptr, +[](void *, const ContextNode &Node) {
printProfile(Node, "", " ");
return true;
});
}

int main(int argc, char **argv) {
theRoot();
// This would be implemented in a specific RPC handler, but here we just call
// it directly.
return !profileWriter();
}
4 changes: 4 additions & 0 deletions compiler-rt/test/ctx_profile/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ def get_required_attr(config, attr_name):
config.test_source_root = os.path.dirname(__file__)
# Default test suffixes.
config.suffixes = [".c", ".cpp", ".test"]

config.substitutions.append(
("%clangxx ", " ".join([config.clang] + config.cxx_mode_flags) + " ")
)
Loading