Changeset 4e41aa4 in mainline


Ignore:
Timestamp:
2012-12-03T18:47:08Z (11 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
21b703f
Parents:
a440a0f
Message:

Added kernel and libc futex benchmark to rcubench.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/rcubench/rcubench.c

    ra440a0f r4e41aa4  
    5050#include <rcu.h>
    5151
     52typedef struct bench {
     53        enum {
     54                T_KERN_FUTEX,
     55                T_LIBC_FUTEX
     56        } type;
     57        size_t iters;
     58        size_t nthreads;
     59        size_t array_size;
     60        size_t *array;
     61        futex_t done_threads;
     62       
     63        futex_t ke_bench_fut;
     64        fibril_mutex_t libc_bench_mtx;
     65} bench_t;
     66
     67
     68/* Combats compiler optimizations. */
     69static volatile size_t dummy = 0;
     70
     71static size_t sum_array(size_t *array, size_t len)
     72{
     73        size_t sum = 0;
     74       
     75        for (size_t k = 0; k < len; ++k)
     76                sum += array[k];
     77       
     78        return sum;
     79}
     80
     81static void  kernel_futex_bench(bench_t *bench)
     82{
     83        futex_t * const fut = &bench->ke_bench_fut;
     84        const size_t iters = bench->iters;
     85        size_t sum = 0;
     86       
     87        for (size_t i = 0; i < iters; ++i) {
     88                /* Do some work with the futex locked to encourage contention. */
     89                futex_down(fut);
     90                sum += sum_array(bench->array, bench->array_size);
     91                futex_up(fut);
     92               
     93                /*
     94                 * Do half as much work to give other threads a chance to acquire
     95                 * the futex.
     96                 */
     97                sum += sum_array(bench->array, bench->array_size / 2);
     98        }
     99       
     100        /*
     101         * Writing to a global volatile variable separated with a cc-barrier
     102         * should discourage the compiler from optimizing away sum_array()s.
     103         */
     104        compiler_barrier();
     105        dummy = sum;
     106}
     107
     108static void libc_futex_bench(bench_t *bench)
     109{
     110        fibril_mutex_t * const mtx = &bench->libc_bench_mtx;
     111        const size_t iters = bench->iters;
     112       
     113        for (size_t i = 0; i < iters; ++i) {
     114                fibril_mutex_lock(mtx);
     115                /* no-op */
     116                compiler_barrier();
     117                fibril_mutex_unlock(mtx);
     118        }
     119}
     120
     121
     122static void thread_func(void *arg)
     123{
     124        bench_t *bench = (bench_t*)arg;
     125        assert(bench->type == T_KERN_FUTEX || bench->type == T_LIBC_FUTEX);
     126       
     127        if (bench->type == T_KERN_FUTEX)
     128                kernel_futex_bench(bench);
     129        else
     130                libc_futex_bench(bench);
     131       
     132        /* Signal another thread completed. */
     133        futex_up(&bench->done_threads);
     134}
     135
     136static void run_threads_and_wait(bench_t *bench)
     137{
     138        assert(1 <= bench->nthreads);
     139       
     140        if (2 <= bench->nthreads) {
     141                printf("Creating %zu additional threads...\n", bench->nthreads - 1);
     142        }
     143       
     144        /* Create and run the first nthreads - 1 threads.*/
     145        for (size_t k = 1; k < bench->nthreads; ++k) {
     146                thread_id_t tid;
     147                /* Also sets up a fibril for the thread. */
     148                int ret = thread_create(thread_func, bench, "rcubench-t", &tid);
     149                if (ret != EOK) {
     150                        printf("Error: Failed to create benchmark thread.\n");
     151                        abort();
     152                }
     153                thread_detach(tid);
     154        }
     155       
     156        /*
     157         * Run the last thread in place so that we create multiple threads
     158         * only when needed. Otherwise libc would immediately upgrade
     159         * single-threaded futexes to proper multithreaded futexes
     160         */
     161        thread_func(bench);
     162       
     163        printf("Waiting for remaining threads to complete.\n");
     164       
     165        /* Wait for threads to complete. */
     166        for (size_t k = 0; k < bench->nthreads; ++k) {
     167                futex_down(&bench->done_threads);
     168        }
     169}
     170
     171static void print_usage(void)
     172{
     173        printf("rcubench [test-name] [k-iterations] [n-threads] {work-size}\n");
     174        printf("eg:\n");
     175        printf("  rcubench ke   100000 3 4\n");
     176        printf("  rcubench libc 100000 2\n");
     177        printf("  rcubench def-ke  \n");
     178        printf("  rcubench def-libc\n");
     179}
     180
     181static bool parse_cmd_line(int argc, char **argv, bench_t *bench,
     182        const char **err)
     183{
     184        if (argc < 2) {
     185                *err = "Benchmark name not specified";
     186                return false;
     187        }
     188
     189        futex_initialize(&bench->ke_bench_fut, 1);
     190        fibril_mutex_initialize(&bench->libc_bench_mtx);
     191       
     192        if (0 == str_cmp(argv[1], "def-ke")) {
     193                bench->type = T_KERN_FUTEX;
     194                bench->nthreads = 4;
     195                bench->iters = 1000 * 1000;
     196                bench->array_size = 10;
     197                bench->array = malloc(bench->array_size * sizeof(size_t));
     198                return NULL != bench->array;
     199        } else if (0 == str_cmp(argv[1], "def-libc")) {
     200                bench->type = T_LIBC_FUTEX;
     201                bench->nthreads = 4;
     202                bench->iters = 1000 * 1000;
     203                bench->array_size = 0;
     204                bench->array = NULL;
     205                return true;
     206        } else if (0 == str_cmp(argv[1], "ke")) {
     207                bench->type = T_KERN_FUTEX;
     208        } else if (0 == str_cmp(argv[1], "libc")) {
     209                bench->type = T_LIBC_FUTEX;
     210        } else {
     211                *err = "Unknown test name";
     212                return false;
     213        }
     214       
     215        if (argc < 4) {
     216                *err = "Not enough parameters";
     217                return false;
     218        }
     219       
     220        uint32_t iter_cnt = 0;
     221        int ret = str_uint32_t(argv[2], NULL, 0, true, &iter_cnt);
     222
     223        if (ret == EOK && 1 <= iter_cnt) {
     224                bench->iters = iter_cnt;
     225        } else {
     226                *err = "Err: Invalid number of iterations";
     227                return false;
     228        }
     229       
     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        if (argc > 4) {
     241                uint32_t work_size = 0;
     242                ret = str_uint32_t(argv[4], NULL, 0, true, &work_size);
     243
     244                if (ret == EOK && work_size <= 10000) {
     245                        bench->array_size = work_size;
     246                } else {
     247                        *err = "Err: Work size too large";
     248                        return false;
     249                }
     250        } else {
     251                bench->array_size = 0;
     252        }
     253       
     254        if (0 < bench->array_size) {
     255                bench->array = malloc(bench->array_size * sizeof(size_t));
     256                if (!bench->array) {
     257                        *err = "Err: Failed to allocate work array";
     258                        return false;
     259                }
     260        } else {
     261                bench->array = NULL;
     262        }
     263       
     264        return true;
     265}
    52266
    53267int main(int argc, char **argv)
    54268{
    55         printf("hello!\n");
     269        const char *err = "(error)";
     270        bench_t bench;
     271       
     272        futex_initialize(&bench.done_threads, 0);
     273       
     274        if (!parse_cmd_line(argc, argv, &bench, &err)) {
     275                printf("%s\n", err);
     276                print_usage();
     277                return -1;
     278        }
     279       
     280        printf("Running '%s' futex bench in '%zu' threads with '%zu' iterations.\n",
     281                bench.type == T_KERN_FUTEX ? "kernel" : "libc",
     282                bench.nthreads, bench.iters);
     283       
     284        struct timeval start, end;
     285        getuptime(&start);
     286       
     287        run_threads_and_wait(&bench);
     288       
     289        getuptime(&end);
     290        int64_t duration = tv_sub(&end, &start);
     291       
     292        uint64_t total_iters = (uint64_t)bench.iters * bench.nthreads;
     293        uint64_t iters_per_sec = total_iters * 1000 * 1000 / duration;
     294        uint64_t secs = (uint64_t)duration / 1000 / 1000;
     295       
     296        printf("Completed %" PRIu64 " iterations in %" PRId64  " usecs (%" PRIu64
     297                " secs); %" PRIu64 " iters/sec\n",
     298                total_iters, duration, secs, iters_per_sec);   
     299       
    56300        return 0;
    57301}
Note: See TracChangeset for help on using the changeset viewer.