source: mainline/uspace/app/rcubench/rcubench.c@ 3061bc1

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

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • Property mode set to 100644
File size: 7.0 KB
Line 
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>
49#include <str.h>
50
51#include <rcu.h>
52
53
54/* Results are printed to this file in addition to stdout. */
55static FILE *results_fd = NULL;
56
57typedef struct bench {
58 const char *name;
59 void (*func)(struct bench *);
60 size_t iters;
61 size_t nthreads;
62 futex_t done_threads;
63
64 futex_t bench_fut;
65} bench_t;
66
67
68
69
70static void kernel_futex_bench(bench_t *bench)
71{
72 const size_t iters = bench->iters;
73 int val = 0;
74
75 for (size_t i = 0; i < iters; ++i) {
76 __SYSCALL1(SYS_FUTEX_WAKEUP, (sysarg_t) &val);
77 __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &val);
78 }
79}
80
81static void libc_futex_lock_bench(bench_t *bench)
82{
83 const size_t iters = bench->iters;
84 futex_t loc_fut = FUTEX_INITIALIZER;
85
86 for (size_t i = 0; i < iters; ++i) {
87 futex_lock(&loc_fut);
88 /* no-op */
89 compiler_barrier();
90 futex_unlock(&loc_fut);
91 }
92}
93
94static void libc_futex_sema_bench(bench_t *bench)
95{
96 const size_t iters = bench->iters;
97 futex_t loc_fut = FUTEX_INITIALIZER;
98
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}
106
107static void thread_func(void *arg)
108{
109 bench_t *bench = (bench_t*)arg;
110
111 bench->func(bench);
112
113 /* Signal another thread completed. */
114 futex_up(&bench->done_threads);
115}
116
117static void run_threads_and_wait(bench_t *bench)
118{
119 assert(1 <= bench->nthreads);
120
121 if (2 <= bench->nthreads) {
122 printf("Creating %zu additional threads...\n", bench->nthreads - 1);
123 }
124
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. */
129 errno_t ret = thread_create(thread_func, bench, "rcubench-t", &tid);
130 if (ret != EOK) {
131 printf("Error: Failed to create benchmark thread.\n");
132 abort();
133 }
134 thread_detach(tid);
135 }
136
137 /*
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);
143
144 printf("Waiting for remaining threads to complete.\n");
145
146 /* Wait for threads to complete. */
147 for (size_t k = 0; k < bench->nthreads; ++k) {
148 futex_down(&bench->done_threads);
149 }
150}
151
152static const char *results_txt = "/tmp/urcu-bench-results.txt";
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;
170
171 va_start(args, fmt);
172 vfprintf(results_fd, fmt, args);
173 va_end(args);
174
175 va_start(args, fmt);
176 vprintf(fmt, args);
177 va_end(args);
178}
179
180static void print_usage(void)
181{
182 printf("rcubench [test-name] [k-iterations] [n-threads]\n");
183 printf("Available tests: \n");
184 printf(" sys-futex.. threads make wakeup/sleepdown futex syscalls in a loop\n");
185 printf(" but for separate variables/futex kernel objects.\n");
186 printf(" lock .. threads lock/unlock separate futexes.\n");
187 printf(" sema .. threads down/up separate futexes.\n");
188 printf("eg:\n");
189 printf(" rcubench sys-futex 100000 3\n");
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);
193}
194
195static bool parse_cmd_line(int argc, char **argv, bench_t *bench,
196 const char **err)
197{
198 if (argc < 4) {
199 *err = "Not enough parameters";
200 return false;
201 }
202
203 futex_initialize(&bench->bench_fut, 1);
204
205 if (0 == str_cmp(argv[1], "sys-futex")) {
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;
211 } else {
212 *err = "Unknown test name";
213 return false;
214 }
215
216 bench->name = argv[1];
217
218 /* Determine iteration count. */
219 uint32_t iter_cnt = 0;
220 errno_t ret = str_uint32_t(argv[2], NULL, 0, true, &iter_cnt);
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;
227 }
228
229 /* Determine thread count. */
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;
238 }
239
240 return true;
241}
242
243int main(int argc, char **argv)
244{
245 const char *err = "(error)";
246 bench_t bench;
247
248 futex_initialize(&bench.done_threads, 0);
249
250 if (!parse_cmd_line(argc, argv, &bench, &err)) {
251 printf("%s\n", err);
252 print_usage();
253 return -1;
254 }
255
256 open_results();
257
258 print_res("Running '%s' futex bench in '%zu' threads with '%zu' iterations.\n",
259 bench.name, bench.nthreads, bench.iters);
260
261 struct timeval start, end;
262 getuptime(&start);
263
264 run_threads_and_wait(&bench);
265
266 getuptime(&end);
267 int64_t duration = tv_sub_diff(&end, &start);
268
269 uint64_t secs = (uint64_t)duration / 1000 / 1000;
270 uint64_t total_iters = (uint64_t)bench.iters * bench.nthreads;
271 uint64_t iters_per_sec = 0;
272
273 if (0 < duration) {
274 iters_per_sec = total_iters * 1000 * 1000 / duration;
275 }
276
277 print_res("Completed %" PRIu64 " iterations in %" PRId64 " usecs (%" PRIu64
278 " secs); %" PRIu64 " iters/sec\n",
279 total_iters, duration, secs, iters_per_sec);
280
281 close_results();
282
283 return 0;
284}
285
286
287/**
288 * @}
289 */
Note: See TracBrowser for help on using the repository browser.