11bec43f5SNamhyung Kim /* SPDX-License-Identifier: GPL-2.0 */ 21bec43f5SNamhyung Kim #include <inttypes.h> 31bec43f5SNamhyung Kim #include <math.h> 41bec43f5SNamhyung Kim #include <stdio.h> 51bec43f5SNamhyung Kim #include <stdlib.h> 61bec43f5SNamhyung Kim 71bec43f5SNamhyung Kim #include "dwarf-regs.h" /* for EM_HOST */ 81bec43f5SNamhyung Kim #include "syscalltbl.h" 9*ef60b8f5SNamhyung Kim #include "util/cgroup.h" 101bec43f5SNamhyung Kim #include "util/hashmap.h" 111bec43f5SNamhyung Kim #include "util/trace.h" 121bec43f5SNamhyung Kim #include "util/util.h" 131bec43f5SNamhyung Kim #include <bpf/bpf.h> 14*ef60b8f5SNamhyung Kim #include <linux/rbtree.h> 151bec43f5SNamhyung Kim #include <linux/time64.h> 161bec43f5SNamhyung Kim #include <tools/libc_compat.h> /* reallocarray */ 171bec43f5SNamhyung Kim 181bec43f5SNamhyung Kim #include "bpf_skel/syscall_summary.h" 191bec43f5SNamhyung Kim #include "bpf_skel/syscall_summary.skel.h" 201bec43f5SNamhyung Kim 211bec43f5SNamhyung Kim 221bec43f5SNamhyung Kim static struct syscall_summary_bpf *skel; 23*ef60b8f5SNamhyung Kim static struct rb_root cgroups = RB_ROOT; 241bec43f5SNamhyung Kim 251bec43f5SNamhyung Kim int trace_prepare_bpf_summary(enum trace_summary_mode mode) 261bec43f5SNamhyung Kim { 271bec43f5SNamhyung Kim skel = syscall_summary_bpf__open(); 281bec43f5SNamhyung Kim if (skel == NULL) { 291bec43f5SNamhyung Kim fprintf(stderr, "failed to open syscall summary bpf skeleton\n"); 301bec43f5SNamhyung Kim return -1; 311bec43f5SNamhyung Kim } 321bec43f5SNamhyung Kim 331bec43f5SNamhyung Kim if (mode == SUMMARY__BY_THREAD) 341bec43f5SNamhyung Kim skel->rodata->aggr_mode = SYSCALL_AGGR_THREAD; 35*ef60b8f5SNamhyung Kim else if (mode == SUMMARY__BY_CGROUP) 36*ef60b8f5SNamhyung Kim skel->rodata->aggr_mode = SYSCALL_AGGR_CGROUP; 371bec43f5SNamhyung Kim else 381bec43f5SNamhyung Kim skel->rodata->aggr_mode = SYSCALL_AGGR_CPU; 391bec43f5SNamhyung Kim 40*ef60b8f5SNamhyung Kim if (cgroup_is_v2("perf_event") > 0) 41*ef60b8f5SNamhyung Kim skel->rodata->use_cgroup_v2 = 1; 42*ef60b8f5SNamhyung Kim 431bec43f5SNamhyung Kim if (syscall_summary_bpf__load(skel) < 0) { 441bec43f5SNamhyung Kim fprintf(stderr, "failed to load syscall summary bpf skeleton\n"); 451bec43f5SNamhyung Kim return -1; 461bec43f5SNamhyung Kim } 471bec43f5SNamhyung Kim 481bec43f5SNamhyung Kim if (syscall_summary_bpf__attach(skel) < 0) { 491bec43f5SNamhyung Kim fprintf(stderr, "failed to attach syscall summary bpf skeleton\n"); 501bec43f5SNamhyung Kim return -1; 511bec43f5SNamhyung Kim } 521bec43f5SNamhyung Kim 53*ef60b8f5SNamhyung Kim if (mode == SUMMARY__BY_CGROUP) 54*ef60b8f5SNamhyung Kim read_all_cgroups(&cgroups); 55*ef60b8f5SNamhyung Kim 561bec43f5SNamhyung Kim return 0; 571bec43f5SNamhyung Kim } 581bec43f5SNamhyung Kim 591bec43f5SNamhyung Kim void trace_start_bpf_summary(void) 601bec43f5SNamhyung Kim { 611bec43f5SNamhyung Kim skel->bss->enabled = 1; 621bec43f5SNamhyung Kim } 631bec43f5SNamhyung Kim 641bec43f5SNamhyung Kim void trace_end_bpf_summary(void) 651bec43f5SNamhyung Kim { 661bec43f5SNamhyung Kim skel->bss->enabled = 0; 671bec43f5SNamhyung Kim } 681bec43f5SNamhyung Kim 691bec43f5SNamhyung Kim struct syscall_node { 701bec43f5SNamhyung Kim int syscall_nr; 711bec43f5SNamhyung Kim struct syscall_stats stats; 721bec43f5SNamhyung Kim }; 731bec43f5SNamhyung Kim 741bec43f5SNamhyung Kim static double rel_stddev(struct syscall_stats *stat) 751bec43f5SNamhyung Kim { 761bec43f5SNamhyung Kim double variance, average; 771bec43f5SNamhyung Kim 781bec43f5SNamhyung Kim if (stat->count < 2) 791bec43f5SNamhyung Kim return 0; 801bec43f5SNamhyung Kim 811bec43f5SNamhyung Kim average = (double)stat->total_time / stat->count; 821bec43f5SNamhyung Kim 831bec43f5SNamhyung Kim variance = stat->squared_sum; 841bec43f5SNamhyung Kim variance -= (stat->total_time * stat->total_time) / stat->count; 851bec43f5SNamhyung Kim variance /= stat->count - 1; 861bec43f5SNamhyung Kim 871bec43f5SNamhyung Kim return 100 * sqrt(variance / stat->count) / average; 881bec43f5SNamhyung Kim } 891bec43f5SNamhyung Kim 901bec43f5SNamhyung Kim /* 911bec43f5SNamhyung Kim * The syscall_data is to maintain syscall stats ordered by total time. 921bec43f5SNamhyung Kim * It supports different summary modes like per-thread or global. 931bec43f5SNamhyung Kim * 941bec43f5SNamhyung Kim * For per-thread stats, it uses two-level data strurcture - 951bec43f5SNamhyung Kim * syscall_data is keyed by TID and has an array of nodes which 961bec43f5SNamhyung Kim * represents each syscall for the thread. 971bec43f5SNamhyung Kim * 981bec43f5SNamhyung Kim * For global stats, it's still two-level technically but we don't need 991bec43f5SNamhyung Kim * per-cpu analysis so it's keyed by the syscall number to combine stats 1001bec43f5SNamhyung Kim * from different CPUs. And syscall_data always has a syscall_node so 1011bec43f5SNamhyung Kim * it can effectively work as flat hierarchy. 102*ef60b8f5SNamhyung Kim * 103*ef60b8f5SNamhyung Kim * For per-cgroup stats, it uses two-level data structure like thread 104*ef60b8f5SNamhyung Kim * syscall_data is keyed by CGROUP and has an array of node which 105*ef60b8f5SNamhyung Kim * represents each syscall for the cgroup. 1061bec43f5SNamhyung Kim */ 1071bec43f5SNamhyung Kim struct syscall_data { 108*ef60b8f5SNamhyung Kim u64 key; /* tid if AGGR_THREAD, syscall-nr if AGGR_CPU, cgroup if AGGR_CGROUP */ 1091bec43f5SNamhyung Kim int nr_events; 1101bec43f5SNamhyung Kim int nr_nodes; 1111bec43f5SNamhyung Kim u64 total_time; 1121bec43f5SNamhyung Kim struct syscall_node *nodes; 1131bec43f5SNamhyung Kim }; 1141bec43f5SNamhyung Kim 1151bec43f5SNamhyung Kim static int datacmp(const void *a, const void *b) 1161bec43f5SNamhyung Kim { 1171bec43f5SNamhyung Kim const struct syscall_data * const *sa = a; 1181bec43f5SNamhyung Kim const struct syscall_data * const *sb = b; 1191bec43f5SNamhyung Kim 1201bec43f5SNamhyung Kim return (*sa)->total_time > (*sb)->total_time ? -1 : 1; 1211bec43f5SNamhyung Kim } 1221bec43f5SNamhyung Kim 1231bec43f5SNamhyung Kim static int nodecmp(const void *a, const void *b) 1241bec43f5SNamhyung Kim { 1251bec43f5SNamhyung Kim const struct syscall_node *na = a; 1261bec43f5SNamhyung Kim const struct syscall_node *nb = b; 1271bec43f5SNamhyung Kim 1281bec43f5SNamhyung Kim return na->stats.total_time > nb->stats.total_time ? -1 : 1; 1291bec43f5SNamhyung Kim } 1301bec43f5SNamhyung Kim 1311bec43f5SNamhyung Kim static size_t sc_node_hash(long key, void *ctx __maybe_unused) 1321bec43f5SNamhyung Kim { 1331bec43f5SNamhyung Kim return key; 1341bec43f5SNamhyung Kim } 1351bec43f5SNamhyung Kim 1361bec43f5SNamhyung Kim static bool sc_node_equal(long key1, long key2, void *ctx __maybe_unused) 1371bec43f5SNamhyung Kim { 1381bec43f5SNamhyung Kim return key1 == key2; 1391bec43f5SNamhyung Kim } 1401bec43f5SNamhyung Kim 1411bec43f5SNamhyung Kim static int print_common_stats(struct syscall_data *data, FILE *fp) 1421bec43f5SNamhyung Kim { 1431bec43f5SNamhyung Kim int printed = 0; 1441bec43f5SNamhyung Kim 1451bec43f5SNamhyung Kim for (int i = 0; i < data->nr_nodes; i++) { 1461bec43f5SNamhyung Kim struct syscall_node *node = &data->nodes[i]; 1471bec43f5SNamhyung Kim struct syscall_stats *stat = &node->stats; 1481bec43f5SNamhyung Kim double total = (double)(stat->total_time) / NSEC_PER_MSEC; 1491bec43f5SNamhyung Kim double min = (double)(stat->min_time) / NSEC_PER_MSEC; 1501bec43f5SNamhyung Kim double max = (double)(stat->max_time) / NSEC_PER_MSEC; 1511bec43f5SNamhyung Kim double avg = total / stat->count; 1521bec43f5SNamhyung Kim const char *name; 1531bec43f5SNamhyung Kim 1541bec43f5SNamhyung Kim /* TODO: support other ABIs */ 1551bec43f5SNamhyung Kim name = syscalltbl__name(EM_HOST, node->syscall_nr); 1561bec43f5SNamhyung Kim if (name) 1571bec43f5SNamhyung Kim printed += fprintf(fp, " %-15s", name); 1581bec43f5SNamhyung Kim else 1591bec43f5SNamhyung Kim printed += fprintf(fp, " syscall:%-7d", node->syscall_nr); 1601bec43f5SNamhyung Kim 1611bec43f5SNamhyung Kim printed += fprintf(fp, " %8u %6u %9.3f %9.3f %9.3f %9.3f %9.2f%%\n", 1621bec43f5SNamhyung Kim stat->count, stat->error, total, min, avg, max, 1631bec43f5SNamhyung Kim rel_stddev(stat)); 1641bec43f5SNamhyung Kim } 1651bec43f5SNamhyung Kim return printed; 1661bec43f5SNamhyung Kim } 1671bec43f5SNamhyung Kim 1681bec43f5SNamhyung Kim static int update_thread_stats(struct hashmap *hash, struct syscall_key *map_key, 1691bec43f5SNamhyung Kim struct syscall_stats *map_data) 1701bec43f5SNamhyung Kim { 1711bec43f5SNamhyung Kim struct syscall_data *data; 1721bec43f5SNamhyung Kim struct syscall_node *nodes; 1731bec43f5SNamhyung Kim 1741bec43f5SNamhyung Kim if (!hashmap__find(hash, map_key->cpu_or_tid, &data)) { 1751bec43f5SNamhyung Kim data = zalloc(sizeof(*data)); 1761bec43f5SNamhyung Kim if (data == NULL) 1771bec43f5SNamhyung Kim return -ENOMEM; 1781bec43f5SNamhyung Kim 1791bec43f5SNamhyung Kim data->key = map_key->cpu_or_tid; 1801bec43f5SNamhyung Kim if (hashmap__add(hash, data->key, data) < 0) { 1811bec43f5SNamhyung Kim free(data); 1821bec43f5SNamhyung Kim return -ENOMEM; 1831bec43f5SNamhyung Kim } 1841bec43f5SNamhyung Kim } 1851bec43f5SNamhyung Kim 1861bec43f5SNamhyung Kim /* update thread total stats */ 1871bec43f5SNamhyung Kim data->nr_events += map_data->count; 1881bec43f5SNamhyung Kim data->total_time += map_data->total_time; 1891bec43f5SNamhyung Kim 1901bec43f5SNamhyung Kim nodes = reallocarray(data->nodes, data->nr_nodes + 1, sizeof(*nodes)); 1911bec43f5SNamhyung Kim if (nodes == NULL) 1921bec43f5SNamhyung Kim return -ENOMEM; 1931bec43f5SNamhyung Kim 1941bec43f5SNamhyung Kim data->nodes = nodes; 1951bec43f5SNamhyung Kim nodes = &data->nodes[data->nr_nodes++]; 1961bec43f5SNamhyung Kim nodes->syscall_nr = map_key->nr; 1971bec43f5SNamhyung Kim 1981bec43f5SNamhyung Kim /* each thread has an entry for each syscall, just use the stat */ 1991bec43f5SNamhyung Kim memcpy(&nodes->stats, map_data, sizeof(*map_data)); 2001bec43f5SNamhyung Kim return 0; 2011bec43f5SNamhyung Kim } 2021bec43f5SNamhyung Kim 2031bec43f5SNamhyung Kim static int print_thread_stat(struct syscall_data *data, FILE *fp) 2041bec43f5SNamhyung Kim { 2051bec43f5SNamhyung Kim int printed = 0; 2061bec43f5SNamhyung Kim 2071bec43f5SNamhyung Kim qsort(data->nodes, data->nr_nodes, sizeof(*data->nodes), nodecmp); 2081bec43f5SNamhyung Kim 209*ef60b8f5SNamhyung Kim printed += fprintf(fp, " thread (%d), ", (int)data->key); 2101bec43f5SNamhyung Kim printed += fprintf(fp, "%d events\n\n", data->nr_events); 2111bec43f5SNamhyung Kim 2121bec43f5SNamhyung Kim printed += fprintf(fp, " syscall calls errors total min avg max stddev\n"); 2131bec43f5SNamhyung Kim printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); 2141bec43f5SNamhyung Kim printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n"); 2151bec43f5SNamhyung Kim 2161bec43f5SNamhyung Kim printed += print_common_stats(data, fp); 2171bec43f5SNamhyung Kim printed += fprintf(fp, "\n\n"); 2181bec43f5SNamhyung Kim 2191bec43f5SNamhyung Kim return printed; 2201bec43f5SNamhyung Kim } 2211bec43f5SNamhyung Kim 2221bec43f5SNamhyung Kim static int print_thread_stats(struct syscall_data **data, int nr_data, FILE *fp) 2231bec43f5SNamhyung Kim { 2241bec43f5SNamhyung Kim int printed = 0; 2251bec43f5SNamhyung Kim 2261bec43f5SNamhyung Kim for (int i = 0; i < nr_data; i++) 2271bec43f5SNamhyung Kim printed += print_thread_stat(data[i], fp); 2281bec43f5SNamhyung Kim 2291bec43f5SNamhyung Kim return printed; 2301bec43f5SNamhyung Kim } 2311bec43f5SNamhyung Kim 2321bec43f5SNamhyung Kim static int update_total_stats(struct hashmap *hash, struct syscall_key *map_key, 2331bec43f5SNamhyung Kim struct syscall_stats *map_data) 2341bec43f5SNamhyung Kim { 2351bec43f5SNamhyung Kim struct syscall_data *data; 2361bec43f5SNamhyung Kim struct syscall_stats *stat; 2371bec43f5SNamhyung Kim 2381bec43f5SNamhyung Kim if (!hashmap__find(hash, map_key->nr, &data)) { 2391bec43f5SNamhyung Kim data = zalloc(sizeof(*data)); 2401bec43f5SNamhyung Kim if (data == NULL) 2411bec43f5SNamhyung Kim return -ENOMEM; 2421bec43f5SNamhyung Kim 2431bec43f5SNamhyung Kim data->nodes = zalloc(sizeof(*data->nodes)); 2441bec43f5SNamhyung Kim if (data->nodes == NULL) { 2451bec43f5SNamhyung Kim free(data); 2461bec43f5SNamhyung Kim return -ENOMEM; 2471bec43f5SNamhyung Kim } 2481bec43f5SNamhyung Kim 2491bec43f5SNamhyung Kim data->nr_nodes = 1; 2501bec43f5SNamhyung Kim data->key = map_key->nr; 2511bec43f5SNamhyung Kim data->nodes->syscall_nr = data->key; 2521bec43f5SNamhyung Kim 2531bec43f5SNamhyung Kim if (hashmap__add(hash, data->key, data) < 0) { 2541bec43f5SNamhyung Kim free(data->nodes); 2551bec43f5SNamhyung Kim free(data); 2561bec43f5SNamhyung Kim return -ENOMEM; 2571bec43f5SNamhyung Kim } 2581bec43f5SNamhyung Kim } 2591bec43f5SNamhyung Kim 2601bec43f5SNamhyung Kim /* update total stats for this syscall */ 2611bec43f5SNamhyung Kim data->nr_events += map_data->count; 2621bec43f5SNamhyung Kim data->total_time += map_data->total_time; 2631bec43f5SNamhyung Kim 2641bec43f5SNamhyung Kim /* This is sum of the same syscall from different CPUs */ 2651bec43f5SNamhyung Kim stat = &data->nodes->stats; 2661bec43f5SNamhyung Kim 2671bec43f5SNamhyung Kim stat->total_time += map_data->total_time; 2681bec43f5SNamhyung Kim stat->squared_sum += map_data->squared_sum; 2691bec43f5SNamhyung Kim stat->count += map_data->count; 2701bec43f5SNamhyung Kim stat->error += map_data->error; 2711bec43f5SNamhyung Kim 2721bec43f5SNamhyung Kim if (stat->max_time < map_data->max_time) 2731bec43f5SNamhyung Kim stat->max_time = map_data->max_time; 2741bec43f5SNamhyung Kim if (stat->min_time > map_data->min_time || stat->min_time == 0) 2751bec43f5SNamhyung Kim stat->min_time = map_data->min_time; 2761bec43f5SNamhyung Kim 2771bec43f5SNamhyung Kim return 0; 2781bec43f5SNamhyung Kim } 2791bec43f5SNamhyung Kim 2801bec43f5SNamhyung Kim static int print_total_stats(struct syscall_data **data, int nr_data, FILE *fp) 2811bec43f5SNamhyung Kim { 2821bec43f5SNamhyung Kim int printed = 0; 2831bec43f5SNamhyung Kim int nr_events = 0; 2841bec43f5SNamhyung Kim 2851bec43f5SNamhyung Kim for (int i = 0; i < nr_data; i++) 2861bec43f5SNamhyung Kim nr_events += data[i]->nr_events; 2871bec43f5SNamhyung Kim 2881bec43f5SNamhyung Kim printed += fprintf(fp, " total, %d events\n\n", nr_events); 2891bec43f5SNamhyung Kim 2901bec43f5SNamhyung Kim printed += fprintf(fp, " syscall calls errors total min avg max stddev\n"); 2911bec43f5SNamhyung Kim printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); 2921bec43f5SNamhyung Kim printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n"); 2931bec43f5SNamhyung Kim 2941bec43f5SNamhyung Kim for (int i = 0; i < nr_data; i++) 2951bec43f5SNamhyung Kim printed += print_common_stats(data[i], fp); 2961bec43f5SNamhyung Kim 2971bec43f5SNamhyung Kim printed += fprintf(fp, "\n\n"); 2981bec43f5SNamhyung Kim return printed; 2991bec43f5SNamhyung Kim } 3001bec43f5SNamhyung Kim 301*ef60b8f5SNamhyung Kim static int update_cgroup_stats(struct hashmap *hash, struct syscall_key *map_key, 302*ef60b8f5SNamhyung Kim struct syscall_stats *map_data) 303*ef60b8f5SNamhyung Kim { 304*ef60b8f5SNamhyung Kim struct syscall_data *data; 305*ef60b8f5SNamhyung Kim struct syscall_node *nodes; 306*ef60b8f5SNamhyung Kim 307*ef60b8f5SNamhyung Kim if (!hashmap__find(hash, map_key->cgroup, &data)) { 308*ef60b8f5SNamhyung Kim data = zalloc(sizeof(*data)); 309*ef60b8f5SNamhyung Kim if (data == NULL) 310*ef60b8f5SNamhyung Kim return -ENOMEM; 311*ef60b8f5SNamhyung Kim 312*ef60b8f5SNamhyung Kim data->key = map_key->cgroup; 313*ef60b8f5SNamhyung Kim if (hashmap__add(hash, data->key, data) < 0) { 314*ef60b8f5SNamhyung Kim free(data); 315*ef60b8f5SNamhyung Kim return -ENOMEM; 316*ef60b8f5SNamhyung Kim } 317*ef60b8f5SNamhyung Kim } 318*ef60b8f5SNamhyung Kim 319*ef60b8f5SNamhyung Kim /* update thread total stats */ 320*ef60b8f5SNamhyung Kim data->nr_events += map_data->count; 321*ef60b8f5SNamhyung Kim data->total_time += map_data->total_time; 322*ef60b8f5SNamhyung Kim 323*ef60b8f5SNamhyung Kim nodes = reallocarray(data->nodes, data->nr_nodes + 1, sizeof(*nodes)); 324*ef60b8f5SNamhyung Kim if (nodes == NULL) 325*ef60b8f5SNamhyung Kim return -ENOMEM; 326*ef60b8f5SNamhyung Kim 327*ef60b8f5SNamhyung Kim data->nodes = nodes; 328*ef60b8f5SNamhyung Kim nodes = &data->nodes[data->nr_nodes++]; 329*ef60b8f5SNamhyung Kim nodes->syscall_nr = map_key->nr; 330*ef60b8f5SNamhyung Kim 331*ef60b8f5SNamhyung Kim /* each thread has an entry for each syscall, just use the stat */ 332*ef60b8f5SNamhyung Kim memcpy(&nodes->stats, map_data, sizeof(*map_data)); 333*ef60b8f5SNamhyung Kim return 0; 334*ef60b8f5SNamhyung Kim } 335*ef60b8f5SNamhyung Kim 336*ef60b8f5SNamhyung Kim static int print_cgroup_stat(struct syscall_data *data, FILE *fp) 337*ef60b8f5SNamhyung Kim { 338*ef60b8f5SNamhyung Kim int printed = 0; 339*ef60b8f5SNamhyung Kim struct cgroup *cgrp = __cgroup__find(&cgroups, data->key); 340*ef60b8f5SNamhyung Kim 341*ef60b8f5SNamhyung Kim qsort(data->nodes, data->nr_nodes, sizeof(*data->nodes), nodecmp); 342*ef60b8f5SNamhyung Kim 343*ef60b8f5SNamhyung Kim if (cgrp) 344*ef60b8f5SNamhyung Kim printed += fprintf(fp, " cgroup %s,", cgrp->name); 345*ef60b8f5SNamhyung Kim else 346*ef60b8f5SNamhyung Kim printed += fprintf(fp, " cgroup id:%lu,", (unsigned long)data->key); 347*ef60b8f5SNamhyung Kim 348*ef60b8f5SNamhyung Kim printed += fprintf(fp, " %d events\n\n", data->nr_events); 349*ef60b8f5SNamhyung Kim 350*ef60b8f5SNamhyung Kim printed += fprintf(fp, " syscall calls errors total min avg max stddev\n"); 351*ef60b8f5SNamhyung Kim printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); 352*ef60b8f5SNamhyung Kim printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n"); 353*ef60b8f5SNamhyung Kim 354*ef60b8f5SNamhyung Kim printed += print_common_stats(data, fp); 355*ef60b8f5SNamhyung Kim printed += fprintf(fp, "\n\n"); 356*ef60b8f5SNamhyung Kim 357*ef60b8f5SNamhyung Kim return printed; 358*ef60b8f5SNamhyung Kim } 359*ef60b8f5SNamhyung Kim 360*ef60b8f5SNamhyung Kim static int print_cgroup_stats(struct syscall_data **data, int nr_data, FILE *fp) 361*ef60b8f5SNamhyung Kim { 362*ef60b8f5SNamhyung Kim int printed = 0; 363*ef60b8f5SNamhyung Kim 364*ef60b8f5SNamhyung Kim for (int i = 0; i < nr_data; i++) 365*ef60b8f5SNamhyung Kim printed += print_cgroup_stat(data[i], fp); 366*ef60b8f5SNamhyung Kim 367*ef60b8f5SNamhyung Kim return printed; 368*ef60b8f5SNamhyung Kim } 369*ef60b8f5SNamhyung Kim 3701bec43f5SNamhyung Kim int trace_print_bpf_summary(FILE *fp) 3711bec43f5SNamhyung Kim { 3721bec43f5SNamhyung Kim struct bpf_map *map = skel->maps.syscall_stats_map; 3731bec43f5SNamhyung Kim struct syscall_key *prev_key, key; 3741bec43f5SNamhyung Kim struct syscall_data **data = NULL; 3751bec43f5SNamhyung Kim struct hashmap schash; 3761bec43f5SNamhyung Kim struct hashmap_entry *entry; 3771bec43f5SNamhyung Kim int nr_data = 0; 3781bec43f5SNamhyung Kim int printed = 0; 3791bec43f5SNamhyung Kim int i; 3801bec43f5SNamhyung Kim size_t bkt; 3811bec43f5SNamhyung Kim 3821bec43f5SNamhyung Kim hashmap__init(&schash, sc_node_hash, sc_node_equal, /*ctx=*/NULL); 3831bec43f5SNamhyung Kim 3841bec43f5SNamhyung Kim printed = fprintf(fp, "\n Summary of events:\n\n"); 3851bec43f5SNamhyung Kim 3861bec43f5SNamhyung Kim /* get stats from the bpf map */ 3871bec43f5SNamhyung Kim prev_key = NULL; 3881bec43f5SNamhyung Kim while (!bpf_map__get_next_key(map, prev_key, &key, sizeof(key))) { 3891bec43f5SNamhyung Kim struct syscall_stats stat; 3901bec43f5SNamhyung Kim 3911bec43f5SNamhyung Kim if (!bpf_map__lookup_elem(map, &key, sizeof(key), &stat, sizeof(stat), 0)) { 392*ef60b8f5SNamhyung Kim switch (skel->rodata->aggr_mode) { 393*ef60b8f5SNamhyung Kim case SYSCALL_AGGR_THREAD: 3941bec43f5SNamhyung Kim update_thread_stats(&schash, &key, &stat); 395*ef60b8f5SNamhyung Kim break; 396*ef60b8f5SNamhyung Kim case SYSCALL_AGGR_CPU: 3971bec43f5SNamhyung Kim update_total_stats(&schash, &key, &stat); 398*ef60b8f5SNamhyung Kim break; 399*ef60b8f5SNamhyung Kim case SYSCALL_AGGR_CGROUP: 400*ef60b8f5SNamhyung Kim update_cgroup_stats(&schash, &key, &stat); 401*ef60b8f5SNamhyung Kim break; 402*ef60b8f5SNamhyung Kim default: 403*ef60b8f5SNamhyung Kim break; 404*ef60b8f5SNamhyung Kim } 4051bec43f5SNamhyung Kim } 4061bec43f5SNamhyung Kim 4071bec43f5SNamhyung Kim prev_key = &key; 4081bec43f5SNamhyung Kim } 4091bec43f5SNamhyung Kim 4101bec43f5SNamhyung Kim nr_data = hashmap__size(&schash); 4111bec43f5SNamhyung Kim data = calloc(nr_data, sizeof(*data)); 4121bec43f5SNamhyung Kim if (data == NULL) 4131bec43f5SNamhyung Kim goto out; 4141bec43f5SNamhyung Kim 4151bec43f5SNamhyung Kim i = 0; 4161bec43f5SNamhyung Kim hashmap__for_each_entry(&schash, entry, bkt) 4171bec43f5SNamhyung Kim data[i++] = entry->pvalue; 4181bec43f5SNamhyung Kim 4191bec43f5SNamhyung Kim qsort(data, nr_data, sizeof(*data), datacmp); 4201bec43f5SNamhyung Kim 421*ef60b8f5SNamhyung Kim switch (skel->rodata->aggr_mode) { 422*ef60b8f5SNamhyung Kim case SYSCALL_AGGR_THREAD: 4231bec43f5SNamhyung Kim printed += print_thread_stats(data, nr_data, fp); 424*ef60b8f5SNamhyung Kim break; 425*ef60b8f5SNamhyung Kim case SYSCALL_AGGR_CPU: 4261bec43f5SNamhyung Kim printed += print_total_stats(data, nr_data, fp); 427*ef60b8f5SNamhyung Kim break; 428*ef60b8f5SNamhyung Kim case SYSCALL_AGGR_CGROUP: 429*ef60b8f5SNamhyung Kim printed += print_cgroup_stats(data, nr_data, fp); 430*ef60b8f5SNamhyung Kim break; 431*ef60b8f5SNamhyung Kim default: 432*ef60b8f5SNamhyung Kim break; 433*ef60b8f5SNamhyung Kim } 4341bec43f5SNamhyung Kim 4351bec43f5SNamhyung Kim for (i = 0; i < nr_data && data; i++) { 4361bec43f5SNamhyung Kim free(data[i]->nodes); 4371bec43f5SNamhyung Kim free(data[i]); 4381bec43f5SNamhyung Kim } 4391bec43f5SNamhyung Kim free(data); 4401bec43f5SNamhyung Kim 4411bec43f5SNamhyung Kim out: 4421bec43f5SNamhyung Kim hashmap__clear(&schash); 4431bec43f5SNamhyung Kim return printed; 4441bec43f5SNamhyung Kim } 4451bec43f5SNamhyung Kim 4461bec43f5SNamhyung Kim void trace_cleanup_bpf_summary(void) 4471bec43f5SNamhyung Kim { 448*ef60b8f5SNamhyung Kim if (!RB_EMPTY_ROOT(&cgroups)) { 449*ef60b8f5SNamhyung Kim struct cgroup *cgrp, *tmp; 450*ef60b8f5SNamhyung Kim 451*ef60b8f5SNamhyung Kim rbtree_postorder_for_each_entry_safe(cgrp, tmp, &cgroups, node) 452*ef60b8f5SNamhyung Kim cgroup__put(cgrp); 453*ef60b8f5SNamhyung Kim 454*ef60b8f5SNamhyung Kim cgroups = RB_ROOT; 455*ef60b8f5SNamhyung Kim } 456*ef60b8f5SNamhyung Kim 4571bec43f5SNamhyung Kim syscall_summary_bpf__destroy(skel); 4581bec43f5SNamhyung Kim } 459