15e5a94b6SBenoît Canet /* 25e5a94b6SBenoît Canet * QEMU System Emulator block accounting 35e5a94b6SBenoît Canet * 45e5a94b6SBenoît Canet * Copyright (c) 2011 Christoph Hellwig 5aece5edcSAlberto Garcia * Copyright (c) 2015 Igalia, S.L. 65e5a94b6SBenoît Canet * 75e5a94b6SBenoît Canet * Permission is hereby granted, free of charge, to any person obtaining a copy 85e5a94b6SBenoît Canet * of this software and associated documentation files (the "Software"), to deal 95e5a94b6SBenoît Canet * in the Software without restriction, including without limitation the rights 105e5a94b6SBenoît Canet * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 115e5a94b6SBenoît Canet * copies of the Software, and to permit persons to whom the Software is 125e5a94b6SBenoît Canet * furnished to do so, subject to the following conditions: 135e5a94b6SBenoît Canet * 145e5a94b6SBenoît Canet * The above copyright notice and this permission notice shall be included in 155e5a94b6SBenoît Canet * all copies or substantial portions of the Software. 165e5a94b6SBenoît Canet * 175e5a94b6SBenoît Canet * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 185e5a94b6SBenoît Canet * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 195e5a94b6SBenoît Canet * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 205e5a94b6SBenoît Canet * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 215e5a94b6SBenoît Canet * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 225e5a94b6SBenoît Canet * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 235e5a94b6SBenoît Canet * THE SOFTWARE. 245e5a94b6SBenoît Canet */ 255e5a94b6SBenoît Canet 2680c71a24SPeter Maydell #include "qemu/osdep.h" 275e5a94b6SBenoît Canet #include "block/accounting.h" 285e5a94b6SBenoît Canet #include "block/block_int.h" 29a56ebc6bSPaolo Bonzini #include "qemu/timer.h" 30*32cad1ffSPhilippe Mathieu-Daudé #include "system/qtest.h" 315e5a94b6SBenoît Canet 325519593cSAlberto Garcia static QEMUClockType clock_type = QEMU_CLOCK_REALTIME; 33918a17a4SAlberto Garcia static const int qtest_latency_ns = NANOSECONDS_PER_SECOND / 1000; 345519593cSAlberto Garcia 359caa6f3dSPaolo Bonzini void block_acct_init(BlockAcctStats *stats) 369caa6f3dSPaolo Bonzini { 375b50bf77SPaolo Bonzini qemu_mutex_init(&stats->lock); 389caa6f3dSPaolo Bonzini if (qtest_enabled()) { 399caa6f3dSPaolo Bonzini clock_type = QEMU_CLOCK_VIRTUAL; 409caa6f3dSPaolo Bonzini } 4162a6c300SDenis V. Lunev stats->account_invalid = true; 4262a6c300SDenis V. Lunev stats->account_failed = true; 439caa6f3dSPaolo Bonzini } 449caa6f3dSPaolo Bonzini 45b2aaf354SDenis V. Lunev static bool bool_from_onoffauto(OnOffAuto val, bool def) 46362e9299SAlberto Garcia { 47b2aaf354SDenis V. Lunev switch (val) { 48b2aaf354SDenis V. Lunev case ON_OFF_AUTO_AUTO: 49b2aaf354SDenis V. Lunev return def; 50b2aaf354SDenis V. Lunev case ON_OFF_AUTO_ON: 51b2aaf354SDenis V. Lunev return true; 52b2aaf354SDenis V. Lunev case ON_OFF_AUTO_OFF: 53b2aaf354SDenis V. Lunev return false; 54b2aaf354SDenis V. Lunev default: 55b2aaf354SDenis V. Lunev abort(); 56b2aaf354SDenis V. Lunev } 57b2aaf354SDenis V. Lunev } 58b2aaf354SDenis V. Lunev 59b2aaf354SDenis V. Lunev void block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid, 60b2aaf354SDenis V. Lunev enum OnOffAuto account_failed) 61b2aaf354SDenis V. Lunev { 6262a6c300SDenis V. Lunev stats->account_invalid = bool_from_onoffauto(account_invalid, 6362a6c300SDenis V. Lunev stats->account_invalid); 6462a6c300SDenis V. Lunev stats->account_failed = bool_from_onoffauto(account_failed, 6562a6c300SDenis V. Lunev stats->account_failed); 66362e9299SAlberto Garcia } 67362e9299SAlberto Garcia 68979e9b03SAlberto Garcia void block_acct_cleanup(BlockAcctStats *stats) 69979e9b03SAlberto Garcia { 70979e9b03SAlberto Garcia BlockAcctTimedStats *s, *next; 71979e9b03SAlberto Garcia QSLIST_FOREACH_SAFE(s, &stats->intervals, entries, next) { 72979e9b03SAlberto Garcia g_free(s); 73979e9b03SAlberto Garcia } 745b50bf77SPaolo Bonzini qemu_mutex_destroy(&stats->lock); 75979e9b03SAlberto Garcia } 76979e9b03SAlberto Garcia 77979e9b03SAlberto Garcia void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length) 78979e9b03SAlberto Garcia { 79979e9b03SAlberto Garcia BlockAcctTimedStats *s; 80979e9b03SAlberto Garcia unsigned i; 81979e9b03SAlberto Garcia 82979e9b03SAlberto Garcia s = g_new0(BlockAcctTimedStats, 1); 83979e9b03SAlberto Garcia s->interval_length = interval_length; 845b50bf77SPaolo Bonzini s->stats = stats; 855b50bf77SPaolo Bonzini qemu_mutex_lock(&stats->lock); 86979e9b03SAlberto Garcia QSLIST_INSERT_HEAD(&stats->intervals, s, entries); 87979e9b03SAlberto Garcia 88979e9b03SAlberto Garcia for (i = 0; i < BLOCK_MAX_IOTYPE; i++) { 89979e9b03SAlberto Garcia timed_average_init(&s->latency[i], clock_type, 90979e9b03SAlberto Garcia (uint64_t) interval_length * NANOSECONDS_PER_SECOND); 91979e9b03SAlberto Garcia } 925b50bf77SPaolo Bonzini qemu_mutex_unlock(&stats->lock); 93979e9b03SAlberto Garcia } 94979e9b03SAlberto Garcia 95979e9b03SAlberto Garcia BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats, 96979e9b03SAlberto Garcia BlockAcctTimedStats *s) 97979e9b03SAlberto Garcia { 98979e9b03SAlberto Garcia if (s == NULL) { 99979e9b03SAlberto Garcia return QSLIST_FIRST(&stats->intervals); 100979e9b03SAlberto Garcia } else { 101979e9b03SAlberto Garcia return QSLIST_NEXT(s, entries); 102979e9b03SAlberto Garcia } 103979e9b03SAlberto Garcia } 104979e9b03SAlberto Garcia 1055366d0c8SBenoît Canet void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, 1065366d0c8SBenoît Canet int64_t bytes, enum BlockAcctType type) 1075e5a94b6SBenoît Canet { 10828298fd3SBenoît Canet assert(type < BLOCK_MAX_IOTYPE); 1095e5a94b6SBenoît Canet 1105e5a94b6SBenoît Canet cookie->bytes = bytes; 1115519593cSAlberto Garcia cookie->start_time_ns = qemu_clock_get_ns(clock_type); 1125e5a94b6SBenoît Canet cookie->type = type; 1135e5a94b6SBenoît Canet } 1145e5a94b6SBenoît Canet 115b741ae74SVladimir Sementsov-Ogievskiy /* block_latency_histogram_compare_func: 116b741ae74SVladimir Sementsov-Ogievskiy * Compare @key with interval [@it[0], @it[1]). 117b741ae74SVladimir Sementsov-Ogievskiy * Return: -1 if @key < @it[0] 118b741ae74SVladimir Sementsov-Ogievskiy * 0 if @key in [@it[0], @it[1]) 119b741ae74SVladimir Sementsov-Ogievskiy * +1 if @key >= @it[1] 120b741ae74SVladimir Sementsov-Ogievskiy */ 121b741ae74SVladimir Sementsov-Ogievskiy static int block_latency_histogram_compare_func(const void *key, const void *it) 122b741ae74SVladimir Sementsov-Ogievskiy { 123b741ae74SVladimir Sementsov-Ogievskiy uint64_t k = *(uint64_t *)key; 124b741ae74SVladimir Sementsov-Ogievskiy uint64_t a = ((uint64_t *)it)[0]; 125b741ae74SVladimir Sementsov-Ogievskiy uint64_t b = ((uint64_t *)it)[1]; 126b741ae74SVladimir Sementsov-Ogievskiy 127b741ae74SVladimir Sementsov-Ogievskiy return k < a ? -1 : (k < b ? 0 : 1); 128b741ae74SVladimir Sementsov-Ogievskiy } 129b741ae74SVladimir Sementsov-Ogievskiy 130b741ae74SVladimir Sementsov-Ogievskiy static void block_latency_histogram_account(BlockLatencyHistogram *hist, 131b741ae74SVladimir Sementsov-Ogievskiy int64_t latency_ns) 132b741ae74SVladimir Sementsov-Ogievskiy { 133b741ae74SVladimir Sementsov-Ogievskiy uint64_t *pos; 134b741ae74SVladimir Sementsov-Ogievskiy 135b741ae74SVladimir Sementsov-Ogievskiy if (hist->bins == NULL) { 136b741ae74SVladimir Sementsov-Ogievskiy /* histogram disabled */ 137b741ae74SVladimir Sementsov-Ogievskiy return; 138b741ae74SVladimir Sementsov-Ogievskiy } 139b741ae74SVladimir Sementsov-Ogievskiy 140b741ae74SVladimir Sementsov-Ogievskiy 141b741ae74SVladimir Sementsov-Ogievskiy if (latency_ns < hist->boundaries[0]) { 142b741ae74SVladimir Sementsov-Ogievskiy hist->bins[0]++; 143b741ae74SVladimir Sementsov-Ogievskiy return; 144b741ae74SVladimir Sementsov-Ogievskiy } 145b741ae74SVladimir Sementsov-Ogievskiy 146b741ae74SVladimir Sementsov-Ogievskiy if (latency_ns >= hist->boundaries[hist->nbins - 2]) { 147b741ae74SVladimir Sementsov-Ogievskiy hist->bins[hist->nbins - 1]++; 148b741ae74SVladimir Sementsov-Ogievskiy return; 149b741ae74SVladimir Sementsov-Ogievskiy } 150b741ae74SVladimir Sementsov-Ogievskiy 151b741ae74SVladimir Sementsov-Ogievskiy pos = bsearch(&latency_ns, hist->boundaries, hist->nbins - 2, 152b741ae74SVladimir Sementsov-Ogievskiy sizeof(hist->boundaries[0]), 153b741ae74SVladimir Sementsov-Ogievskiy block_latency_histogram_compare_func); 154b741ae74SVladimir Sementsov-Ogievskiy assert(pos != NULL); 155b741ae74SVladimir Sementsov-Ogievskiy 156b741ae74SVladimir Sementsov-Ogievskiy hist->bins[pos - hist->boundaries + 1]++; 157b741ae74SVladimir Sementsov-Ogievskiy } 158b741ae74SVladimir Sementsov-Ogievskiy 159b741ae74SVladimir Sementsov-Ogievskiy int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type, 160b741ae74SVladimir Sementsov-Ogievskiy uint64List *boundaries) 161b741ae74SVladimir Sementsov-Ogievskiy { 162b741ae74SVladimir Sementsov-Ogievskiy BlockLatencyHistogram *hist = &stats->latency_histogram[type]; 163b741ae74SVladimir Sementsov-Ogievskiy uint64List *entry; 164b741ae74SVladimir Sementsov-Ogievskiy uint64_t *ptr; 165b741ae74SVladimir Sementsov-Ogievskiy uint64_t prev = 0; 166b741ae74SVladimir Sementsov-Ogievskiy int new_nbins = 1; 167b741ae74SVladimir Sementsov-Ogievskiy 168b741ae74SVladimir Sementsov-Ogievskiy for (entry = boundaries; entry; entry = entry->next) { 169b741ae74SVladimir Sementsov-Ogievskiy if (entry->value <= prev) { 170b741ae74SVladimir Sementsov-Ogievskiy return -EINVAL; 171b741ae74SVladimir Sementsov-Ogievskiy } 172b741ae74SVladimir Sementsov-Ogievskiy new_nbins++; 173b741ae74SVladimir Sementsov-Ogievskiy prev = entry->value; 174b741ae74SVladimir Sementsov-Ogievskiy } 175b741ae74SVladimir Sementsov-Ogievskiy 176b741ae74SVladimir Sementsov-Ogievskiy hist->nbins = new_nbins; 177b741ae74SVladimir Sementsov-Ogievskiy g_free(hist->boundaries); 178b741ae74SVladimir Sementsov-Ogievskiy hist->boundaries = g_new(uint64_t, hist->nbins - 1); 179b741ae74SVladimir Sementsov-Ogievskiy for (entry = boundaries, ptr = hist->boundaries; entry; 180b741ae74SVladimir Sementsov-Ogievskiy entry = entry->next, ptr++) 181b741ae74SVladimir Sementsov-Ogievskiy { 182b741ae74SVladimir Sementsov-Ogievskiy *ptr = entry->value; 183b741ae74SVladimir Sementsov-Ogievskiy } 184b741ae74SVladimir Sementsov-Ogievskiy 185b741ae74SVladimir Sementsov-Ogievskiy g_free(hist->bins); 186b741ae74SVladimir Sementsov-Ogievskiy hist->bins = g_new0(uint64_t, hist->nbins); 187b741ae74SVladimir Sementsov-Ogievskiy 188b741ae74SVladimir Sementsov-Ogievskiy return 0; 189b741ae74SVladimir Sementsov-Ogievskiy } 190b741ae74SVladimir Sementsov-Ogievskiy 191b741ae74SVladimir Sementsov-Ogievskiy void block_latency_histograms_clear(BlockAcctStats *stats) 192b741ae74SVladimir Sementsov-Ogievskiy { 193b741ae74SVladimir Sementsov-Ogievskiy int i; 194b741ae74SVladimir Sementsov-Ogievskiy 195b741ae74SVladimir Sementsov-Ogievskiy for (i = 0; i < BLOCK_MAX_IOTYPE; i++) { 196b741ae74SVladimir Sementsov-Ogievskiy BlockLatencyHistogram *hist = &stats->latency_histogram[i]; 197b741ae74SVladimir Sementsov-Ogievskiy g_free(hist->bins); 198b741ae74SVladimir Sementsov-Ogievskiy g_free(hist->boundaries); 199b741ae74SVladimir Sementsov-Ogievskiy memset(hist, 0, sizeof(*hist)); 200b741ae74SVladimir Sementsov-Ogievskiy } 201b741ae74SVladimir Sementsov-Ogievskiy } 202b741ae74SVladimir Sementsov-Ogievskiy 20339c1b425SPaolo Bonzini static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie, 20439c1b425SPaolo Bonzini bool failed) 2055e5a94b6SBenoît Canet { 206979e9b03SAlberto Garcia BlockAcctTimedStats *s; 207cb38fffbSAlberto Garcia int64_t time_ns = qemu_clock_get_ns(clock_type); 208cb38fffbSAlberto Garcia int64_t latency_ns = time_ns - cookie->start_time_ns; 209cb38fffbSAlberto Garcia 210918a17a4SAlberto Garcia if (qtest_enabled()) { 211918a17a4SAlberto Garcia latency_ns = qtest_latency_ns; 212918a17a4SAlberto Garcia } 213918a17a4SAlberto Garcia 21428298fd3SBenoît Canet assert(cookie->type < BLOCK_MAX_IOTYPE); 2155e5a94b6SBenoît Canet 216f3444466SAnton Nefedov if (cookie->type == BLOCK_ACCT_NONE) { 217f3444466SAnton Nefedov return; 218f3444466SAnton Nefedov } 219f3444466SAnton Nefedov 220c37c9736SGan Qixin WITH_QEMU_LOCK_GUARD(&stats->lock) { 22139c1b425SPaolo Bonzini if (failed) { 22239c1b425SPaolo Bonzini stats->failed_ops[cookie->type]++; 22339c1b425SPaolo Bonzini } else { 2245366d0c8SBenoît Canet stats->nr_bytes[cookie->type] += cookie->bytes; 2255366d0c8SBenoît Canet stats->nr_ops[cookie->type]++; 22639c1b425SPaolo Bonzini } 22739c1b425SPaolo Bonzini 228b741ae74SVladimir Sementsov-Ogievskiy block_latency_histogram_account(&stats->latency_histogram[cookie->type], 229b741ae74SVladimir Sementsov-Ogievskiy latency_ns); 230b741ae74SVladimir Sementsov-Ogievskiy 23139c1b425SPaolo Bonzini if (!failed || stats->account_failed) { 232cb38fffbSAlberto Garcia stats->total_time_ns[cookie->type] += latency_ns; 233cb38fffbSAlberto Garcia stats->last_access_time_ns = time_ns; 234979e9b03SAlberto Garcia 235979e9b03SAlberto Garcia QSLIST_FOREACH(s, &stats->intervals, entries) { 236979e9b03SAlberto Garcia timed_average_account(&s->latency[cookie->type], latency_ns); 237979e9b03SAlberto Garcia } 2385e5a94b6SBenoît Canet } 239c37c9736SGan Qixin } 240f3444466SAnton Nefedov 241f3444466SAnton Nefedov cookie->type = BLOCK_ACCT_NONE; 24239c1b425SPaolo Bonzini } 24339c1b425SPaolo Bonzini 24439c1b425SPaolo Bonzini void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie) 24539c1b425SPaolo Bonzini { 24639c1b425SPaolo Bonzini block_account_one_io(stats, cookie, false); 24739c1b425SPaolo Bonzini } 2485e5a94b6SBenoît Canet 2497ee12dafSAlberto Garcia void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie) 2507ee12dafSAlberto Garcia { 25139c1b425SPaolo Bonzini block_account_one_io(stats, cookie, true); 252362e9299SAlberto Garcia } 2537ee12dafSAlberto Garcia 2547ee12dafSAlberto Garcia void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type) 2557ee12dafSAlberto Garcia { 2567ee12dafSAlberto Garcia assert(type < BLOCK_MAX_IOTYPE); 2577ee12dafSAlberto Garcia 25839c1b425SPaolo Bonzini /* block_account_one_io() updates total_time_ns[], but this one does 25939c1b425SPaolo Bonzini * not. The reason is that invalid requests are accounted during their 26039c1b425SPaolo Bonzini * submission, therefore there's no actual I/O involved. 26139c1b425SPaolo Bonzini */ 2625b50bf77SPaolo Bonzini qemu_mutex_lock(&stats->lock); 2637ee12dafSAlberto Garcia stats->invalid_ops[type]++; 264362e9299SAlberto Garcia 265362e9299SAlberto Garcia if (stats->account_invalid) { 2667ee12dafSAlberto Garcia stats->last_access_time_ns = qemu_clock_get_ns(clock_type); 2677ee12dafSAlberto Garcia } 2685b50bf77SPaolo Bonzini qemu_mutex_unlock(&stats->lock); 269362e9299SAlberto Garcia } 2705e5a94b6SBenoît Canet 271f4564d53SPeter Lieven void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, 272f4564d53SPeter Lieven int num_requests) 273f4564d53SPeter Lieven { 274f4564d53SPeter Lieven assert(type < BLOCK_MAX_IOTYPE); 2755b50bf77SPaolo Bonzini 2765b50bf77SPaolo Bonzini qemu_mutex_lock(&stats->lock); 277f4564d53SPeter Lieven stats->merged[type] += num_requests; 2785b50bf77SPaolo Bonzini qemu_mutex_unlock(&stats->lock); 279f4564d53SPeter Lieven } 280cb38fffbSAlberto Garcia 281cb38fffbSAlberto Garcia int64_t block_acct_idle_time_ns(BlockAcctStats *stats) 282cb38fffbSAlberto Garcia { 283cb38fffbSAlberto Garcia return qemu_clock_get_ns(clock_type) - stats->last_access_time_ns; 284cb38fffbSAlberto Garcia } 28596e4dedaSAlberto Garcia 28696e4dedaSAlberto Garcia double block_acct_queue_depth(BlockAcctTimedStats *stats, 28796e4dedaSAlberto Garcia enum BlockAcctType type) 28896e4dedaSAlberto Garcia { 28996e4dedaSAlberto Garcia uint64_t sum, elapsed; 29096e4dedaSAlberto Garcia 29196e4dedaSAlberto Garcia assert(type < BLOCK_MAX_IOTYPE); 29296e4dedaSAlberto Garcia 2935b50bf77SPaolo Bonzini qemu_mutex_lock(&stats->stats->lock); 29496e4dedaSAlberto Garcia sum = timed_average_sum(&stats->latency[type], &elapsed); 2955b50bf77SPaolo Bonzini qemu_mutex_unlock(&stats->stats->lock); 29696e4dedaSAlberto Garcia 29796e4dedaSAlberto Garcia return (double) sum / elapsed; 29896e4dedaSAlberto Garcia } 299