1 /*
2 * Parse output from tmem-list and reformat to human-readable
3 *
4 * NOTE: NEVER delete a parse call as this file documents backwards
5 * compatibility for older versions of tmem-list and we don't want to
6 * accidentally reuse an old tag
7 *
8 * Copyright (c) 2009, Dan Magenheimer, Oracle Corp.
9 */
10
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <string.h>
14
15 #define BUFSIZE 4096
16 #define PAGE_SIZE 4096
17
parse(char * s,char * match)18 unsigned long long parse(char *s,char *match)
19 {
20 char *s1 = strstr(s,match);
21 unsigned long long ret;
22
23 if ( s1 == NULL )
24 return 0LL;
25 s1 += 2;
26 if ( *s1++ != ':' )
27 return 0LL;
28 sscanf(s1,"%llu",&ret);
29 return ret;
30 }
31
parse_hex(char * s,char * match)32 unsigned long long parse_hex(char *s,char *match)
33 {
34 char *s1 = strstr(s,match);
35 unsigned long long ret;
36
37 if ( s1 == NULL )
38 return 0LL;
39 s1 += 2;
40 if ( *s1++ != ':' )
41 return 0LL;
42 sscanf(s1,"%llx",&ret);
43 return ret;
44 }
45
parse2(char * s,char * match1,char * match2)46 unsigned long long parse2(char *s,char *match1, char *match2)
47 {
48 char match[3];
49 match[0] = *match1;
50 match[1] = *match2;
51 match[2] = '\0';
52 return parse(s,match);
53 }
54
parse_string(char * s,char * match,char * buf,int len)55 void parse_string(char *s,char *match, char *buf, int len)
56 {
57 char *s1 = strstr(s,match);
58 int i;
59
60 if ( s1 == NULL )
61 return;
62 s1 += 2;
63 if ( *s1++ != ':' )
64 return;
65 for ( i = 0; i < len; i++ )
66 *buf++ = *s1++;
67 }
68
parse_sharers(char * s,char * match,char * buf,int len)69 void parse_sharers(char *s, char *match, char *buf, int len)
70 {
71 char *s1 = strstr(s,match);
72 char *b = buf;
73
74 if ( s1 == NULL )
75 return;
76 while ( s1 )
77 {
78 s1 += 2;
79 if (*s1++ != ':')
80 return;
81 while (*s1 >= '0' && *s1 <= '9')
82 *b++ = *s1++;
83 *b++ = ',';
84 s1 = strstr(s1,match);
85 }
86 if ( b != buf )
87 *--b = '\0';
88 }
89
parse_global(char * s)90 void parse_global(char *s)
91 {
92 unsigned long long total_ops = parse(s,"Tt");
93 unsigned long long errored_ops = parse(s,"Te");
94 unsigned long long failed_copies = parse(s,"Cf");
95 unsigned long long alloc_failed = parse(s,"Af");
96 unsigned long long alloc_page_failed = parse(s,"Pf");
97 unsigned long long avail_pages = parse(s,"Ta");
98 unsigned long long low_on_memory = parse(s,"Lm");
99 unsigned long long evicted_pgs = parse(s,"Et");
100 unsigned long long evict_attempts = parse(s,"Ea");
101 unsigned long long relinq_pgs = parse(s,"Rt");
102 unsigned long long relinq_attempts = parse(s,"Ra");
103 unsigned long long max_evicts_per_relinq = parse(s,"Rx");
104 unsigned long long total_flush_pool = parse(s,"Fp");
105 unsigned long long global_eph_count = parse(s,"Ec");
106 unsigned long long global_eph_max = parse(s,"Em");
107 unsigned long long obj_count = parse(s,"Oc");
108 unsigned long long obj_max = parse(s,"Om");
109 unsigned long long rtree_node_count = parse(s,"Nc");
110 unsigned long long rtree_node_max = parse(s,"Nm");
111 unsigned long long pgp_count = parse(s,"Pc");
112 unsigned long long pgp_max = parse(s,"Pm");
113 unsigned long long page_count = parse(s,"Fc");
114 unsigned long long max_page_count = parse(s,"Fm");
115 unsigned long long pcd_count = parse(s,"Sc");
116 unsigned long long max_pcd_count = parse(s,"Sm");
117 unsigned long long pcd_tot_tze_size = parse(s,"Zt");
118 unsigned long long pcd_tot_csize = parse(s,"Gz");
119 unsigned long long deduped_puts = parse(s,"Gd");
120 unsigned long long tot_good_eph_puts = parse(s,"Ep");
121
122 printf("total tmem ops=%llu (errors=%llu) -- tmem pages avail=%llu\n",
123 total_ops, errored_ops, avail_pages);
124 printf("datastructs: objs=%llu (max=%llu) pgps=%llu (max=%llu) "
125 "nodes=%llu (max=%llu) pages=%llu (max=%llu) ",
126 obj_count, obj_max, pgp_count, pgp_max,
127 rtree_node_count, rtree_node_max,
128 page_count,max_page_count);
129 if (max_pcd_count != 0 && global_eph_count != 0 && tot_good_eph_puts != 0) {
130 printf("pcds=%llu (max=%llu) ",
131 pcd_count,max_pcd_count);
132 printf("deduped: avg=%4.2f%% (curr=%4.2f%%) ",
133 ((deduped_puts*1.0)/tot_good_eph_puts)*100,
134 (1.0-(pcd_count*1.0)/global_eph_count)*100);
135 }
136 if (pcd_count != 0)
137 {
138 if (pcd_tot_tze_size && (pcd_tot_tze_size < pcd_count*PAGE_SIZE))
139 printf("tze savings=%4.2f%% ",
140 (1.0-(pcd_tot_tze_size*1.0)/(pcd_count*PAGE_SIZE))*100);
141 if (pcd_tot_csize && (pcd_tot_csize < pcd_count*PAGE_SIZE))
142 printf("compression savings=%4.2f%% ",
143 (1.0-(pcd_tot_csize*1.0)/(pcd_count*PAGE_SIZE))*100);
144 }
145 printf("\n");
146 printf("misc: failed_copies=%llu alloc_failed=%llu alloc_page_failed=%llu "
147 "low_mem=%llu evicted=%llu/%llu relinq=%llu/%llu, "
148 "max_evicts_per_relinq=%llu, flush_pools=%llu, "
149 "eph_count=%llu, eph_max=%llu\n",
150 failed_copies, alloc_failed, alloc_page_failed, low_on_memory,
151 evicted_pgs, evict_attempts, relinq_pgs, relinq_attempts,
152 max_evicts_per_relinq, total_flush_pool,
153 global_eph_count, global_eph_max);
154 }
155
156 #define PARSE_CYC_COUNTER(s,x,prefix) unsigned long long \
157 x##_count = parse2(s,prefix,"n"), \
158 x##_sum_cycles = parse2(s,prefix,"t"), \
159 x##_max_cycles = parse2(s,prefix,"x"), \
160 x##_min_cycles = parse2(s,prefix,"m")
161 #define PRINTF_CYC_COUNTER(x,text) \
162 if (x##_count) printf(text" avg=%llu, max=%llu, " \
163 "min=%llu, samples=%llu\n", \
164 x##_sum_cycles ? (x##_sum_cycles/x##_count) : 0, \
165 x##_max_cycles, x##_min_cycles, x##_count)
166
parse_time_stats(char * s)167 void parse_time_stats(char *s)
168 {
169 PARSE_CYC_COUNTER(s,succ_get,"G");
170 PARSE_CYC_COUNTER(s,succ_put,"P");
171 PARSE_CYC_COUNTER(s,non_succ_get,"g");
172 PARSE_CYC_COUNTER(s,non_succ_put,"p");
173 PARSE_CYC_COUNTER(s,flush,"F");
174 PARSE_CYC_COUNTER(s,flush_obj,"O");
175 PARSE_CYC_COUNTER(s,pg_copy,"C");
176 PARSE_CYC_COUNTER(s,compress,"c");
177 PARSE_CYC_COUNTER(s,decompress,"d");
178
179 PRINTF_CYC_COUNTER(succ_get,"succ get cycles:");
180 PRINTF_CYC_COUNTER(succ_put,"succ put cycles:");
181 PRINTF_CYC_COUNTER(non_succ_get,"failed get cycles:");
182 PRINTF_CYC_COUNTER(non_succ_put,"failed put cycles:");
183 PRINTF_CYC_COUNTER(flush,"flush cycles:");
184 PRINTF_CYC_COUNTER(flush_obj,"flush_obj cycles:");
185 PRINTF_CYC_COUNTER(pg_copy,"page copy cycles:");
186 PRINTF_CYC_COUNTER(compress,"compression cycles:");
187 PRINTF_CYC_COUNTER(decompress,"decompression cycles:");
188 }
189
parse_client(char * s)190 void parse_client(char *s)
191 {
192 unsigned long cli_id = parse(s,"CI");
193 unsigned long weight = parse(s,"ww");
194 unsigned long cap = parse(s,"ca");
195 unsigned long compress = parse(s,"co");
196 unsigned long frozen = parse(s,"fr");
197 unsigned long long eph_count = parse(s,"Ec");
198 unsigned long long max_eph_count = parse(s,"Em");
199 unsigned long long compressed_pages = parse(s,"cp");
200 unsigned long long compressed_sum_size = parse(s,"cb");
201 unsigned long long compress_poor = parse(s,"cn");
202 unsigned long long compress_nomem = parse(s,"cm");
203 unsigned long long total_cycles = parse(s,"Tc");
204 unsigned long long succ_eph_gets = parse(s,"Ge");
205 unsigned long long succ_pers_puts = parse(s,"Pp");
206 unsigned long long succ_pers_gets = parse(s,"Gp");
207
208 printf("domid%lu: weight=%lu,cap=%lu,compress=%d,frozen=%d,"
209 "total_cycles=%llu,succ_eph_gets=%llu,"
210 "succ_pers_puts=%llu,succ_pers_gets=%llu,"
211 "eph_count=%llu,max_eph=%llu,"
212 "compression ratio=%lu%% (samples=%llu,poor=%llu,nomem=%llu)\n",
213 cli_id, weight, cap, compress?1:0, frozen?1:0,
214 total_cycles, succ_eph_gets, succ_pers_puts, succ_pers_gets,
215 eph_count, max_eph_count,
216 compressed_pages ? (long)((compressed_sum_size*100LL) /
217 (compressed_pages*PAGE_SIZE)) : 0,
218 compressed_pages, compress_poor, compress_nomem);
219
220 }
221
parse_pool(char * s)222 void parse_pool(char *s)
223 {
224 char pool_type[3];
225 unsigned long cli_id = parse(s,"CI");
226 unsigned long pool_id = parse(s,"PI");
227 unsigned long long pgp_count = parse(s,"Pc");
228 unsigned long long max_pgp_count = parse(s,"Pm");
229 unsigned long long obj_count = parse(s,"Oc");
230 unsigned long long max_obj_count = parse(s,"Om");
231 unsigned long long objnode_count = parse(s,"Nc");
232 unsigned long long max_objnode_count = parse(s,"Nm");
233 unsigned long long good_puts = parse(s,"ps");
234 unsigned long long puts = parse(s,"pt");
235 unsigned long long no_mem_puts = parse(s,"px");
236 unsigned long long dup_puts_flushed = parse(s,"pd");
237 unsigned long long dup_puts_replaced = parse(s,"pr");
238 unsigned long long found_gets = parse(s,"gs");
239 unsigned long long gets = parse(s,"gt");
240 unsigned long long flushs_found = parse(s,"fs");
241 unsigned long long flushs = parse(s,"ft");
242 unsigned long long flush_objs_found = parse(s,"os");
243 unsigned long long flush_objs = parse(s,"ot");
244
245 parse_string(s,"PT",pool_type,2);
246 pool_type[2] = '\0';
247 if (pool_type[1] == 'S')
248 return; /* no need to repeat print data for shared pools */
249 printf("domid%lu,id%lu[%s]:pgp=%llu(max=%llu) obj=%llu(%llu) "
250 "objnode=%llu(%llu) puts=%llu/%llu/%llu(dup=%llu/%llu) "
251 "gets=%llu/%llu(%llu%%) "
252 "flush=%llu/%llu flobj=%llu/%llu\n",
253 cli_id, pool_id, pool_type,
254 pgp_count, max_pgp_count, obj_count, max_obj_count,
255 objnode_count, max_objnode_count,
256 good_puts, puts, no_mem_puts,
257 dup_puts_flushed, dup_puts_replaced,
258 found_gets, gets,
259 gets ? (found_gets*100LL)/gets : 0,
260 flushs_found, flushs, flush_objs_found, flush_objs);
261
262 }
263
parse_shared_pool(char * s)264 void parse_shared_pool(char *s)
265 {
266 char pool_type[3];
267 char buf[BUFSIZE];
268 unsigned long pool_id = parse(s,"PI");
269 unsigned long long uid0 = parse_hex(s,"U0");
270 unsigned long long uid1 = parse_hex(s,"U1");
271 unsigned long long pgp_count = parse(s,"Pc");
272 unsigned long long max_pgp_count = parse(s,"Pm");
273 unsigned long long obj_count = parse(s,"Oc");
274 unsigned long long max_obj_count = parse(s,"Om");
275 unsigned long long objnode_count = parse(s,"Nc");
276 unsigned long long max_objnode_count = parse(s,"Nm");
277 unsigned long long good_puts = parse(s,"ps");
278 unsigned long long puts = parse(s,"pt");
279 unsigned long long no_mem_puts = parse(s,"px");
280 unsigned long long dup_puts_flushed = parse(s,"pd");
281 unsigned long long dup_puts_replaced = parse(s,"pr");
282 unsigned long long found_gets = parse(s,"gs");
283 unsigned long long gets = parse(s,"gt");
284 unsigned long long flushs_found = parse(s,"fs");
285 unsigned long long flushs = parse(s,"ft");
286 unsigned long long flush_objs_found = parse(s,"os");
287 unsigned long long flush_objs = parse(s,"ot");
288
289 parse_string(s,"PT",pool_type,2);
290 pool_type[2] = '\0';
291 parse_sharers(s,"SC",buf,BUFSIZE);
292 printf("poolid=%lu[%s] uuid=%llx.%llx, shared-by:%s: "
293 "pgp=%llu(max=%llu) obj=%llu(%llu) "
294 "objnode=%llu(%llu) puts=%llu/%llu/%llu(dup=%llu/%llu) "
295 "gets=%llu/%llu(%llu%%) "
296 "flush=%llu/%llu flobj=%llu/%llu\n",
297 pool_id, pool_type, uid0, uid1, buf,
298 pgp_count, max_pgp_count, obj_count, max_obj_count,
299 objnode_count, max_objnode_count,
300 good_puts, puts, no_mem_puts,
301 dup_puts_flushed, dup_puts_replaced,
302 found_gets, gets,
303 gets ? (found_gets*100LL)/gets : 0,
304 flushs_found, flushs, flush_objs_found, flush_objs);
305 }
306
main(int ac,char ** av)307 int main(int ac, char **av)
308 {
309 char *p, c;
310 char buf[BUFSIZE];
311
312 while ( (p = fgets(buf,BUFSIZE,stdin)) != NULL )
313 {
314 c = *p++;
315 if ( *p++ != '=' )
316 continue;
317 switch ( c )
318 {
319 case 'G':
320 parse_global(p);
321 break;
322 case 'T':
323 parse_time_stats(p);
324 break;
325 case 'C':
326 parse_client(p);
327 break;
328 case 'P':
329 parse_pool(p);
330 break;
331 case 'S':
332 parse_shared_pool(p);
333 break;
334 default:
335 continue;
336 }
337 }
338 return 0;
339 }
340