150 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3 4#include <stdio.h>5#include <string.h>6 7#include <ynl.h>8 9#include <net/if.h>10 11#include "netdev-user.h"12 13struct stat {14 unsigned int ifc;15 16 struct {17 unsigned int cnt;18 size_t refs, bytes;19 } live[2];20 21 size_t alloc_slow, alloc_fast, recycle_ring, recycle_cache;22};23 24struct stats_array {25 unsigned int i, max;26 struct stat *s;27};28 29static struct stat *find_ifc(struct stats_array *a, unsigned int ifindex)30{31 unsigned int i;32 33 for (i = 0; i < a->i; i++) {34 if (a->s[i].ifc == ifindex)35 return &a->s[i];36 }37 38 a->i++;39 if (a->i == a->max) {40 a->max *= 2;41 a->s = reallocarray(a->s, a->max, sizeof(*a->s));42 }43 a->s[i].ifc = ifindex;44 return &a->s[i];45}46 47static void count(struct stat *s, unsigned int l,48 struct netdev_page_pool_get_rsp *pp)49{50 s->live[l].cnt++;51 if (pp->_present.inflight)52 s->live[l].refs += pp->inflight;53 if (pp->_present.inflight_mem)54 s->live[l].bytes += pp->inflight_mem;55}56 57int main(int argc, char **argv)58{59 struct netdev_page_pool_stats_get_list *pp_stats;60 struct netdev_page_pool_get_list *pools;61 struct stats_array a = {};62 struct ynl_error yerr;63 struct ynl_sock *ys;64 65 ys = ynl_sock_create(&ynl_netdev_family, &yerr);66 if (!ys) {67 fprintf(stderr, "YNL: %s\n", yerr.msg);68 return 1;69 }70 71 a.max = 128;72 a.s = calloc(a.max, sizeof(*a.s));73 if (!a.s)74 goto err_close;75 76 pools = netdev_page_pool_get_dump(ys);77 if (!pools)78 goto err_free;79 80 ynl_dump_foreach(pools, pp) {81 struct stat *s = find_ifc(&a, pp->ifindex);82 83 count(s, 1, pp);84 if (pp->_present.detach_time)85 count(s, 0, pp);86 }87 netdev_page_pool_get_list_free(pools);88 89 pp_stats = netdev_page_pool_stats_get_dump(ys);90 if (!pp_stats)91 goto err_free;92 93 ynl_dump_foreach(pp_stats, pp) {94 struct stat *s = find_ifc(&a, pp->info.ifindex);95 96 if (pp->_present.alloc_fast)97 s->alloc_fast += pp->alloc_fast;98 if (pp->_present.alloc_refill)99 s->alloc_fast += pp->alloc_refill;100 if (pp->_present.alloc_slow)101 s->alloc_slow += pp->alloc_slow;102 if (pp->_present.recycle_ring)103 s->recycle_ring += pp->recycle_ring;104 if (pp->_present.recycle_cached)105 s->recycle_cache += pp->recycle_cached;106 }107 netdev_page_pool_stats_get_list_free(pp_stats);108 109 for (unsigned int i = 0; i < a.i; i++) {110 char ifname[IF_NAMESIZE];111 struct stat *s = &a.s[i];112 const char *name;113 double recycle;114 115 if (!s->ifc) {116 name = "<orphan>\t";117 } else {118 name = if_indextoname(s->ifc, ifname);119 if (name)120 printf("%8s", name);121 printf("[%d]\t", s->ifc);122 }123 124 printf("page pools: %u (zombies: %u)\n",125 s->live[1].cnt, s->live[0].cnt);126 printf("\t\trefs: %zu bytes: %zu (refs: %zu bytes: %zu)\n",127 s->live[1].refs, s->live[1].bytes,128 s->live[0].refs, s->live[0].bytes);129 130 /* We don't know how many pages are sitting in cache and ring131 * so we will under-count the recycling rate a bit.132 */133 recycle = (double)(s->recycle_ring + s->recycle_cache) /134 (s->alloc_fast + s->alloc_slow) * 100;135 printf("\t\trecycling: %.1lf%% (alloc: %zu:%zu recycle: %zu:%zu)\n",136 recycle, s->alloc_slow, s->alloc_fast,137 s->recycle_ring, s->recycle_cache);138 }139 140 ynl_sock_destroy(ys);141 return 0;142 143err_free:144 free(a.s);145err_close:146 fprintf(stderr, "YNL: %s\n", ys->err.msg);147 ynl_sock_destroy(ys);148 return 2;149}150