qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

qapi: add block latency histogram interface

Set (and clear) histograms through new command
block-latency-histogram-set and show new statistics in
query-blockstats results.

For now, the command is marked experimental with prefix 'x-',
to gain experience with the interface without being stuck
with design decisions.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20180309165212.97144-3-vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
[eblake: fix typos, mention x- prefix in commit message]
Signed-off-by: Eric Blake <eblake@redhat.com>

authored by

Vladimir Sementsov-Ogievskiy and committed by
Eric Blake
7e5c776d b741ae74

+194 -1
+41
block/qapi.c
··· 394 394 qapi_free_BlockInfo(info); 395 395 } 396 396 397 + static uint64List *uint64_list(uint64_t *list, int size) 398 + { 399 + int i; 400 + uint64List *out_list = NULL; 401 + uint64List **pout_list = &out_list; 402 + 403 + for (i = 0; i < size; i++) { 404 + uint64List *entry = g_new(uint64List, 1); 405 + entry->value = list[i]; 406 + *pout_list = entry; 407 + pout_list = &entry->next; 408 + } 409 + 410 + *pout_list = NULL; 411 + 412 + return out_list; 413 + } 414 + 415 + static void bdrv_latency_histogram_stats(BlockLatencyHistogram *hist, 416 + bool *not_null, 417 + BlockLatencyHistogramInfo **info) 418 + { 419 + *not_null = hist->bins != NULL; 420 + if (*not_null) { 421 + *info = g_new0(BlockLatencyHistogramInfo, 1); 422 + 423 + (*info)->boundaries = uint64_list(hist->boundaries, hist->nbins - 1); 424 + (*info)->bins = uint64_list(hist->bins, hist->nbins); 425 + } 426 + } 427 + 397 428 static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) 398 429 { 399 430 BlockAcctStats *stats = blk_get_stats(blk); ··· 459 490 dev_stats->avg_wr_queue_depth = 460 491 block_acct_queue_depth(ts, BLOCK_ACCT_WRITE); 461 492 } 493 + 494 + bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_READ], 495 + &ds->has_x_rd_latency_histogram, 496 + &ds->x_rd_latency_histogram); 497 + bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_WRITE], 498 + &ds->has_x_wr_latency_histogram, 499 + &ds->x_wr_latency_histogram); 500 + bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_FLUSH], 501 + &ds->has_x_flush_latency_histogram, 502 + &ds->x_flush_latency_histogram); 462 503 } 463 504 464 505 static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,
+43
blockdev.c
··· 4239 4239 aio_context_release(old_context); 4240 4240 } 4241 4241 4242 + void qmp_x_block_latency_histogram_set( 4243 + const char *device, 4244 + bool has_boundaries, uint64List *boundaries, 4245 + bool has_boundaries_read, uint64List *boundaries_read, 4246 + bool has_boundaries_write, uint64List *boundaries_write, 4247 + bool has_boundaries_flush, uint64List *boundaries_flush, 4248 + Error **errp) 4249 + { 4250 + BlockBackend *blk = blk_by_name(device); 4251 + BlockAcctStats *stats; 4252 + 4253 + if (!blk) { 4254 + error_setg(errp, "Device '%s' not found", device); 4255 + return; 4256 + } 4257 + stats = blk_get_stats(blk); 4258 + 4259 + if (!has_boundaries && !has_boundaries_read && !has_boundaries_write && 4260 + !has_boundaries_flush) 4261 + { 4262 + block_latency_histograms_clear(stats); 4263 + return; 4264 + } 4265 + 4266 + if (has_boundaries || has_boundaries_read) { 4267 + block_latency_histogram_set( 4268 + stats, BLOCK_ACCT_READ, 4269 + has_boundaries_read ? boundaries_read : boundaries); 4270 + } 4271 + 4272 + if (has_boundaries || has_boundaries_write) { 4273 + block_latency_histogram_set( 4274 + stats, BLOCK_ACCT_WRITE, 4275 + has_boundaries_write ? boundaries_write : boundaries); 4276 + } 4277 + 4278 + if (has_boundaries || has_boundaries_flush) { 4279 + block_latency_histogram_set( 4280 + stats, BLOCK_ACCT_FLUSH, 4281 + has_boundaries_flush ? boundaries_flush : boundaries); 4282 + } 4283 + } 4284 + 4242 4285 QemuOptsList qemu_common_drive_opts = { 4243 4286 .name = "drive", 4244 4287 .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
+110 -1
qapi/block-core.json
··· 454 454 'status': 'DirtyBitmapStatus'} } 455 455 456 456 ## 457 + # @BlockLatencyHistogramInfo: 458 + # 459 + # Block latency histogram. 460 + # 461 + # @boundaries: list of interval boundary values in nanoseconds, all greater 462 + # than zero and in ascending order. 463 + # For example, the list [10, 50, 100] produces the following 464 + # histogram intervals: [0, 10), [10, 50), [50, 100), [100, +inf). 465 + # 466 + # @bins: list of io request counts corresponding to histogram intervals. 467 + # len(@bins) = len(@boundaries) + 1 468 + # For the example above, @bins may be something like [3, 1, 5, 2], 469 + # and corresponding histogram looks like: 470 + # 471 + # 5| * 472 + # 4| * 473 + # 3| * * 474 + # 2| * * * 475 + # 1| * * * * 476 + # +------------------ 477 + # 10 50 100 478 + # 479 + # Since: 2.12 480 + ## 481 + { 'struct': 'BlockLatencyHistogramInfo', 482 + 'data': {'boundaries': ['uint64'], 'bins': ['uint64'] } } 483 + 484 + ## 485 + # @x-block-latency-histogram-set: 486 + # 487 + # Manage read, write and flush latency histograms for the device. 488 + # 489 + # If only @device parameter is specified, remove all present latency histograms 490 + # for the device. Otherwise, add/reset some of (or all) latency histograms. 491 + # 492 + # @device: device name to set latency histogram for. 493 + # 494 + # @boundaries: list of interval boundary values (see description in 495 + # BlockLatencyHistogramInfo definition). If specified, all 496 + # latency histograms are removed, and empty ones created for all 497 + # io types with intervals corresponding to @boundaries (except for 498 + # io types, for which specific boundaries are set through the 499 + # following parameters). 500 + # 501 + # @boundaries-read: list of interval boundary values for read latency 502 + # histogram. If specified, old read latency histogram is 503 + # removed, and empty one created with intervals 504 + # corresponding to @boundaries-read. The parameter has higher 505 + # priority then @boundaries. 506 + # 507 + # @boundaries-write: list of interval boundary values for write latency 508 + # histogram. 509 + # 510 + # @boundaries-flush: list of interval boundary values for flush latency 511 + # histogram. 512 + # 513 + # Returns: error if device is not found or any boundary arrays are invalid. 514 + # 515 + # Since: 2.12 516 + # 517 + # Example: set new histograms for all io types with intervals 518 + # [0, 10), [10, 50), [50, 100), [100, +inf): 519 + # 520 + # -> { "execute": "block-latency-histogram-set", 521 + # "arguments": { "device": "drive0", 522 + # "boundaries": [10, 50, 100] } } 523 + # <- { "return": {} } 524 + # 525 + # Example: set new histogram only for write, other histograms will remain 526 + # not changed (or not created): 527 + # 528 + # -> { "execute": "block-latency-histogram-set", 529 + # "arguments": { "device": "drive0", 530 + # "boundaries-write": [10, 50, 100] } } 531 + # <- { "return": {} } 532 + # 533 + # Example: set new histograms with the following intervals: 534 + # read, flush: [0, 10), [10, 50), [50, 100), [100, +inf) 535 + # write: [0, 1000), [1000, 5000), [5000, +inf) 536 + # 537 + # -> { "execute": "block-latency-histogram-set", 538 + # "arguments": { "device": "drive0", 539 + # "boundaries": [10, 50, 100], 540 + # "boundaries-write": [1000, 5000] } } 541 + # <- { "return": {} } 542 + # 543 + # Example: remove all latency histograms: 544 + # 545 + # -> { "execute": "block-latency-histogram-set", 546 + # "arguments": { "device": "drive0" } } 547 + # <- { "return": {} } 548 + ## 549 + { 'command': 'x-block-latency-histogram-set', 550 + 'data': {'device': 'str', 551 + '*boundaries': ['uint64'], 552 + '*boundaries-read': ['uint64'], 553 + '*boundaries-write': ['uint64'], 554 + '*boundaries-flush': ['uint64'] } } 555 + 556 + ## 457 557 # @BlockInfo: 458 558 # 459 559 # Block device information. This structure describes a virtual device and ··· 733 833 # @timed_stats: Statistics specific to the set of previously defined 734 834 # intervals of time (Since 2.5) 735 835 # 836 + # @x_rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12) 837 + # 838 + # @x_wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12) 839 + # 840 + # @x_flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12) 841 + # 736 842 # Since: 0.14.0 737 843 ## 738 844 { 'struct': 'BlockDeviceStats', ··· 745 851 'failed_flush_operations': 'int', 'invalid_rd_operations': 'int', 746 852 'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int', 747 853 'account_invalid': 'bool', 'account_failed': 'bool', 748 - 'timed_stats': ['BlockDeviceTimedStats'] } } 854 + 'timed_stats': ['BlockDeviceTimedStats'], 855 + '*x_rd_latency_histogram': 'BlockLatencyHistogramInfo', 856 + '*x_wr_latency_histogram': 'BlockLatencyHistogramInfo', 857 + '*x_flush_latency_histogram': 'BlockLatencyHistogramInfo' } } 749 858 750 859 ## 751 860 # @BlockStats: