Created
January 17, 2021 11:35
-
-
Save foxhoundsk/8b25a5a0e7a0f57b2a0e0d8a19efda14 to your computer and use it in GitHub Desktop.
syscall overhead measurement
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bpf.h> | |
#include <bpf_helpers.h> | |
#include <bpf_endian.h> | |
#include <stddef.h> | |
#include <string.h> | |
#include <asm/ptrace.h> | |
struct map { | |
__u64 ts; | |
}; | |
SEC("getuid") | |
int kp_sys_batch(struct pt_regs *ctx) | |
{ | |
__u32 i = 0; | |
struct map *r; | |
r = bpf_map_lookup_elem(&reals, &i); | |
if (!r) | |
return 1; | |
r->ts = bpf_ktime_get_ns(); | |
return 0; | |
} | |
char _license[] SEC("license") = "GPL"; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <unistd.h> | |
#include <asm/unistd.h> | |
#include <time.h> | |
#define TEST_CNT 1000000 | |
int main(int argc, char **argv) | |
{ | |
struct timespec tp, t1; | |
uint64_t delta = 0; | |
/* warm up */ | |
for (int i = 0; i < TEST_CNT; i++) { | |
clock_gettime(CLOCK_MONOTONIC, &t1); | |
syscall(__NR_getuid); /* dummy call */ | |
clock_gettime(CLOCK_MONOTONIC, &tp); | |
} | |
for (int i = 0; i < TEST_CNT; i++) { | |
clock_gettime(CLOCK_MONOTONIC, &t1); | |
syscall(__NR_getuid); /* dummy call */ | |
clock_gettime(CLOCK_MONOTONIC, &tp); | |
delta += (1000000000 * tp.tv_sec + tp.tv_nsec) - (1000000000 * t1.tv_sec + t1.tv_nsec); | |
} | |
printf("avg: %fns\n", (double) delta / TEST_CNT); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <unistd.h> | |
#include <asm/unistd.h> | |
#include <time.h> | |
#include <linux/perf_event.h> | |
#include <linux/hw_breakpoint.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <sys/ioctl.h> | |
#define likely(x) __builtin_expect((x),1) | |
#define unlikely(x) __builtin_expect((x),0) | |
#define TEST_CNT 1000000 | |
#define BPF_FILE_NAME "mkern.o" | |
#define BPF_MAP_NAME "msys" | |
struct map { | |
__u64 ts; | |
}; | |
static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid, | |
int cpu, int group_fd, | |
unsigned long flags) | |
{ | |
attr->size = sizeof(*attr); | |
return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); | |
} | |
static int attach_kprobe(int prog_fd) | |
{ | |
int err, fd, id; | |
char buf[32]; | |
struct perf_event_attr attr = {}; | |
err = system("echo 'p:kp_sys_batch sys_batch' > /sys/kernel/debug/tracing/kprobe_events"); | |
if (err < 0) { | |
fprintf(stderr, "Failed to create kprobe, error '%s'\n", strerror(errno)); | |
return -1; | |
} | |
fd = open("/sys/kernel/debug/tracing/events/kprobes/kp_sys_batch/id", O_RDONLY, 0); | |
if (fd < 0) { | |
fprintf(stderr, "Failed to open event %s\n", "sys_batch"); | |
return -1; | |
} | |
err = read(fd, buf, sizeof(buf)); | |
if (err < 0 || err >= sizeof(buf)) { | |
fprintf(stderr, "read from '%s' failed '%s'\n", "sys_batch", strerror(errno)); | |
return -1; | |
} | |
close(fd); | |
buf[err] = 0; | |
id = atoi(buf); | |
attr.config = id; | |
attr.type = PERF_TYPE_TRACEPOINT; | |
attr.sample_type = PERF_SAMPLE_RAW; | |
attr.sample_period = 1; | |
attr.wakeup_events = 1; | |
fd = sys_perf_event_open(&attr, 0/*this process*/, -1/*any cpu*/, -1/*group leader*/, 0); | |
if (fd < 0) { | |
perror("sys_perf_event_open"); | |
fprintf(stderr, "Failed to open perf_event (id: %llu)\n", attr.config); | |
return -1; | |
} | |
err = ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); | |
if (err < 0) { | |
fprintf(stderr, "ioctl PERF_EVENT_IOC_ENABLE failed err %s\n", | |
strerror(errno)); | |
return -1; | |
} | |
err = ioctl(fd, PERF_EVENT_IOC_SET_BPF, prog_fd); | |
if (err < 0) { | |
fprintf(stderr, "ioctl PERF_EVENT_IOC_SET_BPF failed: %s\n", | |
strerror(errno)); | |
return -1; | |
} | |
return 0; | |
} | |
static void maxi_memlock_rlimit(void) | |
{ | |
struct rlimit rlim_new = { | |
.rlim_cur = RLIM_INFINITY, | |
.rlim_max = RLIM_INFINITY, | |
}; | |
if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { | |
fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n"); | |
exit(-1); | |
} | |
} | |
static int find_map_fd(struct bpf_object *bpf_obj, const char *mapname) | |
{ | |
struct bpf_map *map; | |
int map_fd = -1; | |
map = bpf_object__find_map_by_name(bpf_obj, mapname); | |
if (!map) { | |
fprintf(stderr, "Failed finding map by name: %s\n", mapname); | |
exit(-1); | |
} | |
map_fd = bpf_map__fd(map); | |
return map_fd; | |
} | |
int main(int argc, char **argv) | |
{ | |
int bpf_map_fd; | |
int bpf_prog_fd = -1; | |
int err; | |
int key = 0; | |
struct timespec tp; | |
struct bpf_object *bpf_obj; | |
struct map map; | |
struct bpf_prog_load_attr xattr = { | |
.prog_type = BPF_PROG_TYPE_KPROBE, | |
.file = BPF_FILE_NAME, | |
}; | |
maxi_memlock_rlimit(); | |
err = bpf_prog_load_xattr(&xattr, &bpf_obj, &bpf_prog_fd); | |
if (err) { | |
fprintf(stderr, "Failed loading bpf object file\n"); | |
exit(-1); | |
} | |
if (attach_kprobe(bpf_prog_fd)) { | |
fprintf(stderr, "Failed attaching kprobe\n"); | |
exit(-1); | |
} | |
bpf_map_fd = find_map_fd(bpf_obj, BPF_MAP_NAME); | |
if (find_map_fd < 0) { | |
fprintf(stderr, "Failed finding map fd\n"); | |
exit(-1); | |
} | |
/* warm up */ | |
for (int i = 0; likely(i < TEST_CNT); i++) { | |
//syscall(__NR_afs_syscall, 0, 0, 0, 0, 0); /* dummy call */ | |
syscall(__NR_getuid); /* dummy call */ | |
clock_gettime(CLOCK_MONOTONIC, &tp); | |
if (unlikely(bpf_map_lookup_elem(bpf_map_fd, &key, &map))) { | |
fprintf(stderr, "Failed to lookup map element\n"); | |
perror("lookup"); | |
exit(-1); | |
} | |
} | |
uint64_t delta = 0; | |
for (int i = 0; i < TEST_CNT; i++) { | |
clock_gettime(CLOCK_MONOTONIC, &tp); | |
syscall(__NR_getuid); /* dummy call */ | |
if (unlikely(bpf_map_lookup_elem(bpf_map_fd, &key, &map))) { | |
fprintf(stderr, "Failed to lookup map element\n"); | |
perror("lookup"); | |
exit(-1); | |
} | |
delta += map.ts - (1000000000 * tp.tv_sec + tp.tv_nsec); | |
} | |
printf("avg: %fns\n", (double) delta / TEST_CNT); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <unistd.h> | |
#include <asm/unistd.h> | |
#include <time.h> | |
#include <linux/perf_event.h> | |
#include <linux/hw_breakpoint.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <sys/ioctl.h> | |
#define likely(x) __builtin_expect((x),1) | |
#define unlikely(x) __builtin_expect((x),0) | |
#define TEST_CNT 1000000 | |
#define BPF_FILE_NAME "mkern.o" | |
#define BPF_MAP_NAME "msys" | |
struct map { | |
__u64 ts; | |
}; | |
static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid, | |
int cpu, int group_fd, | |
unsigned long flags) | |
{ | |
attr->size = sizeof(*attr); | |
return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); | |
} | |
static int attach_kprobe(int prog_fd) | |
{ | |
int err, fd, id; | |
char buf[32]; | |
struct perf_event_attr attr = {}; | |
err = system("echo 'r:kp_sys_batch __x64_sys_getuid' > /sys/kernel/debug/tracing/kprobe_events"); | |
if (err < 0) { | |
fprintf(stderr, "Failed to create kprobe, error '%s'\n", strerror(errno)); | |
return -1; | |
} | |
fd = open("/sys/kernel/debug/tracing/events/kprobes/kp_sys_batch/id", O_RDONLY, 0); | |
if (fd < 0) { | |
fprintf(stderr, "Failed to open event %s\n", "sys_batch"); | |
return -1; | |
} | |
err = read(fd, buf, sizeof(buf)); | |
if (err < 0 || err >= sizeof(buf)) { | |
fprintf(stderr, "read from '%s' failed '%s'\n", "sys_batch", strerror(errno)); | |
return -1; | |
} | |
close(fd); | |
buf[err] = 0; | |
id = atoi(buf); | |
attr.config = id; | |
attr.type = PERF_TYPE_TRACEPOINT; | |
attr.sample_type = PERF_SAMPLE_RAW; | |
attr.sample_period = 1; | |
attr.wakeup_events = 1; | |
fd = sys_perf_event_open(&attr, 0/*this process*/, -1/*any cpu*/, -1/*group leader*/, 0); | |
if (fd < 0) { | |
perror("sys_perf_event_open"); | |
fprintf(stderr, "Failed to open perf_event (id: %llu)\n", attr.config); | |
return -1; | |
} | |
err = ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); | |
if (err < 0) { | |
fprintf(stderr, "ioctl PERF_EVENT_IOC_ENABLE failed err %s\n", | |
strerror(errno)); | |
return -1; | |
} | |
err = ioctl(fd, PERF_EVENT_IOC_SET_BPF, prog_fd); | |
if (err < 0) { | |
fprintf(stderr, "ioctl PERF_EVENT_IOC_SET_BPF failed: %s\n", | |
strerror(errno)); | |
return -1; | |
} | |
return 0; | |
} | |
static void maxi_memlock_rlimit(void) | |
{ | |
struct rlimit rlim_new = { | |
.rlim_cur = RLIM_INFINITY, | |
.rlim_max = RLIM_INFINITY, | |
}; | |
if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { | |
fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n"); | |
exit(-1); | |
} | |
} | |
static int find_map_fd(struct bpf_object *bpf_obj, const char *mapname) | |
{ | |
struct bpf_map *map; | |
int map_fd = -1; | |
map = bpf_object__find_map_by_name(bpf_obj, mapname); | |
if (!map) { | |
fprintf(stderr, "Failed finding map by name: %s\n", mapname); | |
exit(-1); | |
} | |
map_fd = bpf_map__fd(map); | |
return map_fd; | |
} | |
int main(int argc, char **argv) | |
{ | |
int bpf_map_fd; | |
int bpf_prog_fd = -1; | |
int err; | |
int key = 0; | |
struct timespec tp; | |
struct bpf_object *bpf_obj; | |
struct map map; | |
struct bpf_prog_load_attr xattr = { | |
.prog_type = BPF_PROG_TYPE_KPROBE, | |
.file = BPF_FILE_NAME, | |
}; | |
maxi_memlock_rlimit(); | |
err = bpf_prog_load_xattr(&xattr, &bpf_obj, &bpf_prog_fd); | |
if (err) { | |
fprintf(stderr, "Failed loading bpf object file\n"); | |
exit(-1); | |
} | |
if (attach_kprobe(bpf_prog_fd)) { | |
fprintf(stderr, "Failed attaching kprobe\n"); | |
exit(-1); | |
} | |
bpf_map_fd = find_map_fd(bpf_obj, BPF_MAP_NAME); | |
if (find_map_fd < 0) { | |
fprintf(stderr, "Failed finding map fd\n"); | |
exit(-1); | |
} | |
/* warm up */ | |
for (int i = 0; likely(i < TEST_CNT); i++) { | |
//syscall(__NR_afs_syscall, 0, 0, 0, 0, 0); /* dummy call */ | |
syscall(__NR_getuid); /* dummy call */ | |
clock_gettime(CLOCK_MONOTONIC, &tp); | |
if (unlikely(bpf_map_lookup_elem(bpf_map_fd, &key, &map))) { | |
fprintf(stderr, "Failed to lookup map element\n"); | |
perror("lookup"); | |
exit(-1); | |
} | |
} | |
uint64_t delta = 0; | |
for (int i = 0; i < TEST_CNT; i++) { | |
syscall(__NR_getuid); /* dummy call */ | |
clock_gettime(CLOCK_MONOTONIC, &tp); | |
if (unlikely(bpf_map_lookup_elem(bpf_map_fd, &key, &map))) { | |
fprintf(stderr, "Failed to lookup map element\n"); | |
perror("lookup"); | |
exit(-1); | |
} | |
delta += (1000000000 * tp.tv_sec + tp.tv_nsec) - map.ts; | |
} | |
printf("avg: %fns\n", (double) delta / TEST_CNT); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment