mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
100 lines
3.3 KiB
C
100 lines
3.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
#ifndef DROIDDECK_PROOT_PROFILE_H
|
|
#define DROIDDECK_PROOT_PROFILE_H
|
|
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
struct dd_profile_counter {
|
|
uint64_t calls, wall_ns, cpu_ns, max_ns;
|
|
};
|
|
static struct dd_profile_counter dd_profile_counts[PR_NB_SYSNUM][2];
|
|
static int dd_profile_on = -1;
|
|
static uint64_t dd_profile_id, dd_profile_next, dd_profile_slow_ns = 1000000;
|
|
static unsigned dd_profile_samples;
|
|
|
|
static uint64_t dd_profile_clock(clockid_t clock)
|
|
{
|
|
struct timespec ts;
|
|
if (clock_gettime(clock, &ts) != 0) return 0;
|
|
return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
|
|
}
|
|
|
|
static void dd_profile_flush(void)
|
|
{
|
|
int saved = errno;
|
|
for (unsigned nr = 0; nr < PR_NB_SYSNUM; nr++) {
|
|
for (unsigned stage = 0; stage < 2; stage++) {
|
|
const struct dd_profile_counter *c = &dd_profile_counts[nr][stage];
|
|
if (!c->calls) continue;
|
|
fprintf(stderr, "proot-profile {\"type\":\"total\",\"tracer\":%d,\"id\":%" PRIu64
|
|
",\"syscall\":\"%s\",\"stage\":\"%s\",\"calls\":%" PRIu64
|
|
",\"wall_ns\":%" PRIu64 ",\"cpu_ns\":%" PRIu64 ",\"max_ns\":%" PRIu64 "}\n",
|
|
getpid(), dd_profile_id, stringify_sysnum(nr), stage ? "exit" : "enter",
|
|
c->calls, c->wall_ns, c->cpu_ns, c->max_ns);
|
|
}
|
|
}
|
|
errno = saved;
|
|
}
|
|
|
|
static int dd_profile_enabled(void)
|
|
{
|
|
if (dd_profile_on >= 0) return dd_profile_on;
|
|
int saved = errno;
|
|
const char *value = getenv("PROOT_PROFILE");
|
|
dd_profile_on = value && strcmp(value, "1") == 0;
|
|
if (dd_profile_on) {
|
|
value = getenv("PROOT_PROFILE_SLOW_US");
|
|
if (value && *value) {
|
|
char *end;
|
|
unsigned long long us = strtoull(value, &end, 10);
|
|
if (!*end && us > 0 && us <= 1000000000ULL) dd_profile_slow_ns = us * 1000;
|
|
}
|
|
dd_profile_id = dd_profile_clock(CLOCK_MONOTONIC);
|
|
dd_profile_next = dd_profile_id + 5000000000ULL;
|
|
atexit(dd_profile_flush);
|
|
fprintf(stderr, "proot-profile {\"type\":\"start\",\"tracer\":%d,\"id\":%" PRIu64
|
|
",\"slow_ns\":%" PRIu64 ",\"sample_limit\":32,\"sample_window_ms\":5000,\"scope\":\"syscall-handler\"}\n",
|
|
getpid(), dd_profile_id, dd_profile_slow_ns);
|
|
}
|
|
errno = saved;
|
|
return dd_profile_on;
|
|
}
|
|
|
|
static void dd_profile_record(unsigned nr, int entering, pid_t pid,
|
|
uint64_t start_wall, uint64_t start_cpu)
|
|
{
|
|
int saved = errno;
|
|
uint64_t cpu = dd_profile_clock(CLOCK_THREAD_CPUTIME_ID);
|
|
uint64_t wall = dd_profile_clock(CLOCK_MONOTONIC);
|
|
if (nr >= PR_NB_SYSNUM) nr = PR_void;
|
|
if (!start_wall || !start_cpu || wall < start_wall || cpu < start_cpu) goto done;
|
|
uint64_t elapsed = wall - start_wall, used = cpu - start_cpu;
|
|
struct dd_profile_counter *c = &dd_profile_counts[nr][!entering];
|
|
c->calls++;
|
|
c->wall_ns += elapsed;
|
|
c->cpu_ns += used;
|
|
if (elapsed > c->max_ns) c->max_ns = elapsed;
|
|
if (wall >= dd_profile_next) {
|
|
dd_profile_flush();
|
|
dd_profile_next = wall + 5000000000ULL;
|
|
dd_profile_samples = 0;
|
|
}
|
|
if (elapsed >= dd_profile_slow_ns && dd_profile_samples < 32) {
|
|
dd_profile_samples++;
|
|
fprintf(stderr, "proot-profile {\"type\":\"slow\",\"tracer\":%d,\"id\":%" PRIu64
|
|
",\"pid\":%d,\"syscall\":\"%s\",\"stage\":\"%s\",\"wall_ns\":%" PRIu64
|
|
",\"cpu_ns\":%" PRIu64 "}\n", getpid(), dd_profile_id, pid,
|
|
stringify_sysnum(nr), entering ? "enter" : "exit", elapsed, used);
|
|
}
|
|
done:
|
|
errno = saved;
|
|
}
|
|
#endif
|