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 <r...@gmx.de>