Files
async-profiler/test/native/perfEventsLinuxTest.cpp

290 lines
12 KiB
C++

/*
* Copyright The async-profiler authors
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef __linux__
#include "callTraceStorage.h"
#include "profiler.h"
#include "testRunner.hpp"
#include <dlfcn.h>
#include <stdio.h>
#define ASSERT_EVENT_TYPE(event_type, name_, type_, default_interval_, config_, config1_, config2_, counter_arg_) \
ASSERT_NE(event_type, NULL); \
CHECK_EQ(event_type->name, name_); \
CHECK_EQ(event_type->type, type_); \
CHECK_EQ(event_type->default_interval, default_interval_); \
CHECK_EQ(event_type->config, config_); \
CHECK_EQ(event_type->config1, config1_); \
CHECK_EQ(event_type->config2, config2_); \
CHECK_EQ(event_type->counter_arg, counter_arg_)
#define ASSERT_EVENT_TYPE_NONZERO_CONFIG(event_type, name_, type_, default_interval_) \
ASSERT_NE(event_type, NULL); \
CHECK_EQ(event_type->name, name_); \
CHECK_EQ(event_type->type, type_); \
CHECK_EQ(event_type->default_interval, default_interval_); \
CHECK_NE(event_type->config, 0); \
CHECK_EQ(event_type->config1, 0); \
CHECK_EQ(event_type->config2, 0); \
CHECK_EQ(event_type->counter_arg, 0)
#define ASSERT_BP(event_type, bp_type, address, bp_len, counter_arg) \
ASSERT_EVENT_TYPE(event_type, "mem:breakpoint", PERF_TYPE_BREAKPOINT, BKPT_INTERVAL, bp_type, address, bp_len, counter_arg)
#define ASSERT_RAW(event_type, name, config) ASSERT_EVENT_TYPE(event_type, name, PERF_TYPE_RAW, 1000, config, 0, 0, 0)
#define ASSERT_PROBE(event_type, name_, type_, default_interval_, config_, probeName, config2_, counter_arg_) \
ASSERT_NE(event_type, NULL); \
CHECK_EQ(event_type->name, name_); \
CHECK_NE(type_, 0); \
CHECK_EQ(event_type->default_interval, default_interval_); \
CHECK_EQ(event_type->config, config_); \
CHECK_EQ(((const char*)event_type->config1), probeName); \
CHECK_EQ(event_type->config2, config2_); \
CHECK_EQ(event_type->counter_arg, counter_arg_)
TEST_CASE(ForName_Predefined_cpu) {
PerfEventType* event_type = PerfEventType::forName("cpu");
ASSERT_EVENT_TYPE(event_type, "cpu-clock", PERF_TYPE_SOFTWARE, DEFAULT_INTERVAL, PERF_COUNT_SW_CPU_CLOCK, 0, 0, 0);
}
TEST_CASE(ForName_Predefined_cpu_clock) {
PerfEventType* event_type = PerfEventType::forName("cpu-clock");
ASSERT_EVENT_TYPE(event_type, "cpu-clock", PERF_TYPE_SOFTWARE, DEFAULT_INTERVAL, PERF_COUNT_SW_CPU_CLOCK, 0, 0, 0);
}
TEST_CASE(ForName_Invalid_space) {
PerfEventType* event_type = PerfEventType::forName(" ");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_Invalid_Zero) {
PerfEventType* event_type = PerfEventType::forName("mem:0");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_Invalid) {
PerfEventType* event_type = PerfEventType::forName("mem:foo_unknownSymbol");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_InvalidColon2) {
PerfEventType* event_type = PerfEventType::forName("mem::");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_InvalidColon) {
PerfEventType* event_type = PerfEventType::forName("mem:");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_HexAddr) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123");
ASSERT_BP(event_type, HW_BREAKPOINT_RW, 0x123, 1, 0);
}
TEST_CASE(ForName_Breakpoint_DecAddr) {
PerfEventType* event_type = PerfEventType::forName("mem:123");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_Addr_DecOffset) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+22000");
ASSERT_BP(event_type, HW_BREAKPOINT_RW, 22291, 1, 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000");
ASSERT_BP(event_type, HW_BREAKPOINT_RW, 0x22123, 1, 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_DecLen) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/8");
ASSERT_BP(event_type, HW_BREAKPOINT_RW, 0x22123, 8, 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/0x8");
ASSERT_BP(event_type, HW_BREAKPOINT_RW, 0x22123, 0x8, 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_R) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/0x8:r");
ASSERT_BP(event_type, HW_BREAKPOINT_R, 0x22123, 0x8, 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_W) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/0x8:w");
ASSERT_BP(event_type, HW_BREAKPOINT_W, 0x22123, 0x8, 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_X) {
char name[50];
snprintf(name, sizeof(name), "mem:0x123+0x22000/0x%zx:x", sizeof(long));
PerfEventType* event_type = PerfEventType::forName(name);
ASSERT_BP(event_type, HW_BREAKPOINT_X, 0x22123, sizeof(long), 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_InvalidDefaultRW) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/0x8:i");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_X_Arg) {
char name[50];
snprintf(name, sizeof(name), "mem:0x123+0x22000/0x%zx:x{3}", sizeof(long));
PerfEventType* event_type = PerfEventType::forName(name);
ASSERT_BP(event_type, HW_BREAKPOINT_X, 0x22123, sizeof(long), 3);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_RW) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/0x8:rw");
ASSERT_BP(event_type, HW_BREAKPOINT_RW, 0x22123, 0x8, 0);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_RX) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/0x8:rx");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_WX) {
PerfEventType* event_type = PerfEventType::forName("mem:0x123+0x22000/0x8:wx");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Breakpoint_Addr_HexOffset_HexLen_X_Known) {
char name[50];
snprintf(name, sizeof(name), "mem:mmap+0x22000/0x%zx:x", sizeof(long));
PerfEventType* event_type = PerfEventType::forName(name);
const __u64 mmap_addr = (__u64)(uintptr_t)dlsym(RTLD_DEFAULT, "mmap");
ASSERT_NE(mmap_addr, 0);
ASSERT_BP(event_type, HW_BREAKPOINT_X, mmap_addr + 0x22000, sizeof(long), 2);
}
TEST_CASE(ForName_Breakpoint_Symbol) {
PerfEventType* event_type = PerfEventType::forName("mem:strcmp");
const __u64 strcmp_addr = (__u64)(uintptr_t)dlsym(RTLD_DEFAULT, "strcmp");
ASSERT_NE(strcmp_addr, 0);
ASSERT_BP(event_type, HW_BREAKPOINT_RW, strcmp_addr, 1, 0);
}
TEST_CASE(ForName_Tracepoint_Invalid) {
PerfEventType* event_type = PerfEventType::forName("trace:foo");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_Tracepoint_Id) {
PerfEventType* event_type = PerfEventType::forName("trace:123");
ASSERT_EVENT_TYPE(event_type, "trace:tracepoint", PERF_TYPE_TRACEPOINT, 1, 123, 0, 0, 0);
}
TEST_CASE(ForName_Tracepoint_Zero) {
PerfEventType* event_type = PerfEventType::forName("trace:0");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_kprobe_Invalid) {
PerfEventType* event_type = PerfEventType::forName("kprobe:");
ASSERT_EQ(event_type, NULL);
}
TEST_CASE(ForName_kprobe, fileReadable("/sys/bus/event_source/devices/kprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("kprobe:foo");
ASSERT_PROBE(event_type, "kprobe:func", 6, 1, 0, "foo", 0, 0);
}
TEST_CASE(ForName_kprobe_offset, fileReadable("/sys/bus/event_source/devices/kprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("kprobe:foo+99");
ASSERT_PROBE(event_type, "kprobe:func", 6, 1, 0, "foo", 99, 0);
}
TEST_CASE(ForName_uprobe, fileReadable("/sys/bus/event_source/devices/uprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("uprobe:foo");
ASSERT_PROBE(event_type, "uprobe:path", 7, 1, 0, "foo", 0, 0);
}
TEST_CASE(ForName_uprobe_offset, fileReadable("/sys/bus/event_source/devices/uprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("uprobe:foo+0x99");
ASSERT_PROBE(event_type, "uprobe:path", 7, 1, 0, "foo", 0x99, 0);
}
TEST_CASE(ForName_kretprobe, fileReadable("/sys/bus/event_source/devices/kprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("kretprobe:foo");
ASSERT_PROBE(event_type, "kprobe:func", 6, 1, 1, "foo", 0, 0);
}
TEST_CASE(ForName_kretprobe_offset, fileReadable("/sys/bus/event_source/devices/kprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("kretprobe:foo+-10");
ASSERT_PROBE(event_type, "kprobe:func", 6, 1, 1, "foo", -10, 0);
}
TEST_CASE(ForName_uretprobe, fileReadable("/sys/bus/event_source/devices/uprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("uretprobe:foo");
ASSERT_PROBE(event_type, "uprobe:path", 7, 1, 1, "foo", 0, 0);
}
TEST_CASE(ForName_uretprobe_offset, fileReadable("/sys/bus/event_source/devices/uprobe/type")) {
PerfEventType* event_type = PerfEventType::forName("uretprobe:foo+066");
ASSERT_PROBE(event_type, "uprobe:path", 7, 1, 1, "foo", 54, 0);
}
TEST_CASE(ForName_raw_pmu_0) {
PerfEventType* event_type = PerfEventType::forName("r0");
ASSERT_RAW(event_type, "rNNN", 0);
}
TEST_CASE(ForName_raw_pmu_33) {
PerfEventType* event_type = PerfEventType::forName("r33");
ASSERT_RAW(event_type, "rNNN", 0x33);
}
TEST_CASE(ForName_raw_pmu_033) {
PerfEventType* event_type = PerfEventType::forName("r033");
ASSERT_RAW(event_type, "rNNN", 0x33);
}
TEST_CASE(ForName_raw_pmu_u64) {
PerfEventType* event_type = PerfEventType::forName("rF00FFFFF0123999");
ASSERT_RAW(event_type, "rNNN", 0xF00FFFFF0123999);
}
TEST_CASE(ForName_symbol) {
PerfEventType* event_type = PerfEventType::forName("strcmp");
const __u64 strcmp_addr = (__u64)(uintptr_t)dlsym(RTLD_DEFAULT, "strcmp");
ASSERT_NE(strcmp_addr, 0);
ASSERT_BP(event_type, HW_BREAKPOINT_X, strcmp_addr, sizeof(long), 0);
}
TEST_CASE(ForName_symbol_private) {
Profiler::instance()->updateSymbols(false);
PerfEventType* event_type = PerfEventType::forName("asprof_execute");
const __u64 addr = (__u64)(uintptr_t)asprof_execute;
ASSERT_BP(event_type, HW_BREAKPOINT_X, addr, sizeof(long), 0);
const __u64 dyn_addr = (__u64)(uintptr_t)dlsym(RTLD_DEFAULT, "asprof_execute");
// This symbol is not a dynamic symbol.
ASSERT_EQ(dyn_addr, 0);
}
TEST_CASE(ForName_pmu_descriptor, fileReadable("/sys/bus/event_source/devices/cpu/events/cache-misses")) {
PerfEventType* event_type = PerfEventType::forName("cpu/cache-misses/");
ASSERT_EVENT_TYPE_NONZERO_CONFIG(event_type, "pmu/event-descriptor/", PERF_TYPE_RAW, 1000);
}
TEST_CASE(ForName_kernel_tracepoint, fileReadable("/sys/kernel/tracing/events/oom/mark_victim/id") ||
fileReadable("/sys/kernel/debug/tracing/events/oom/mark_victim/id")) {
PerfEventType* event_type = PerfEventType::forName("oom:mark_victim");
ASSERT_EVENT_TYPE_NONZERO_CONFIG(event_type, "trace:tracepoint", PERF_TYPE_TRACEPOINT, 1);
}
#endif // __linux__