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
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.