32
32
33
33
#include < config.h>
34
34
35
+ #include < map>
36
+ #include < vector>
37
+ #include < algorithm>
38
+
35
39
#include < stdio.h>
36
40
#include < stdlib.h>
37
41
#include < stdint.h>
47
51
#include < nbdkit-filter.h>
48
52
49
53
#include " cleanup.h"
54
+
50
55
#include " tvdiff.h"
51
56
#include " windows-compat.h"
52
57
@@ -62,6 +67,8 @@ typedef struct {
62
67
uint64_t usecs;
63
68
} nbdstat;
64
69
70
+ typedef std::map<size_t , size_t > blksize_hist_t ;
71
+
65
72
/* This lock protects all the stats. */
66
73
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
67
74
static nbdstat pread_st = { " read" };
@@ -71,6 +78,10 @@ static nbdstat zero_st = { "zero" };
71
78
static nbdstat extents_st = { " extents" };
72
79
static nbdstat cache_st = { " cache" };
73
80
static nbdstat flush_st = { " flush" };
81
+ static blksize_hist_t blksize_pread_st;
82
+ static blksize_hist_t blksize_pwrite_st;
83
+ static blksize_hist_t blksize_trim_st;
84
+ static blksize_hist_t blksize_zero_st;
74
85
75
86
#define KiB 1024
76
87
#define MiB 1048576
@@ -143,6 +154,50 @@ print_totals (uint64_t usecs)
143
154
free (rate);
144
155
}
145
156
157
+ static void
158
+ print_histogram (const blksize_hist_t hist, int count)
159
+ {
160
+ double total = 0 ;
161
+ for (auto el : hist) {
162
+ total += static_cast <double > (el.second );
163
+ }
164
+
165
+ // Sort
166
+ auto pairs = std::vector<std::pair<size_t , size_t >> (hist.begin (), hist.end ());
167
+ std::sort (pairs.begin (), pairs.end (),
168
+ [](decltype (pairs[0 ]) a, decltype (pairs[0 ]) b) {
169
+ return a.second > b.second ;
170
+ });
171
+
172
+ int i = 0 ;
173
+ for (auto el : pairs) {
174
+ if (++i >= count)
175
+ break ;
176
+ fprintf (fp, " %13zu %9zu (%.2f%%)\n " ,
177
+ el.first , el.second , static_cast <double >(el.second ) / total * 100 );
178
+ }
179
+ }
180
+
181
+ static void
182
+ print_blocksize_stats (void )
183
+ {
184
+ fprintf (fp, " \n READ Request sizes (top 28):\n " );
185
+ fprintf (fp, " blocksize request count\n " );
186
+ print_histogram (blksize_pread_st, 28 );
187
+
188
+ fprintf (fp, " \n WRITE Request sizes (top 28):\n " );
189
+ fprintf (fp, " blocksize request count\n " );
190
+ print_histogram (blksize_pwrite_st, 28 );
191
+
192
+ fprintf (fp, " \n TRIM Request sizes (top 28):\n " );
193
+ fprintf (fp, " blocksize request count\n " );
194
+ print_histogram (blksize_trim_st, 28 );
195
+
196
+ fprintf (fp, " \n ZERO Request sizes (top 28):\n " );
197
+ fprintf (fp, " blocksize request count\n " );
198
+ print_histogram (blksize_zero_st, 28 );
199
+ }
200
+
146
201
static inline void
147
202
print_stats (int64_t usecs)
148
203
{
@@ -154,6 +209,7 @@ print_stats (int64_t usecs)
154
209
print_stat (&extents_st, usecs);
155
210
print_stat (&cache_st, usecs);
156
211
print_stat (&flush_st, usecs);
212
+ print_blocksize_stats ();
157
213
fflush (fp);
158
214
}
159
215
@@ -268,6 +324,11 @@ stats_pread (nbdkit_next *next,
268
324
struct timeval start;
269
325
int r;
270
326
327
+ {
328
+ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
329
+ blksize_pread_st[count]++;
330
+ }
331
+
271
332
gettimeofday (&start, NULL );
272
333
r = next->pread (next, buf, count, offset, flags, err);
273
334
if (r == 0 ) record_stat (&pread_st, count, &start);
@@ -284,6 +345,11 @@ stats_pwrite (nbdkit_next *next,
284
345
struct timeval start;
285
346
int r;
286
347
348
+ {
349
+ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
350
+ blksize_pwrite_st[count]++;
351
+ }
352
+
287
353
gettimeofday (&start, NULL );
288
354
r = next->pwrite (next, buf, count, offset, flags, err);
289
355
if (r == 0 ) record_stat (&pwrite_st, count, &start);
@@ -300,6 +366,11 @@ stats_trim (nbdkit_next *next,
300
366
struct timeval start;
301
367
int r;
302
368
369
+ {
370
+ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
371
+ blksize_trim_st[count]++;
372
+ }
373
+
303
374
gettimeofday (&start, NULL );
304
375
r = next->trim (next, count, offset, flags, err);
305
376
if (r == 0 ) record_stat (&trim_st, count, &start);
@@ -331,6 +402,11 @@ stats_zero (nbdkit_next *next,
331
402
struct timeval start;
332
403
int r;
333
404
405
+ {
406
+ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
407
+ blksize_zero_st[count]++;
408
+ }
409
+
334
410
gettimeofday (&start, NULL );
335
411
r = next->zero (next, count, offset, flags, err);
336
412
if (r == 0 ) record_stat (&zero_st, count, &start);
@@ -373,21 +449,24 @@ stats_cache (nbdkit_next *next,
373
449
return r;
374
450
}
375
451
376
- static struct nbdkit_filter filter = {
377
- .name = "stats" ,
378
- .longname = "nbdkit stats filter" ,
379
- .unload = stats_unload ,
380
- .config = stats_config ,
381
- .config_complete = stats_config_complete ,
382
- .config_help = stats_config_help ,
383
- .get_ready = stats_get_ready ,
384
- .pread = stats_pread ,
385
- .pwrite = stats_pwrite ,
386
- .trim = stats_trim ,
387
- .flush = stats_flush ,
388
- .zero = stats_zero ,
389
- .extents = stats_extents ,
390
- .cache = stats_cache ,
391
- };
452
+ static struct nbdkit_filter filter = []() -> nbdkit_filter {
453
+ auto f = nbdkit_filter ();
454
+ f.name = " stats" ;
455
+ f.longname = " nbdkit stats filter" ;
456
+ f.unload = stats_unload;
457
+ f.config = stats_config;
458
+ f.config_complete = stats_config_complete;
459
+ f.config_help = stats_config_help;
460
+ f.get_ready = stats_get_ready;
461
+ f.pread = stats_pread;
462
+ f.pwrite = stats_pwrite;
463
+ f.flush = stats_flush;
464
+ f.trim = stats_trim;
465
+ f.zero = stats_zero;
466
+ f.extents = stats_extents;
467
+ f.cache = stats_cache;
468
+
469
+ return f;
470
+ }();
392
471
393
472
NBDKIT_REGISTER_FILTER (filter)
0 commit comments