From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45860) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xj8mS-0002JK-R6 for qemu-devel@nongnu.org; Tue, 28 Oct 2014 11:34:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xj8mL-0001V6-A3 for qemu-devel@nongnu.org; Tue, 28 Oct 2014 11:33:56 -0400 Received: from mout.gmx.net ([212.227.17.22]:64626) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xj8mK-0001Uw-Vf for qemu-devel@nongnu.org; Tue, 28 Oct 2014 11:33:49 -0400 From: Harald Schieche Date: Tue, 28 Oct 2014 16:33:42 +0100 Message-Id: <1414510422-8277-1-git-send-email-rehs@gmx.de> Subject: [Qemu-devel] [PATCH] Simple performance logging and network limiting based on trace option List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Stefan Weil , Harald Schieche , Stefan Hajnoczi , Anthony Liguori diff --git a/block/raw-posix.c b/block/raw-posix.c index 475cf74..3c5cc71 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1031,6 +1031,27 @@ static int aio_worker(void *arg) return ret; } +static void log_guest_storage_performance(void) +{ + /* + * Performance logging isn't specified yet. + * Therefore we're using existing tracing. + */ + static int64_t logged_clock; + static int64_t counter; + int64_t clock = get_clock(); + + counter++; + if (clock - logged_clock >= 1000000000LL) { + if (logged_clock > 0) { /* don't log first event */ + trace_log_guest_storage_performance + (counter, (clock - logged_clock) / 1000000000LL); + } + counter = 0; + logged_clock = clock; + } +} + static int paio_submit_co(BlockDriverState *bs, int fd, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, int type) @@ -1051,6 +1072,7 @@ static int paio_submit_co(BlockDriverState *bs, int fd, assert(qiov->size == acb->aio_nbytes); } + log_guest_storage_performance(); trace_paio_submit_co(sector_num, nb_sectors, type); pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); return thread_pool_submit_co(pool, aio_worker, acb); @@ -1076,6 +1098,7 @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, int fd, assert(qiov->size == acb->aio_nbytes); } + log_guest_storage_performance(); trace_paio_submit(acb, opaque, sector_num, nb_sectors, type); pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); diff --git a/block/raw-win32.c b/block/raw-win32.c index 7b58881..8cb2743 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -138,6 +138,27 @@ static int aio_worker(void *arg) return ret; } +static void log_guest_storage_performance(void) +{ + /* + * Performance logging isn't specified yet. + * Therefore we're using existing tracing. + */ + static int64_t logged_clock; + static int64_t counter; + int64_t clock = get_clock(); + + counter++; + if (clock - logged_clock >= 1000000000LL) { + if (logged_clock > 0) { /* don't log first event */ + trace_log_guest_storage_performance + (counter, (clock - logged_clock) / 1000000000LL); + } + counter = 0; + logged_clock = clock; + } +} + static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockCompletionFunc *cb, void *opaque, int type) @@ -156,6 +177,7 @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, acb->aio_nbytes = nb_sectors * 512; acb->aio_offset = sector_num * 512; + log_guest_storage_performance(); trace_paio_submit(acb, opaque, sector_num, nb_sectors, type); pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); diff --git a/include/net/queue.h b/include/net/queue.h index fc02b33..d8ea589 100644 --- a/include/net/queue.h +++ b/include/net/queue.h @@ -34,6 +34,8 @@ typedef void (NetPacketSent) (NetClientState *sender, ssize_t ret); #define QEMU_NET_PACKET_FLAG_NONE 0 #define QEMU_NET_PACKET_FLAG_RAW (1<<0) +void qemu_net_set_bandwidth_limit(int64_t limit); + NetQueue *qemu_new_net_queue(void *opaque); void qemu_del_net_queue(NetQueue *queue); diff --git a/net/queue.c b/net/queue.c index f948318..2b0fef7 100644 --- a/net/queue.c +++ b/net/queue.c @@ -23,7 +23,9 @@ #include "net/queue.h" #include "qemu/queue.h" +#include "qemu/timer.h" #include "net/net.h" +#include "trace.h" /* The delivery handler may only return zero if it will call * qemu_net_queue_flush() when it determines that it is once again able @@ -58,6 +60,15 @@ struct NetQueue { unsigned delivering : 1; }; +static int64_t bandwidth_limit; /* maximum number of bits per second */ + +void qemu_net_set_bandwidth_limit(int64_t limit) +{ + bandwidth_limit = limit; + trace_qemu_net_set_bandwidth_limit(limit); +} + + NetQueue *qemu_new_net_queue(void *opaque) { NetQueue *queue; @@ -175,6 +186,48 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue, return ret; } +static int64_t limit_network_performance(int64_t start_clock, + int64_t bytes) +{ + int64_t clock = get_clock(); + int64_t sleep_usecs = 0; + if (bandwidth_limit > 0) { + sleep_usecs = (bytes * 8 * 1000000LL) / bandwidth_limit - + (clock - start_clock) / 1000LL; + } + if (sleep_usecs > 0) { + usleep(sleep_usecs); + clock = get_clock(); + } + + return clock; +} + +static void log_and_limit_network_performance(size_t size) +{ + /* + * Performance logging isn't specified yet. + * Therefore we're using existing tracing. + */ + static int64_t logged_clock; + static int64_t packets; + static int64_t bytes; + int64_t clock = 0; + + packets++; + bytes = bytes + size; + clock = limit_network_performance(logged_clock, bytes); + if (clock - logged_clock >= 1000000000LL) { + if (logged_clock > 0) { /* don't log first event */ + trace_log_network_performance + (packets, bytes*8, (clock - logged_clock) / 1000000000LL); + } + packets = 0; + bytes = 0; + logged_clock = clock; + } +} + ssize_t qemu_net_queue_send(NetQueue *queue, NetClientState *sender, unsigned flags, @@ -184,6 +237,7 @@ ssize_t qemu_net_queue_send(NetQueue *queue, { ssize_t ret; + log_and_limit_network_performance(size) ; if (queue->delivering || !qemu_can_send_packet(sender)) { qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); return 0; diff --git a/qemu-options.hx b/qemu-options.hx index 22cf3b9..35aee69 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1916,6 +1916,19 @@ override the default configuration (@option{-net nic -net user}) which is activated if no @option{-net} options are provided. ETEXI +DEF("bandwidth", HAS_ARG, QEMU_OPTION_bandwidth, + "-bandwidth [limit=]n\n" + " set the maximum bandwidth[bits per second] to 'n' (default=0, no limit)\n", + QEMU_ARCH_ALL) +STEXI +@item -bandwidth [limit=]@var{n}] +@findex -bandwidth +Limit the network bandwith (bits per second). +If the limit is reached, Qemu will sleep. +0, the default means no limit. +This option is active if trace-event "log_network_performance" is active +ETEXI + STEXI @end table ETEXI diff --git a/trace-events b/trace-events index 6c3a400..04b2d36 100644 --- a/trace-events +++ b/trace-events @@ -134,6 +134,7 @@ thread_pool_cancel(void *req, void *opaque) "req %p opaque %p" # block/raw-posix.c paio_submit_co(int64_t sector_num, int nb_sectors, int type) "sector_num %"PRId64" nb_sectors %d type %d" paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d" +log_guest_storage_performance(int64_t counter, int64_t seconds) "counter %"PRId64" seconds %"PRId64" # ioport.c cpu_in(unsigned int addr, unsigned int val) "addr %#x value %u" @@ -1378,3 +1379,7 @@ i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA ch cpu_set_state(int cpu_index, uint8_t state) "setting cpu %d state to %" PRIu8 cpu_halt(int cpu_index) "halting cpu %d" cpu_unhalt(int cpu_index) "unhalting cpu %d" + +# net/queue.c +qemu_net_set_bandwidth_limit(int64_t limit) "bits per second %"PRId64" +log_network_performance(int64_t packets, int64_t bits, int64_t seconds) "packets %"PRId64" "bits %"PRId64" seconds %"PRId64" diff --git a/vl.c b/vl.c index 2f81384..02a91e1 100644 --- a/vl.c +++ b/vl.c @@ -1309,6 +1309,30 @@ static void smp_parse(QemuOpts *opts) } +static QemuOptsList qemu_bandwidth_opts = { + .name = "bandwidth-opts", + .implied_opt_name = "limit", + .merge_lists = true, + .head = QTAILQ_HEAD_INITIALIZER(qemu_bandwidth_opts.head), + .desc = { + { + .name = "limit", + .type = QEMU_OPT_NUMBER, + }, + { /*End of list */ } + }, +}; + +static void bandwidth_parse(QemuOpts *opts) +{ + if (opts) { + + qemu_net_set_bandwidth_limit(qemu_opt_get_number(opts, "limit", 0)); + + } + +} + static void realtime_init(void) { if (enable_mlock) { @@ -2758,6 +2782,7 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_machine_opts); qemu_add_opts(&qemu_mem_opts); qemu_add_opts(&qemu_smp_opts); + qemu_add_opts(&qemu_bandwidth_opts); qemu_add_opts(&qemu_boot_opts); qemu_add_opts(&qemu_sandbox_opts); qemu_add_opts(&qemu_add_fd_opts); @@ -3517,6 +3542,12 @@ int main(int argc, char **argv, char **envp) exit(1); } break; + case QEMU_OPTION_bandwidth: + if (!qemu_opts_parse(qemu_find_opts("bandwidth-opts"), + optarg, 1)) { + exit(1); + } + break; case QEMU_OPTION_vnc: #ifdef CONFIG_VNC display_remote++; @@ -3862,6 +3893,8 @@ int main(int argc, char **argv, char **envp) exit(1); } + bandwidth_parse(qemu_opts_find(qemu_find_opts("bandwidth-opts"), NULL)); + /* * Get the default machine options from the machine if it is not already * specified either by the configuration file or by the command line. -- 1.9.1 Signed-off-by: Harald Schieche