15e5a94b6SBenoît Canet /* 25e5a94b6SBenoît Canet * QEMU System Emulator block accounting 35e5a94b6SBenoît Canet * 45e5a94b6SBenoît Canet * Copyright (c) 2011 Christoph Hellwig 55e5a94b6SBenoît Canet * 65e5a94b6SBenoît Canet * Permission is hereby granted, free of charge, to any person obtaining a copy 75e5a94b6SBenoît Canet * of this software and associated documentation files (the "Software"), to deal 85e5a94b6SBenoît Canet * in the Software without restriction, including without limitation the rights 95e5a94b6SBenoît Canet * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 105e5a94b6SBenoît Canet * copies of the Software, and to permit persons to whom the Software is 115e5a94b6SBenoît Canet * furnished to do so, subject to the following conditions: 125e5a94b6SBenoît Canet * 135e5a94b6SBenoît Canet * The above copyright notice and this permission notice shall be included in 145e5a94b6SBenoît Canet * all copies or substantial portions of the Software. 155e5a94b6SBenoît Canet * 165e5a94b6SBenoît Canet * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 175e5a94b6SBenoît Canet * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 185e5a94b6SBenoît Canet * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 195e5a94b6SBenoît Canet * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 205e5a94b6SBenoît Canet * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 215e5a94b6SBenoît Canet * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 225e5a94b6SBenoît Canet * THE SOFTWARE. 235e5a94b6SBenoît Canet */ 245e5a94b6SBenoît Canet 255e5a94b6SBenoît Canet #include "block/accounting.h" 265e5a94b6SBenoît Canet #include "block/block_int.h" 27a56ebc6bSPaolo Bonzini #include "qemu/timer.h" 28*918a17a4SAlberto Garcia #include "sysemu/qtest.h" 295e5a94b6SBenoît Canet 305519593cSAlberto Garcia static QEMUClockType clock_type = QEMU_CLOCK_REALTIME; 31*918a17a4SAlberto Garcia static const int qtest_latency_ns = NANOSECONDS_PER_SECOND / 1000; 325519593cSAlberto Garcia 33362e9299SAlberto Garcia void block_acct_init(BlockAcctStats *stats, bool account_invalid, 34362e9299SAlberto Garcia bool account_failed) 35362e9299SAlberto Garcia { 36362e9299SAlberto Garcia stats->account_invalid = account_invalid; 37362e9299SAlberto Garcia stats->account_failed = account_failed; 38*918a17a4SAlberto Garcia 39*918a17a4SAlberto Garcia if (qtest_enabled()) { 40*918a17a4SAlberto Garcia clock_type = QEMU_CLOCK_VIRTUAL; 41*918a17a4SAlberto Garcia } 42362e9299SAlberto Garcia } 43362e9299SAlberto Garcia 44979e9b03SAlberto Garcia void block_acct_cleanup(BlockAcctStats *stats) 45979e9b03SAlberto Garcia { 46979e9b03SAlberto Garcia BlockAcctTimedStats *s, *next; 47979e9b03SAlberto Garcia QSLIST_FOREACH_SAFE(s, &stats->intervals, entries, next) { 48979e9b03SAlberto Garcia g_free(s); 49979e9b03SAlberto Garcia } 50979e9b03SAlberto Garcia } 51979e9b03SAlberto Garcia 52979e9b03SAlberto Garcia void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length) 53979e9b03SAlberto Garcia { 54979e9b03SAlberto Garcia BlockAcctTimedStats *s; 55979e9b03SAlberto Garcia unsigned i; 56979e9b03SAlberto Garcia 57979e9b03SAlberto Garcia s = g_new0(BlockAcctTimedStats, 1); 58979e9b03SAlberto Garcia s->interval_length = interval_length; 59979e9b03SAlberto Garcia QSLIST_INSERT_HEAD(&stats->intervals, s, entries); 60979e9b03SAlberto Garcia 61979e9b03SAlberto Garcia for (i = 0; i < BLOCK_MAX_IOTYPE; i++) { 62979e9b03SAlberto Garcia timed_average_init(&s->latency[i], clock_type, 63979e9b03SAlberto Garcia (uint64_t) interval_length * NANOSECONDS_PER_SECOND); 64979e9b03SAlberto Garcia } 65979e9b03SAlberto Garcia } 66979e9b03SAlberto Garcia 67979e9b03SAlberto Garcia BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats, 68979e9b03SAlberto Garcia BlockAcctTimedStats *s) 69979e9b03SAlberto Garcia { 70979e9b03SAlberto Garcia if (s == NULL) { 71979e9b03SAlberto Garcia return QSLIST_FIRST(&stats->intervals); 72979e9b03SAlberto Garcia } else { 73979e9b03SAlberto Garcia return QSLIST_NEXT(s, entries); 74979e9b03SAlberto Garcia } 75979e9b03SAlberto Garcia } 76979e9b03SAlberto Garcia 775366d0c8SBenoît Canet void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, 785366d0c8SBenoît Canet int64_t bytes, enum BlockAcctType type) 795e5a94b6SBenoît Canet { 8028298fd3SBenoît Canet assert(type < BLOCK_MAX_IOTYPE); 815e5a94b6SBenoît Canet 825e5a94b6SBenoît Canet cookie->bytes = bytes; 835519593cSAlberto Garcia cookie->start_time_ns = qemu_clock_get_ns(clock_type); 845e5a94b6SBenoît Canet cookie->type = type; 855e5a94b6SBenoît Canet } 865e5a94b6SBenoît Canet 875366d0c8SBenoît Canet void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie) 885e5a94b6SBenoît Canet { 89979e9b03SAlberto Garcia BlockAcctTimedStats *s; 90cb38fffbSAlberto Garcia int64_t time_ns = qemu_clock_get_ns(clock_type); 91cb38fffbSAlberto Garcia int64_t latency_ns = time_ns - cookie->start_time_ns; 92cb38fffbSAlberto Garcia 93*918a17a4SAlberto Garcia if (qtest_enabled()) { 94*918a17a4SAlberto Garcia latency_ns = qtest_latency_ns; 95*918a17a4SAlberto Garcia } 96*918a17a4SAlberto Garcia 9728298fd3SBenoît Canet assert(cookie->type < BLOCK_MAX_IOTYPE); 985e5a94b6SBenoît Canet 995366d0c8SBenoît Canet stats->nr_bytes[cookie->type] += cookie->bytes; 1005366d0c8SBenoît Canet stats->nr_ops[cookie->type]++; 101cb38fffbSAlberto Garcia stats->total_time_ns[cookie->type] += latency_ns; 102cb38fffbSAlberto Garcia stats->last_access_time_ns = time_ns; 103979e9b03SAlberto Garcia 104979e9b03SAlberto Garcia QSLIST_FOREACH(s, &stats->intervals, entries) { 105979e9b03SAlberto Garcia timed_average_account(&s->latency[cookie->type], latency_ns); 106979e9b03SAlberto Garcia } 1075e5a94b6SBenoît Canet } 1085e5a94b6SBenoît Canet 1097ee12dafSAlberto Garcia void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie) 1107ee12dafSAlberto Garcia { 1117ee12dafSAlberto Garcia assert(cookie->type < BLOCK_MAX_IOTYPE); 1127ee12dafSAlberto Garcia 1137ee12dafSAlberto Garcia stats->failed_ops[cookie->type]++; 114362e9299SAlberto Garcia 115362e9299SAlberto Garcia if (stats->account_failed) { 116979e9b03SAlberto Garcia BlockAcctTimedStats *s; 117362e9299SAlberto Garcia int64_t time_ns = qemu_clock_get_ns(clock_type); 118362e9299SAlberto Garcia int64_t latency_ns = time_ns - cookie->start_time_ns; 119362e9299SAlberto Garcia 120*918a17a4SAlberto Garcia if (qtest_enabled()) { 121*918a17a4SAlberto Garcia latency_ns = qtest_latency_ns; 122*918a17a4SAlberto Garcia } 123*918a17a4SAlberto Garcia 124362e9299SAlberto Garcia stats->total_time_ns[cookie->type] += latency_ns; 1257ee12dafSAlberto Garcia stats->last_access_time_ns = time_ns; 126979e9b03SAlberto Garcia 127979e9b03SAlberto Garcia QSLIST_FOREACH(s, &stats->intervals, entries) { 128979e9b03SAlberto Garcia timed_average_account(&s->latency[cookie->type], latency_ns); 129979e9b03SAlberto Garcia } 1307ee12dafSAlberto Garcia } 131362e9299SAlberto Garcia } 1327ee12dafSAlberto Garcia 1337ee12dafSAlberto Garcia void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type) 1347ee12dafSAlberto Garcia { 1357ee12dafSAlberto Garcia assert(type < BLOCK_MAX_IOTYPE); 1367ee12dafSAlberto Garcia 1377ee12dafSAlberto Garcia /* block_acct_done() and block_acct_failed() update 1387ee12dafSAlberto Garcia * total_time_ns[], but this one does not. The reason is that 1397ee12dafSAlberto Garcia * invalid requests are accounted during their submission, 1407ee12dafSAlberto Garcia * therefore there's no actual I/O involved. */ 1417ee12dafSAlberto Garcia 1427ee12dafSAlberto Garcia stats->invalid_ops[type]++; 143362e9299SAlberto Garcia 144362e9299SAlberto Garcia if (stats->account_invalid) { 1457ee12dafSAlberto Garcia stats->last_access_time_ns = qemu_clock_get_ns(clock_type); 1467ee12dafSAlberto Garcia } 147362e9299SAlberto Garcia } 1485e5a94b6SBenoît Canet 149f4564d53SPeter Lieven void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, 150f4564d53SPeter Lieven int num_requests) 151f4564d53SPeter Lieven { 152f4564d53SPeter Lieven assert(type < BLOCK_MAX_IOTYPE); 153f4564d53SPeter Lieven stats->merged[type] += num_requests; 154f4564d53SPeter Lieven } 155cb38fffbSAlberto Garcia 156cb38fffbSAlberto Garcia int64_t block_acct_idle_time_ns(BlockAcctStats *stats) 157cb38fffbSAlberto Garcia { 158cb38fffbSAlberto Garcia return qemu_clock_get_ns(clock_type) - stats->last_access_time_ns; 159cb38fffbSAlberto Garcia } 16096e4dedaSAlberto Garcia 16196e4dedaSAlberto Garcia double block_acct_queue_depth(BlockAcctTimedStats *stats, 16296e4dedaSAlberto Garcia enum BlockAcctType type) 16396e4dedaSAlberto Garcia { 16496e4dedaSAlberto Garcia uint64_t sum, elapsed; 16596e4dedaSAlberto Garcia 16696e4dedaSAlberto Garcia assert(type < BLOCK_MAX_IOTYPE); 16796e4dedaSAlberto Garcia 16896e4dedaSAlberto Garcia sum = timed_average_sum(&stats->latency[type], &elapsed); 16996e4dedaSAlberto Garcia 17096e4dedaSAlberto Garcia return (double) sum / elapsed; 17196e4dedaSAlberto Garcia } 172