source: mainline/uspace/app/rcubench/rcubench.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 6.9 KB
RevLine 
[a440a0f]1/*
2 * Copyright (c) 2012 Adam Hraska
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup test
30 * @{
31 */
32
33/**
34 * @file rcubench.c
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <stdint.h>
40#include <mem.h>
41#include <errno.h>
42#include <thread.h>
43#include <assert.h>
44#include <async.h>
45#include <fibril.h>
46#include <fibril_synch.h>
47#include <compiler/barrier.h>
48#include <futex.h>
[1d6dd2a]49#include <str.h>
[a440a0f]50
51#include <rcu.h>
52
[7554e41]53
54/* Results are printed to this file in addition to stdout. */
55static FILE *results_fd = NULL;
56
[4e41aa4]57typedef struct bench {
[7554e41]58 const char *name;
59 void (*func)(struct bench *);
[4e41aa4]60 size_t iters;
61 size_t nthreads;
62 futex_t done_threads;
[a35b458]63
[7554e41]64 futex_t bench_fut;
[4e41aa4]65} bench_t;
66
67
68
[32d2e60]69
[4e41aa4]70static void kernel_futex_bench(bench_t *bench)
71{
72 const size_t iters = bench->iters;
[6a585dd]73 int val = 0;
[a35b458]74
[4e41aa4]75 for (size_t i = 0; i < iters; ++i) {
[d22e567]76 __SYSCALL1(SYS_FUTEX_WAKEUP, (sysarg_t) &val);
77 __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &val);
[4e41aa4]78 }
79}
80
[7554e41]81static void libc_futex_lock_bench(bench_t *bench)
[4e41aa4]82{
83 const size_t iters = bench->iters;
[7554e41]84 futex_t loc_fut = FUTEX_INITIALIZER;
[a35b458]85
[4e41aa4]86 for (size_t i = 0; i < iters; ++i) {
[7554e41]87 futex_lock(&loc_fut);
[4e41aa4]88 /* no-op */
89 compiler_barrier();
[7554e41]90 futex_unlock(&loc_fut);
[4e41aa4]91 }
92}
93
[7554e41]94static void libc_futex_sema_bench(bench_t *bench)
95{
96 const size_t iters = bench->iters;
97 futex_t loc_fut = FUTEX_INITIALIZER;
[a35b458]98
[7554e41]99 for (size_t i = 0; i < iters; ++i) {
100 futex_down(&loc_fut);
101 /* no-op */
102 compiler_barrier();
103 futex_up(&loc_fut);
104 }
105}
[4e41aa4]106
107static void thread_func(void *arg)
108{
109 bench_t *bench = (bench_t*)arg;
[a35b458]110
[7554e41]111 bench->func(bench);
[a35b458]112
[4e41aa4]113 /* Signal another thread completed. */
[156b6406]114 futex_up(&bench->done_threads);
[4e41aa4]115}
116
117static void run_threads_and_wait(bench_t *bench)
118{
119 assert(1 <= bench->nthreads);
[a35b458]120
[4e41aa4]121 if (2 <= bench->nthreads) {
122 printf("Creating %zu additional threads...\n", bench->nthreads - 1);
123 }
[a35b458]124
[4e41aa4]125 /* Create and run the first nthreads - 1 threads.*/
126 for (size_t k = 1; k < bench->nthreads; ++k) {
127 thread_id_t tid;
128 /* Also sets up a fibril for the thread. */
[b7fd2a0]129 errno_t ret = thread_create(thread_func, bench, "rcubench-t", &tid);
[4e41aa4]130 if (ret != EOK) {
131 printf("Error: Failed to create benchmark thread.\n");
132 abort();
133 }
134 thread_detach(tid);
135 }
[a35b458]136
[1b20da0]137 /*
[4e41aa4]138 * Run the last thread in place so that we create multiple threads
139 * only when needed. Otherwise libc would immediately upgrade
140 * single-threaded futexes to proper multithreaded futexes
141 */
142 thread_func(bench);
[a35b458]143
[4e41aa4]144 printf("Waiting for remaining threads to complete.\n");
[a35b458]145
[4e41aa4]146 /* Wait for threads to complete. */
147 for (size_t k = 0; k < bench->nthreads; ++k) {
[156b6406]148 futex_down(&bench->done_threads);
[4e41aa4]149 }
150}
151
[d22e567]152static const char *results_txt = "/tmp/urcu-bench-results.txt";
[7554e41]153
154static bool open_results(void)
155{
156 results_fd = fopen(results_txt, "a");
157 return NULL != results_fd;
158}
159
160static void close_results(void)
161{
162 if (results_fd) {
163 fclose(results_fd);
164 }
165}
166
167static void print_res(const char *fmt, ... )
168{
169 va_list args;
[a35b458]170
[f74ec77]171 va_start(args, fmt);
[7554e41]172 vfprintf(results_fd, fmt, args);
[f74ec77]173 va_end(args);
[a35b458]174
[f74ec77]175 va_start(args, fmt);
176 vprintf(fmt, args);
[7554e41]177 va_end(args);
178}
179
[4e41aa4]180static void print_usage(void)
181{
[6a585dd]182 printf("rcubench [test-name] [k-iterations] [n-threads]\n");
[7554e41]183 printf("Available tests: \n");
[d22e567]184 printf(" sys-futex.. threads make wakeup/sleepdown futex syscalls in a loop\n");
185 printf(" but for separate variables/futex kernel objects.\n");
[7554e41]186 printf(" lock .. threads lock/unlock separate futexes.\n");
187 printf(" sema .. threads down/up separate futexes.\n");
[4e41aa4]188 printf("eg:\n");
[6a585dd]189 printf(" rcubench sys-futex 100000 3\n");
[7554e41]190 printf(" rcubench lock 100000 2 ..runs futex_lock/unlock in a loop\n");
191 printf(" rcubench sema 100000 2 ..runs futex_down/up in a loop\n");
192 printf("Results are stored in %s\n", results_txt);
[4e41aa4]193}
194
[1b20da0]195static bool parse_cmd_line(int argc, char **argv, bench_t *bench,
[4e41aa4]196 const char **err)
197{
[7554e41]198 if (argc < 4) {
199 *err = "Not enough parameters";
[4e41aa4]200 return false;
201 }
202
[7554e41]203 futex_initialize(&bench->bench_fut, 1);
[a35b458]204
[d22e567]205 if (0 == str_cmp(argv[1], "sys-futex")) {
[7554e41]206 bench->func = kernel_futex_bench;
207 } else if (0 == str_cmp(argv[1], "lock")) {
208 bench->func = libc_futex_lock_bench;
209 } else if (0 == str_cmp(argv[1], "sema")) {
210 bench->func = libc_futex_sema_bench;
[4e41aa4]211 } else {
212 *err = "Unknown test name";
213 return false;
214 }
[a35b458]215
[7554e41]216 bench->name = argv[1];
[a35b458]217
[7554e41]218 /* Determine iteration count. */
[4e41aa4]219 uint32_t iter_cnt = 0;
[b7fd2a0]220 errno_t ret = str_uint32_t(argv[2], NULL, 0, true, &iter_cnt);
[4e41aa4]221
222 if (ret == EOK && 1 <= iter_cnt) {
223 bench->iters = iter_cnt;
224 } else {
225 *err = "Err: Invalid number of iterations";
226 return false;
[1b20da0]227 }
[a35b458]228
[7554e41]229 /* Determine thread count. */
[4e41aa4]230 uint32_t thread_cnt = 0;
231 ret = str_uint32_t(argv[3], NULL, 0, true, &thread_cnt);
232
233 if (ret == EOK && 1 <= thread_cnt && thread_cnt <= 64) {
234 bench->nthreads = thread_cnt;
235 } else {
236 *err = "Err: Invalid number of threads";
237 return false;
[1b20da0]238 }
[a35b458]239
[4e41aa4]240 return true;
241}
[a440a0f]242
243int main(int argc, char **argv)
244{
[4e41aa4]245 const char *err = "(error)";
246 bench_t bench;
[a35b458]247
[4e41aa4]248 futex_initialize(&bench.done_threads, 0);
[a35b458]249
[4e41aa4]250 if (!parse_cmd_line(argc, argv, &bench, &err)) {
251 printf("%s\n", err);
252 print_usage();
253 return -1;
254 }
[a35b458]255
[7554e41]256 open_results();
[a35b458]257
[7554e41]258 print_res("Running '%s' futex bench in '%zu' threads with '%zu' iterations.\n",
259 bench.name, bench.nthreads, bench.iters);
[a35b458]260
[4e41aa4]261 struct timeval start, end;
262 getuptime(&start);
[a35b458]263
[4e41aa4]264 run_threads_and_wait(&bench);
[a35b458]265
[4e41aa4]266 getuptime(&end);
[7f9d97f3]267 int64_t duration = tv_sub_diff(&end, &start);
[a35b458]268
[21b703f]269 uint64_t secs = (uint64_t)duration / 1000 / 1000;
[4e41aa4]270 uint64_t total_iters = (uint64_t)bench.iters * bench.nthreads;
[7554e41]271 uint64_t iters_per_sec = 0;
[a35b458]272
[7554e41]273 if (0 < duration) {
274 iters_per_sec = total_iters * 1000 * 1000 / duration;
275 }
[a35b458]276
[1b20da0]277 print_res("Completed %" PRIu64 " iterations in %" PRId64 " usecs (%" PRIu64
278 " secs); %" PRIu64 " iters/sec\n",
279 total_iters, duration, secs, iters_per_sec);
[7554e41]280
281 close_results();
[a35b458]282
[a440a0f]283 return 0;
284}
285
286
287/**
288 * @}
289 */
Note: See TracBrowser for help on using the repository browser.