#1585: Scale perf counter in case of multiplexing (#1631)

This commit is contained in:
Vishal Chand
2026-01-23 18:13:03 +00:00
committed by GitHub
parent a071e8a2f8
commit dc88d3f756

View File

@@ -58,6 +58,23 @@ enum {
HW_BREAKPOINT_X = 4
};
struct PerfCounter {
u64 value;
u64 time_enabled; /* PERF_FORMAT_TOTAL_TIME_ENABLED */
u64 time_running; /* PERF_FORMAT_TOTAL_TIME_RUNNING */
};
// Per-FD struct for storing perf-event multiplexing data
struct MultiplexState {
u64 time_enabled; /* stores previous time_enabled */
u64 time_running; /* stores previous time_running */
};
static const unsigned int MAX_MULTIPLEXED_FD = 65536;
static MultiplexState multiplex_state[MAX_MULTIPLEXED_FD];
static bool multiplex_state_dirty = false;
static int fetchInt(const char* file_name) {
int fd = open(file_name, O_RDONLY);
if (fd == -1) {
@@ -587,6 +604,9 @@ int PerfEvents::createForThread(int tid) {
attr.disabled = 1;
attr.wakeup_events = 1;
// flags for multiplexing support
attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
if (_alluser) {
attr.exclude_kernel = 1;
}
@@ -648,6 +668,11 @@ int PerfEvents::createForThread(int tid) {
_events[tid]._fd = fd;
_events[tid]._page = (struct perf_event_mmap_page*)page;
if (multiplex_state_dirty && fd < MAX_MULTIPLEXED_FD) {
multiplex_state[fd].time_enabled = 0;
multiplex_state[fd].time_running = 0;
}
struct f_owner_ex ex;
ex.type = F_OWNER_TID;
ex.pid = tid;
@@ -700,8 +725,36 @@ u64 PerfEvents::readCounter(siginfo_t* siginfo, void* ucontext) {
case 3: return StackFrame(ucontext).arg2();
case 4: return StackFrame(ucontext).arg3();
default: {
u64 counter;
return read(siginfo->si_fd, &counter, sizeof(counter)) == sizeof(counter) ? counter : 1;
// Read counter with multiplexing metadata for accurate scaling
struct PerfCounter counter;
if (read(siginfo->si_fd, &counter, sizeof(counter)) == sizeof(counter)) {
u64 current_val = counter.value;
if (counter.time_enabled > counter.time_running) {
int fd = siginfo->si_fd;
if (fd < MAX_MULTIPLEXED_FD) {
u64 delta_enabled = counter.time_enabled - multiplex_state[fd].time_enabled;
u64 delta_running = counter.time_running - multiplex_state[fd].time_running;
multiplex_state[fd].time_enabled = counter.time_enabled;
multiplex_state[fd].time_running = counter.time_running;
if (!multiplex_state_dirty) {
multiplex_state_dirty = true;
}
if (delta_running > 0 && delta_enabled > delta_running) {
// scaled counter = (counter) * (delta_enabled / delta_running)
double ratio = (double)delta_enabled / delta_running;
return (u64)(current_val * ratio);
}
} else if (counter.time_running > 0) {
double ratio = (double)counter.time_enabled / counter.time_running;
return (u64)(current_val * ratio);
}
}
return current_val;
}
return 1;
}
}
}