diff mbox

test-coroutine: test cost introduced by coroutine

Message ID 1407758345-2508-1-git-send-email-ming.lei@canonical.com
State New
Headers show

Commit Message

Ming Lei Aug. 11, 2014, 11:59 a.m. UTC
This test uses getppid() syscall to simulate single operation
run inside coroutine, and compare how many operations done per
second between using coroutine and not using coroutine to
evalute cost introduced by running operation via coroutine.

Paolo introduced 'baseline test' for computing the cost
of coroutine operations, and it may be not enough since coroutine
switches stack for running task and this cost won't be considered
at all, and in reality most of actual corotine cases can't avoid
stack use at all. So this patch uses getppid() syscall to simulte
operation running from coroutine:

	- syscall and related stack operations can't be optimized by compiler
	- push to/pop from user space stack introduced by calling syscall,
	such as for save/restore context
    - also it isn't unusual to call syscall from coroutine

For example, here are the results on my machine when treating 1
getppid() as one operation:

	- Run operation 60000000 iterations(1 getppid() per operation) without using
	coroutine: 3.517642 s, 17056K operations/s
	- Run operation 60000000 iterations(1 getppid() per operation) using
	coroutine: 11.157434 s, 5377K operations/s
	- Coroutine introduced cost: 68%

If running 30 getppid() in one operation:

	- Run operation 60000000 iterations(30 getppid() per operation) without using
	coroutine: 3.264977 s, 612K operations/s
	- Run operation 60000000 iterations(30 getppid() per operation) using
	coroutine: 3.733169 s, 535K operations/s
	- Coroutine introduced cost: %12

So in some situations, the cost introduced by coroutine isn't too small
to be ignored.

Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 tests/test-coroutine.c |   52 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

Comments

Ming Lei Aug. 13, 2014, 10:07 a.m. UTC | #1
On Mon, Aug 11, 2014 at 7:59 PM, Ming Lei <ming.lei@canonical.com> wrote:
> This test uses getppid() syscall to simulate single operation
> run inside coroutine, and compare how many operations done per
> second between using coroutine and not using coroutine to
> evalute cost introduced by running operation via coroutine.
>
> Paolo introduced 'baseline test' for computing the cost
> of coroutine operations, and it may be not enough since coroutine
> switches stack for running task and this cost won't be considered
> at all, and in reality most of actual corotine cases can't avoid
> stack use at all. So this patch uses getppid() syscall to simulte
> operation running from coroutine:
>
>         - syscall and related stack operations can't be optimized by compiler
>         - push to/pop from user space stack introduced by calling syscall,
>         such as for save/restore context
>     - also it isn't unusual to call syscall from coroutine
>
> For example, here are the results on my machine when treating 1
> getppid() as one operation:
>
>         - Run operation 60000000 iterations(1 getppid() per operation) without using
>         coroutine: 3.517642 s, 17056K operations/s
>         - Run operation 60000000 iterations(1 getppid() per operation) using
>         coroutine: 11.157434 s, 5377K operations/s
>         - Coroutine introduced cost: 68%
>
> If running 30 getppid() in one operation:
>
>         - Run operation 60000000 iterations(30 getppid() per operation) without using
>         coroutine: 3.264977 s, 612K operations/s
>         - Run operation 60000000 iterations(30 getppid() per operation) using
>         coroutine: 3.733169 s, 535K operations/s
>         - Coroutine introduced cost: %12
>
> So in some situations, the cost introduced by coroutine isn't too small
> to be ignored.

Please ignore this one, and I have better and simper patch to figure out
coroutine cost.

Thanks,
diff mbox

Patch

diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
index 6e634f4..6fa7d40 100644
--- a/tests/test-coroutine.c
+++ b/tests/test-coroutine.c
@@ -311,6 +311,57 @@  static void perf_baseline(void)
         maxcycles, duration);
 }
 
+static __attribute__((noinline)) void perf_cost_run_one(void *opaque)
+{
+    unsigned long *cnt = opaque;
+    unsigned long i = 0;
+
+    while (i++ < *cnt) {
+        getppid();
+    }
+}
+
+static long perf_cost_run(unsigned long maxcycles, unsigned long cnt,
+                          bool use_co)
+{
+    unsigned long i = 0;
+    double duration;
+    unsigned long ops;
+
+    g_test_timer_start();
+    while (i++ < maxcycles) {
+        if (!use_co) {
+            perf_cost_run_one(&cnt);
+        } else {
+            Coroutine *co = qemu_coroutine_create(perf_cost_run_one);
+            qemu_coroutine_enter(co, &cnt);
+        }
+    }
+    duration = g_test_timer_elapsed();
+    ops = (long)(maxcycles / (duration * 1000));
+
+    g_test_message("Run operation %lu iterations(%lu getppid() per operation) "
+                   "%s: %f s, %luK operations/s",
+                   maxcycles, cnt,
+                   use_co ? "using coroutine" : "without using coroutine",
+                   duration, ops);
+
+    return ops;
+}
+
+static void perf_cost(void)
+{
+    unsigned long maxcycles = 60000000;
+    unsigned long cnt = 1;
+    long ops_base, ops_co;
+
+    ops_base = perf_cost_run(maxcycles / cnt, cnt, false);
+    ops_co = perf_cost_run(maxcycles / cnt, cnt, true);
+
+    g_test_message("Coroutine introduced cost: %lu%%",
+                    (ops_base - ops_co) * 100 / ops_base);
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
@@ -325,6 +376,7 @@  int main(int argc, char **argv)
         g_test_add_func("/perf/nesting", perf_nesting);
         g_test_add_func("/perf/yield", perf_yield);
         g_test_add_func("/perf/function-call", perf_baseline);
+        g_test_add_func("/perf/cost", perf_cost);
     }
     return g_test_run();
 }