/
xdp_mem_track02.bt
executable file
·113 lines (94 loc) · 3.21 KB
/
xdp_mem_track02.bt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/local/bin/bpftrace
/*
* xdp_mem_track02 - Catch when XDP mem_model unreg see inflight packets/pages
*
* In certain cases when unregistring a page_pool allocator via the
* kernels xdp_rxq_info_unreg() / xdp_rxq_info_unreg_mem_model() call,
* then there can still be inflight packets/pages. The purpose is to
* catch these cases, to make sure this code path is activated.
*
* NIC driver developers converting their driver to use page_pool, should
* use this script to verify, they don't leak pages.
*
* Extended version of xdp_mem_track01:
* - Extract inflight counters via page_pool tracepoint
*
*/
BEGIN {
printf("Tracking XDP memory allocator connect+disconnect\n");
@types[0] = "PAGE_SHARED";
@types[1] = "PAGE_ORDER0";
@types[2] = "PAGE_POOL";
@types[3] = "ZERO_COPY";
}
tracepoint:xdp:mem_connect {
$id = args->mem_id;
$page_pool = args->allocator;
$type = args->mem_type;
$type_str = @types[$type];
time();
printf("%s: type:%s mem.id:%d 0x%lX\n",
probe, $type_str, $id, $page_pool);
@active_mem_ids[$id] = nsecs;
}
tracepoint:xdp:mem_disconnect {
$id = args->mem_id;
$page_pool = args->allocator;
$type = args->mem_type;
$type_str = @types[$type];
$cnt = args->disconnect_cnt;
$safe_to_remove = args->safe_to_remove;
time(); /* Used as event marker */
$time_ms = 0;
if (@active_mem_ids[$id]) {
$time_ms = (nsecs - @active_mem_ids[$id]) / 1000000;
}
if ($safe_to_remove == 0) {
printf("%s: type:%s mem.id=%d NOT-safe_to_remove:%d (*HIT*)\n",
probe, $type_str, $id, $safe_to_remove);
/* Track here as xdp:mem_connect didn't see connect */
if ($time_ms == 0) {
@active_mem_ids[$id] = nsecs;
}
/* Tracepoint page_pool_release is triggered just before.
* Transfer info via maps @pp_stat_* to this tracepoint.
*/
$pp = (uint64)$page_pool; /* type-case didn't make difference */
$inflight = @pp_stat_inflight[$pp];
$hold = @pp_stat_hold[$pp];
$release = @pp_stat_release[$pp];
printf("%s: type:%s mem.id=%d inflight:%d (hold:%d release:%d)\n",
probe, $type_str, $id, $inflight, $hold, $release);
/* Print mem IDs that hit not-safe-to-remove */
@test_case_hit[$id, $cnt, $time_ms] = $inflight;
} else {
delete(@active_mem_ids[$id]);
}
if ($cnt > 1) {
printf("%s: type:%s mem.id=%d re-sched(%d) safe_to_remove:%d\n",
probe, $type_str, $id, $cnt, $safe_to_remove);
}
printf("%s: type:%s mem.id:%d 0x%lX safe_to_remove:%d (lived %d ms)\n",
probe, $type_str, $id, $page_pool, $safe_to_remove, $time_ms);
}
tracepoint:page_pool:page_pool_release {
$page_pool = args->pool;
$inflight = args->inflight;
$hold = args->hold;
$release = args->release;
/* Challenge is that 'mem_id' is unknown to page_pool object.
* Thus, identifier is page_pool pointer in map.
*/
if ($inflight > 0) {
printf("%s: pp:0x%lX inflight:%d (hold:%d release:%d)\n",
probe, $page_pool, $inflight, $hold, $release);
$pp = (uint64)$page_pool; /* type-case necessary here */
@pp_stat_inflight[$pp] = $inflight;
@pp_stat_hold[$pp] = $hold;
@pp_stat_release[$pp] = $release;
}
}
END {
/* Default bpftrace will print all remaining maps at END */
clear(@types); /* Avoid printing @types table */
}