Skip to content

Commit 99a9aa9

Browse files
committed
Track request block sizes in stats filter.
Keep track of every encountered blocksize. This is useful for analyzing client behavior and choosing appropriate plugin options. Example output: total: 1207 ops, 24.756059 s, 25.13 GiB, 1.02 GiB/s read: 101 ops, 0.000322 s, 1.64 MiB, 4.99 GiB/s op, 68.02 KiB/s total write: 1088 ops, 0.067040 s, 132.38 MiB, 1.93 GiB/s op, 5.35 MiB/s total trim: 14 ops, 0.002605 s, 25.00 GiB, 9596.93 GiB/s op, 1.01 GiB/s total flush: 4 ops, 0.000001 s, 0 bytes, 0 bytes/s op, 0 bytes/s total READ Request sizes (top 28): blocksize request count 4096 67 (66.34%) 16384 7 (6.93%) 8192 3 (2.97%) 24576 3 (2.97%) 61440 3 (2.97%) 20480 2 (1.98%) 28672 2 (1.98%) 36864 2 (1.98%) 40960 2 (1.98%) 57344 2 (1.98%) 65536 2 (1.98%) 69632 2 (1.98%) 32768 1 (0.99%) 122880 1 (0.99%) 126976 1 (0.99%) 131072 1 (0.99%) WRITE Request sizes (top 28): blocksize request count 131072 1056 (97.06%) 4096 18 (1.65%) 20480 10 (0.92%) 24576 2 (0.18%) 8192 1 (0.09%) 65536 1 (0.09%) TRIM Request sizes (top 28): blocksize request count 2147483648 12 (85.71%) 16777216 1 (7.14%) 1056964608 1 (7.14%) ZERO Request sizes (top 28): blocksize request count
1 parent 1f5dc06 commit 99a9aa9

File tree

5 files changed

+156
-37
lines changed

5 files changed

+156
-37
lines changed

common/utils/cleanup.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
#ifndef NBDKIT_CLEANUP_H
3434
#define NBDKIT_CLEANUP_H
3535

36+
#ifdef __cplusplus
37+
extern "C" {
38+
#endif
39+
3640
#include <pthread.h>
3741
#include <assert.h>
3842

@@ -90,4 +94,8 @@ struct nbdkit_exports;
9094
extern void cleanup_exports_free (struct nbdkit_exports **ptr);
9195
#define CLEANUP_EXPORTS_FREE __attribute__((cleanup (cleanup_exports_free)))
9296

97+
#ifdef __cplusplus
98+
} /* extern "C" */
99+
#endif
100+
93101
#endif /* NBDKIT_CLEANUP_H */

filters/stats/Makefile.am

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ include $(top_srcdir)/common-rules.mk
3333

3434
EXTRA_DIST = nbdkit-stats-filter.pod
3535

36+
if HAVE_CXX
37+
3638
filter_LTLIBRARIES = nbdkit-stats-filter.la
3739

3840
nbdkit_stats_filter_la_SOURCES = \
39-
stats.c \
41+
stats.cpp \
4042
$(top_srcdir)/include/nbdkit-filter.h \
4143
$(NULL)
4244

@@ -68,3 +70,4 @@ nbdkit-stats-filter.1: nbdkit-stats-filter.pod \
6870
$<
6971

7072
endif HAVE_POD
73+
endif HAVE_CXX

filters/stats/nbdkit-stats-filter.pod

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,55 @@ C<nbdkit-stats-filter> is a filter that displays statistics about NBD
1212
operations, such as the number of bytes read and written. Statistics
1313
are written to a file once when nbdkit exits.
1414

15-
=head1 EXAMPLE
16-
17-
In this example we run L<guestfish(1)> over nbdkit to create an ext4
18-
filesystem on a RAM disk, and use the stats filter to display the
19-
number of read, write and trim operations involved:
20-
21-
$ nbdkit -U - --filter=stats memory 1G statsfile=/dev/stderr \
22-
--run '
23-
guestfish add-drive "" protocol:nbd server:unix:$unixsocket \
24-
discard:enable format:raw : \
25-
run : \
26-
mkfs ext4 /dev/sda
27-
'
28-
total: 370 ops, 1.282993 s, 1.04 GiB, 827.29 MiB/s
29-
read: 250 ops, 0.000364 s, 4.76 MiB, 12.78 GiB/s op, 3.71 MiB/s total
30-
write: 78 ops, 0.175715 s, 32.64 MiB, 185.78 MiB/s op, 25.44 MiB/s total
31-
trim: 33 ops, 0.000252 s, 1.00 GiB, 3968.25 GiB/s op, 798.13 MiB/s total
32-
flush: 9 ops, 0.000002 s, 0 bytes, 0 bytes/s op, 0 bytes/s total
15+
=head1 EXAMPLE OUTPUT
16+
17+
# nbdkit --filter=exitfirst --filter=stats memory 25G statsfile=example.txt
18+
# nbd-client localhost /dev/nbd1 && mkfs.ext4 /dev/nbd1 && nbd-client -d /dev/nbd1
19+
[....]
20+
# cat example.txt
21+
total: 1207 ops, 24.756059 s, 25.13 GiB, 1.02 GiB/s
22+
read: 101 ops, 0.000322 s, 1.64 MiB, 4.99 GiB/s op, 68.02 KiB/s total
23+
write: 1088 ops, 0.067040 s, 132.38 MiB, 1.93 GiB/s op, 5.35 MiB/s total
24+
trim: 14 ops, 0.002605 s, 25.00 GiB, 9596.93 GiB/s op, 1.01 GiB/s total
25+
flush: 4 ops, 0.000001 s, 0 bytes, 0 bytes/s op, 0 bytes/s total
26+
27+
READ Request sizes (top 28):
28+
blocksize request count
29+
4096 67 (66.34%)
30+
16384 7 (6.93%)
31+
8192 3 (2.97%)
32+
24576 3 (2.97%)
33+
61440 3 (2.97%)
34+
20480 2 (1.98%)
35+
28672 2 (1.98%)
36+
36864 2 (1.98%)
37+
40960 2 (1.98%)
38+
57344 2 (1.98%)
39+
65536 2 (1.98%)
40+
69632 2 (1.98%)
41+
32768 1 (0.99%)
42+
122880 1 (0.99%)
43+
126976 1 (0.99%)
44+
131072 1 (0.99%)
45+
46+
WRITE Request sizes (top 28):
47+
blocksize request count
48+
131072 1056 (97.06%)
49+
4096 18 (1.65%)
50+
20480 10 (0.92%)
51+
24576 2 (0.18%)
52+
8192 1 (0.09%)
53+
65536 1 (0.09%)
54+
55+
TRIM Request sizes (top 28):
56+
blocksize request count
57+
2147483648 12 (85.71%)
58+
16777216 1 (7.14%)
59+
1056964608 1 (7.14%)
60+
61+
ZERO Request sizes (top 28):
62+
blocksize request count
63+
3364

3465
=head1 PARAMETERS
3566

filters/stats/stats.c renamed to filters/stats/stats.cpp

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
#include <config.h>
3434

35+
#include <map>
36+
#include <vector>
37+
#include <algorithm>
38+
3539
#include <stdio.h>
3640
#include <stdlib.h>
3741
#include <stdint.h>
@@ -47,6 +51,7 @@
4751
#include <nbdkit-filter.h>
4852

4953
#include "cleanup.h"
54+
5055
#include "tvdiff.h"
5156
#include "windows-compat.h"
5257

@@ -62,6 +67,8 @@ typedef struct {
6267
uint64_t usecs;
6368
} nbdstat;
6469

70+
typedef std::map<size_t, size_t> blksize_hist_t;
71+
6572
/* This lock protects all the stats. */
6673
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
6774
static nbdstat pread_st = { "read" };
@@ -71,6 +78,10 @@ static nbdstat zero_st = { "zero" };
7178
static nbdstat extents_st = { "extents" };
7279
static nbdstat cache_st = { "cache" };
7380
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;
7485

7586
#define KiB 1024
7687
#define MiB 1048576
@@ -143,6 +154,50 @@ print_totals (uint64_t usecs)
143154
free (rate);
144155
}
145156

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, "\nREAD Request sizes (top 28):\n");
185+
fprintf (fp, " blocksize request count\n");
186+
print_histogram (blksize_pread_st, 28);
187+
188+
fprintf (fp, "\nWRITE Request sizes (top 28):\n");
189+
fprintf (fp, " blocksize request count\n");
190+
print_histogram (blksize_pwrite_st, 28);
191+
192+
fprintf (fp, "\nTRIM Request sizes (top 28):\n");
193+
fprintf (fp, " blocksize request count\n");
194+
print_histogram (blksize_trim_st, 28);
195+
196+
fprintf (fp, "\nZERO Request sizes (top 28):\n");
197+
fprintf (fp, " blocksize request count\n");
198+
print_histogram (blksize_zero_st, 28);
199+
}
200+
146201
static inline void
147202
print_stats (int64_t usecs)
148203
{
@@ -154,6 +209,7 @@ print_stats (int64_t usecs)
154209
print_stat (&extents_st, usecs);
155210
print_stat (&cache_st, usecs);
156211
print_stat (&flush_st, usecs);
212+
print_blocksize_stats();
157213
fflush (fp);
158214
}
159215

@@ -268,6 +324,11 @@ stats_pread (nbdkit_next *next,
268324
struct timeval start;
269325
int r;
270326

327+
{
328+
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
329+
blksize_pread_st[count]++;
330+
}
331+
271332
gettimeofday (&start, NULL);
272333
r = next->pread (next, buf, count, offset, flags, err);
273334
if (r == 0) record_stat (&pread_st, count, &start);
@@ -284,6 +345,11 @@ stats_pwrite (nbdkit_next *next,
284345
struct timeval start;
285346
int r;
286347

348+
{
349+
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
350+
blksize_pwrite_st[count]++;
351+
}
352+
287353
gettimeofday (&start, NULL);
288354
r = next->pwrite (next, buf, count, offset, flags, err);
289355
if (r == 0) record_stat (&pwrite_st, count, &start);
@@ -300,6 +366,11 @@ stats_trim (nbdkit_next *next,
300366
struct timeval start;
301367
int r;
302368

369+
{
370+
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
371+
blksize_trim_st[count]++;
372+
}
373+
303374
gettimeofday (&start, NULL);
304375
r = next->trim (next, count, offset, flags, err);
305376
if (r == 0) record_stat (&trim_st, count, &start);
@@ -331,6 +402,11 @@ stats_zero (nbdkit_next *next,
331402
struct timeval start;
332403
int r;
333404

405+
{
406+
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
407+
blksize_zero_st[count]++;
408+
}
409+
334410
gettimeofday (&start, NULL);
335411
r = next->zero (next, count, offset, flags, err);
336412
if (r == 0) record_stat (&zero_st, count, &start);
@@ -373,21 +449,24 @@ stats_cache (nbdkit_next *next,
373449
return r;
374450
}
375451

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+
}();
392471

393472
NBDKIT_REGISTER_FILTER(filter)

plugins/torrent/torrent.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@
5252
#include <libtorrent/torrent_info.hpp>
5353
#include <libtorrent/version.hpp>
5454

55-
extern "C" {
5655
#include "cleanup.h"
57-
};
5856

5957
static bool seen_torrent = false;
6058

0 commit comments

Comments
 (0)