Skip to contentSkip to conversation

block latency histogram

PATCH Superseded Vladimir Sementsov-Ogievskiy 2 participants 7 messages Feb 6, 2018 – Feb 7, 2018 Block layer

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

cover block latency histogram

Vladimir Sementsov-Ogievskiy (2):
block/accounting: introduce latency histogram
qapi: add block latency histogram interface

 qapi/block-core.json       | 62 +++++++++++++++++++++++++++++++++-
 include/block/accounting.h |  8 +++++
 block/accounting.c         | 83 ++++++++++++++++++++++++++++++++++++++++++++++
 block/qapi.c               | 31 +++++++++++++++++
 blockdev.c                 | 15 +++++++++
 5 files changed, 198 insertions(+), 1 deletion(-)
Signature · 1 line
2.11.1
#1 lore raw

PATCH 1/2 block/accounting: introduce latency histogram

Introduce latency histogram statics for block devices. For each accounted operation type latency region [0, +inf) is divided into subregions by several points. Then, calculate hits for each subregion.

---
 include/block/accounting.h |  8 +++++
 block/accounting.c         | 83 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)
include/block/accounting.h +8 -0
index b833d26d6c..7fbfc86c43 100644
@@ -45,6 +45,12 @@ struct BlockAcctTimedStats {
     QSLIST_ENTRY(BlockAcctTimedStats) entries;
 };
 
+typedef struct BlockLatencyHistogram {
+    int size;
+    uint64_t *points; /* @size-1 points here (all points, except 0 and +inf) */
+    uint64_t *histogram[BLOCK_MAX_IOTYPE]; /* @size elements for each type */
+} BlockLatencyHistogram;
+
 struct BlockAcctStats {
     QemuMutex lock;
     uint64_t nr_bytes[BLOCK_MAX_IOTYPE];
@@ -57,6 +63,7 @@ struct BlockAcctStats {
     QSLIST_HEAD(, BlockAcctTimedStats) intervals;
     bool account_invalid;
     bool account_failed;
+    BlockLatencyHistogram latency_histogram;
 };
 
 typedef struct BlockAcctCookie {
@@ -82,5 +89,6 @@ void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type,
 int64_t block_acct_idle_time_ns(BlockAcctStats *stats);
 double block_acct_queue_depth(BlockAcctTimedStats *stats,
                               enum BlockAcctType type);
+int block_latency_histogram_set(BlockAcctStats *stats, uint64List *latency);
 
 #endif
block/accounting.c +83 -0

95 lines not on this page · raw message

Signature · 1 line
2.11.1
#2 lore raw

PATCH 2/2 qapi: add block latency histogram interface

In reply to Vladimir Sementsov-Ogievskiy

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

---
 qapi/block-core.json | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 block/qapi.c         | 31 ++++++++++++++++++++++++++
 blockdev.c           | 15 +++++++++++++
 3 files changed, 107 insertions(+), 1 deletion(-)
qapi/block-core.json +61 -1
index 8225308904..4706a934d9 100644
@@ -451,6 +451,63 @@
            'status': 'DirtyBitmapStatus'} }
 
 ##
+# @BlockLatencyHistogramInfo:
+#
+# Block latency histogram.
+#
+# @latency: list of latency points in microseconds. Equals to @latency parameter
+#           of last called block-latency-histogram-set.
+#
+# @read: list of read-request counts corresponding to latency region.
+#        len(@read) = len(@latency) + 1
+#        @read[0] corresponds to latency region [0, @latency[0])
+#        for 0 < i < len(@latency): @read[i] corresponds to latency region
+#            [@latency[i-1], @latency[i])
+#        @read.last_element corresponds to latency region
+#            [@latency.last_element, +inf)
+#
+# @write: list of write-request counts (see @read semantics)
+#
+# @flush: list of flush-request counts (see @read semantics)
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockLatencyHistogramInfo',
+  'data': {'latency': ['uint64'],
+           'read': ['uint64'],
+           'write': ['uint64'],
+           'flush': ['uint64'] } }
+
+##
+# @block-latency-histogram-set:
+#
+# Add latency histogram to block device. If latency histogram alredy exists for
+# the device it will be removed and a new one created. Latency histogram may be
+# quered through query-blockstats.
+#
+# @device: device name to set latency histogram for.
+#
+# @latency: list of latency points in microseconds. The sequcence must be
+#           ascending, elements must be greater than zero. Histogram latency
+#           regions would be
+#           [0, @latency[0]), ..., [@latency[i], @latency[i+1]), ...,
+#           [@latency.last_element, +inf)
+#
+# Returns: error if device is not found.
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "block-latency-histogram-set",
+#      "arguments": { "device": "drive0",
+#                     "latency": [500000, 1000000, 2000000] } }
+# <- { "return": {} }
+##
+{ 'command': 'block-latency-histogram-set',
+  'data': {'device': 'str', 'latency': ['uint64'] } }
+
+##
 # @BlockInfo:
 #
 # Block device information.  This structure describes a virtual device and
@@ -730,6 +787,8 @@
 # @timed_stats: Statistics specific to the set of previously defined
 #               intervals of time (Since 2.5)
 #
+# @latency-histogram: @BlockLatencyHistogramInfo. (Since 2.12)
+#
 # Since: 0.14.0
 ##
 { 'struct': 'BlockDeviceStats',
@@ -742,7 +801,8 @@
            'failed_flush_operations': 'int', 'invalid_rd_operations': 'int',
            'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int',
            'account_invalid': 'bool', 'account_failed': 'bool',
-           'timed_stats': ['BlockDeviceTimedStats'] } }
+           'timed_stats': ['BlockDeviceTimedStats'],
+           '*latency-histogram': 'BlockLatencyHistogramInfo' } }
 
 ##
 # @BlockStats:
block/qapi.c +31 -0
index fc10f0a565..715ed17a6b 100644
@@ -389,6 +389,24 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
     qapi_free_BlockInfo(info);
 }
 
+static uint64List *uint64_list(uint64_t *list, int size)
+{
+    int i;
+    uint64List *out_list = NULL;
+    uint64List **pout_list = &out_list;
+
+    for (i = 0; i < size; i++) {
+        uint64List *entry = g_new(uint64List, 1);
+        entry->value = list[i];
+        *pout_list = entry;
+        pout_list = &entry->next;
+    }
+
+    *pout_list = NULL;
+
+    return out_list;
+}
+
 static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
 {
     BlockAcctStats *stats = blk_get_stats(blk);
@@ -454,6 +472,19 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
         dev_stats->avg_wr_queue_depth =
             block_acct_queue_depth(ts, BLOCK_ACCT_WRITE);
     }
+
+    ds->has_latency_histogram = stats->latency_histogram.points != NULL;
+    if (ds->has_latency_histogram) {
+        BlockLatencyHistogramInfo *info = g_new0(BlockLatencyHistogramInfo, 1);
+        BlockLatencyHistogram *h = &stats->latency_histogram;
+
+        ds->latency_histogram = info;
+
+        info->latency = uint64_list(h->points, h->size - 1);
+        info->read = uint64_list(h->histogram[BLOCK_ACCT_READ], h->size);
+        info->write = uint64_list(h->histogram[BLOCK_ACCT_WRITE], h->size);
+        info->flush = uint64_list(h->histogram[BLOCK_ACCT_FLUSH], h->size);
+    }
 }
 
 static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,
blockdev.c +15 -0
index 8e977eef11..dbf17aca0c 100644
@@ -4176,6 +4176,21 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
     aio_context_release(old_context);
 }
 
+void qmp_block_latency_histogram_set(const char *device, uint64List *latency,
+                                     Error **errp)
+{
+    BlockBackend *blk = blk_by_name(device);
+    if (!blk) {
+        error_setg(errp, "Device '%s' not found", device);
+        return;
+    }
+
+    if (block_latency_histogram_set(blk_get_stats(blk), latency) < 0) {
+        error_setg(errp, "Invalid latency array");
+        return;
+    }
+}
+
 QemuOptsList qemu_common_drive_opts = {
     .name = "drive",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
Signature · 1 line
2.11.1
#3 lore raw

Re: [Qemu-devel] [PATCH 2/2] qapi: add block latency histogram interface

Quoted 16 lines · Vladimir Sementsov-Ogievskiy

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

---
  qapi/block-core.json | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++-
  block/qapi.c         | 31 ++++++++++++++++++++++++++
  blockdev.c           | 15 +++++++++++++
  3 files changed, 107 insertions(+), 1 deletion(-)
qapi/block-core.json +0 -0
index 8225308904..4706a934d9 100644

qapi/block-core.json line 459

Quoted 9 lines
qapi/block-core.json +6 -0
@@ -451,6 +451,63 @@
             'status': 'DirtyBitmapStatus'} }
 
  ##
+# @BlockLatencyHistogramInfo:
+#
+# Block latency histogram.
+#
+# @latency: list of latency points in microseconds. Equals to @latency parameter
+#           of last called block-latency-histogram-set.

Second sentence might read better as:

Matches the @latency parameter from the last call to block-latency-histogram-set for the given device.

Quoted 10 lines
qapi/block-core.json +10 -0
+#
+# @read: list of read-request counts corresponding to latency region.
+#        len(@read) = len(@latency) + 1
+#        @read[0] corresponds to latency region [0, @latency[0])
+#        for 0 < i < len(@latency): @read[i] corresponds to latency region
+#            [@latency[i-1], @latency[i])
+#        @read.last_element corresponds to latency region
+#            [@latency.last_element, +inf)
+#
+# @write: list of write-request counts (see @read semantics)

qapi/block-core.json line 479

Quoted 10 lines
qapi/block-core.json +10 -0
+#
+# @flush: list of flush-request counts (see @read semantics)
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockLatencyHistogramInfo',
+  'data': {'latency': ['uint64'],
+           'read': ['uint64'],
+           'write': ['uint64'],
+           'flush': ['uint64'] } }

Okay, I can see how this interface works.

qapi/block-core.json line 484

Quoted 5 lines
qapi/block-core.json +5 -0
+
+##
+# @block-latency-histogram-set:
+#
+# Add latency histogram to block device. If latency histogram alredy exists for

s/latency/a latency/ (twice)
s/alredy/already/

qapi/block-core.json line 485

Quoted 1 line
qapi/block-core.json +1 -0
+# the device it will be removed and a new one created. Latency histogram may be

s/Latency/The latency/

qapi/block-core.json line 486

Quoted 1 line
qapi/block-core.json +1 -0
+# quered through query-blockstats.

s/quered/queried/

qapi/block-core.json line 490

Quoted 4 lines
qapi/block-core.json +4 -0
+#
+# @device: device name to set latency histogram for.
+#
+# @latency: list of latency points in microseconds. The sequcence must be

s/sequcence/sequence/

Quoted 8 lines
qapi/block-core.json +8 -0
+#           ascending, elements must be greater than zero. Histogram latency
+#           regions would be
+#           [0, @latency[0]), ..., [@latency[i], @latency[i+1]), ...,
+#           [@latency.last_element, +inf)
+#
+# Returns: error if device is not found.
+#
+# Since: 2.12

qapi/block-core.json line 508

Quoted 10 lines
qapi/block-core.json +10 -0
+#
+# Example:
+#
+# -> { "execute": "block-latency-histogram-set",
+#      "arguments": { "device": "drive0",
+#                     "latency": [500000, 1000000, 2000000] } }
+# <- { "return": {} }
+##
+{ 'command': 'block-latency-histogram-set',
+  'data': {'device': 'str', 'latency': ['uint64'] } }

The commit message mentioned that you can set and clear histogram tracking; how does this interface let you clear things? By passing a 0-length latency array? If you violate the constraint (pass non-ascending points, for example), does the previous latency map get wiped out or is it still preserved unchanged?

qapi/block-core.json line 790

Quoted 10 lines
qapi/block-core.json +3 -0
+
+##
  # @BlockInfo:
  #
  # Block device information.  This structure describes a virtual device and
@@ -730,6 +787,8 @@
  # @timed_stats: Statistics specific to the set of previously defined
  #               intervals of time (Since 2.5)
  #
+# @latency-histogram: @BlockLatencyHistogramInfo. (Since 2.12)

I'd mention that this only appears if block-latency-histogram-set has been called.

Quoted 12 lines
qapi/block-core.json +3 -1
+#
  # Since: 0.14.0
  ##
  { 'struct': 'BlockDeviceStats',
@@ -742,7 +801,8 @@
             'failed_flush_operations': 'int', 'invalid_rd_operations': 'int',
             'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int',
             'account_invalid': 'bool', 'account_failed': 'bool',
-           'timed_stats': ['BlockDeviceTimedStats'] } }
+           'timed_stats': ['BlockDeviceTimedStats'],
+           '*latency-histogram': 'BlockLatencyHistogramInfo' } }
 
Signature · 3 lines
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org
#4 lore raw

Re: [Qemu-devel] [PATCH 2/2] qapi: add block latency histogram interface

Quoted 96 lines · Eric Blake
Quoted 24 lines · Vladimir Sementsov-Ogievskiy

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

---
  qapi/block-core.json | 62
+++++++++++++++++++++++++++++++++++++++++++++++++++-
  block/qapi.c         | 31 ++++++++++++++++++++++++++ blockdev.c           | 15 +++++++++++++

  3 files changed, 107 insertions(+), 1 deletion(-)
qapi/block-core.json +5 -0
index 8225308904..4706a934d9 100644
@@ -451,6 +451,63 @@
              'status': 'DirtyBitmapStatus'} }
     ##
+# @BlockLatencyHistogramInfo:
+#
+# Block latency histogram.
+#
+# @latency: list of latency points in microseconds. Equals to 
Quoted 2 lines

@latency parameter
+#           of last called block-latency-histogram-set.

Second sentence might read better as:

Matches the @latency parameter from the last call to block-latency-histogram-set for the given device.

Quoted 11 lines
qapi/block-core.json +5 -0
+#
+# @read: list of read-request counts corresponding to latency region.
+#        len(@read) = len(@latency) + 1
+#        @read[0] corresponds to latency region [0, @latency[0])
+#        for 0 < i < len(@latency): @read[i] corresponds to latency 

region

qapi/block-core.json +5 -0
+#            [@latency[i-1], @latency[i])
+#        @read.last_element corresponds to latency region
+#            [@latency.last_element, +inf)
+#
+# @write: list of write-request counts (see @read semantics)

qapi/block-core.json line 479

Quoted 10 lines
qapi/block-core.json +10 -0
+#
+# @flush: list of flush-request counts (see @read semantics)
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockLatencyHistogramInfo',
+  'data': {'latency': ['uint64'],
+           'read': ['uint64'],
+           'write': ['uint64'],
+           'flush': ['uint64'] } }

Okay, I can see how this interface works.

Quoted 6 lines
qapi/block-core.json +5 -0
+
+##
+# @block-latency-histogram-set:
+#
+# Add latency histogram to block device. If latency histogram alredy 

exists for

s/latency/a latency/ (twice)
s/alredy/already/

Quoted 2 lines

+# the device it will be removed and a new one created. Latency histogram may be

s/Latency/The latency/

Quoted 1 line

+# quered through query-blockstats.

s/quered/queried/

Quoted 5 lines
qapi/block-core.json +4 -0
+#
+# @device: device name to set latency histogram for.
+#
+# @latency: list of latency points in microseconds. The sequcence 

must be

s/sequcence/sequence/

Quoted 13 lines

+#           ascending, elements must be greater than zero. Histogram latency

qapi/block-core.json +11 -0
+#           regions would be
+#           [0, @latency[0]), ..., [@latency[i], @latency[i+1]), ...,
+#           [@latency.last_element, +inf)
+#
+# Returns: error if device is not found.
+#
+# Since: 2.12
+#
+# Example:
+#
+# -> { "execute": "block-latency-histogram-set",
Quoted 8 lines

qapi/block-core.json line 508

Quoted 6 lines
qapi/block-core.json +6 -0
+#      "arguments": { "device": "drive0",
+#                     "latency": [500000, 1000000, 2000000] } }
+# <- { "return": {} }
+##
+{ 'command': 'block-latency-histogram-set',
+  'data': {'device': 'str', 'latency': ['uint64'] } }

The commit message mentioned that you can set and clear histogram tracking; how does this interface let you clear things?  By passing a 0-length latency array?  If you violate the constraint (pass non-ascending points, for example), does the previous latency map get wiped out or is it still preserved unchanged?

On error nothing is changed.

By "clear" I mean zeroing statistics, not removing the whole histogram. And to zero statistics you can call set with the same latency array. There is no way to remove histogram at all.. We can add block-latency-histogram-unset later if needed.

Quoted 13 lines

qapi/block-core.json line 790

Quoted 11 lines
qapi/block-core.json +2 -0
+
+##

  # @BlockInfo:
  #
  # Block device information.  This structure describes a virtual device and

qapi/block-core.json +1 -0
@@ -730,6 +787,8 @@
   # @timed_stats: Statistics specific to the set of previously defined
   #               intervals of time (Since 2.5)
   #
+# @latency-histogram: @BlockLatencyHistogramInfo. (Since 2.12)

I'd mention that this only appears if block-latency-histogram-set has been called.

yes

Quoted 14 lines
Quoted 12 lines
qapi/block-core.json +3 -1
+#
   # Since: 0.14.0
   ##
   { 'struct': 'BlockDeviceStats',
@@ -742,7 +801,8 @@
              'failed_flush_operations': 'int', 'invalid_rd_operations': 'int',
              'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int',
              'account_invalid': 'bool', 'account_failed': 'bool',
-           'timed_stats': ['BlockDeviceTimedStats'] } }
+           'timed_stats': ['BlockDeviceTimedStats'],
+           '*latency-histogram': 'BlockLatencyHistogramInfo' } }
Signature · 2 lines
Best regards,
Vladimir
#5 lore raw

Re: [Qemu-devel] [PATCH 2/2] qapi: add block latency histogram interface

Quoted 7 lines · Vladimir Sementsov-Ogievskiy
Quoted 6 lines · Eric Blake
Quoted 4 lines · Vladimir Sementsov-Ogievskiy

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

Quoted 6 lines
Quoted 1 line

The commit message mentioned that you can set and clear histogram tracking; how does this interface let you clear things?  By passing a 0-length latency array?  If you violate the constraint (pass non-ascending points, for example), does the previous latency map get wiped out or is it still preserved unchanged?

On error nothing is changed.

By "clear" I mean zeroing statistics, not removing the whole histogram. And to zero statistics you can call set with the same latency array. There is no way to remove histogram at all.. We can add block-latency-histogram-unset later if needed.

Maybe "set (or restart) histogram collection points" might read better? I also don't think we need a new command; if you make 'latency' optional, then omitting it can serve to stop collecting statistics altogether, without needing a new command (then again, if you do that, now the command is used to "set, restart, and clear histogram collection").

Signature · 3 lines
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org
#6 lore raw

Re: [Qemu-devel] [PATCH 2/2] qapi: add block latency histogram interface

Quoted 8 lines · Eric Blake
Quoted 7 lines · Vladimir Sementsov-Ogievskiy
Quoted 6 lines · Eric Blake
Quoted 4 lines · Vladimir Sementsov-Ogievskiy

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

Quoted 9 lines
Quoted 6 lines
Quoted 1 line

The commit message mentioned that you can set and clear histogram tracking; how does this interface let you clear things?  By passing a 0-length latency array?  If you violate the constraint (pass non-ascending points, for example), does the previous latency map get wiped out or is it still preserved unchanged?

On error nothing is changed.

By "clear" I mean zeroing statistics, not removing the whole histogram. And to zero statistics you can call set with the same latency array. There is no way to remove histogram at all.. We can add block-latency-histogram-unset later if needed.

Maybe "set (or restart) histogram collection points" might read better? I also don't think we need a new command; if you make 'latency' optional, then omitting it can serve to stop collecting statistics altogether, without needing a new command (then again, if you do that, now the command is used to "set, restart, and clear histogram collection").

I like the idea, will do.

Signature · 2 lines
Best regards,
Vladimir