Changes in / [7acd787:b9f1585] in mainline


Ignore:
Location:
uspace
Files:
6 added
4 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/perf/Makefile

    r7acd787 rb9f1585  
    3434
    3535SOURCES = \
     36        benchlist.c \
    3637        perf.c \
    3738        ipc/ns_ping.c \
  • uspace/app/perf/ipc/ns_ping.c

    r7acd787 rb9f1585  
    2727 */
    2828
    29 #include <math.h>
    3029#include <stdio.h>
    31 #include <stdlib.h>
    32 #include <time.h>
    3330#include <ns.h>
    3431#include <async.h>
    3532#include <errno.h>
     33#include <str_error.h>
     34#include "../benchlist.h"
    3635#include "../perf.h"
    3736
    38 #define MIN_DURATION_SECS  10
    39 #define NUM_SAMPLES 10
     37static bool runner(stopwatch_t *stopwatch, uint64_t niter,
     38    char *error, size_t error_size)
     39{
     40        stopwatch_start(stopwatch);
    4041
    41 static errno_t ping_pong_measure(uint64_t niter, uint64_t *rduration)
    42 {
    43         struct timespec start;
    44         uint64_t count;
     42        for (uint64_t count = 0; count < niter; count++) {
     43                errno_t rc = ns_ping();
    4544
    46         getuptime(&start);
    47 
    48         for (count = 0; count < niter; count++) {
    49                 errno_t retval = ns_ping();
    50 
    51                 if (retval != EOK) {
    52                         printf("Error sending ping message.\n");
    53                         return EIO;
     45                if (rc != EOK) {
     46                        snprintf(error, error_size,
     47                            "failed sending ping message: %s (%d)",
     48                            str_error(rc), rc);
     49                        return false;
    5450                }
    5551        }
    5652
    57         struct timespec now;
    58         getuptime(&now);
     53        stopwatch_stop(stopwatch);
    5954
    60         *rduration = ts_sub_diff(&now, &start) / 1000;
    61         return EOK;
     55        return true;
    6256}
    6357
    64 static void ping_pong_report(uint64_t niter, uint64_t duration)
    65 {
    66         printf("Completed %" PRIu64 " round trips in %" PRIu64 " us",
    67             niter, duration);
    68 
    69         if (duration > 0) {
    70                 printf(", %" PRIu64 " rt/s.\n", niter * 1000 * 1000 / duration);
    71         } else {
    72                 printf(".\n");
    73         }
    74 }
    75 
    76 const char *bench_ns_ping(void)
    77 {
    78         errno_t rc;
    79         uint64_t duration;
    80         uint64_t dsmp[NUM_SAMPLES];
    81 
    82         printf("Warm up and determine work size...\n");
    83 
    84         struct timespec start;
    85         getuptime(&start);
    86 
    87         uint64_t niter = 1;
    88 
    89         while (true) {
    90                 rc = ping_pong_measure(niter, &duration);
    91                 if (rc != EOK)
    92                         return "Failed.";
    93 
    94                 ping_pong_report(niter, duration);
    95 
    96                 if (duration >= MIN_DURATION_SECS * 1000000)
    97                         break;
    98 
    99                 niter *= 2;
    100         }
    101 
    102         printf("Measure %d samples...\n", NUM_SAMPLES);
    103 
    104         int i;
    105 
    106         for (i = 0; i < NUM_SAMPLES; i++) {
    107                 rc = ping_pong_measure(niter, &dsmp[i]);
    108                 if (rc != EOK)
    109                         return "Failed.";
    110 
    111                 ping_pong_report(niter, dsmp[i]);
    112         }
    113 
    114         double sum = 0.0;
    115 
    116         for (i = 0; i < NUM_SAMPLES; i++)
    117                 sum += (double)niter / ((double)dsmp[i] / 1000000.0l);
    118 
    119         double avg = sum / NUM_SAMPLES;
    120 
    121         double qd = 0.0;
    122         double d;
    123         for (i = 0; i < NUM_SAMPLES; i++) {
    124                 d = (double)niter / ((double)dsmp[i] / 1000000.0l) - avg;
    125                 qd += d * d;
    126         }
    127 
    128         double stddev = qd / (NUM_SAMPLES - 1); // XXX sqrt
    129 
    130         printf("Average: %.0f rt/s Std.dev^2: %.0f rt/s Samples: %d\n",
    131             avg, stddev, NUM_SAMPLES);
    132 
    133         return NULL;
    134 }
     58benchmark_t bench_ns_ping = {
     59        .name = "ns_ping",
     60        .desc = "Name service IPC ping-pong benchmark",
     61        .entry = &runner,
     62        .setup = NULL,
     63        .teardown = NULL
     64};
  • uspace/app/perf/ipc/ping_pong.c

    r7acd787 rb9f1585  
    2727 */
    2828
    29 #include <math.h>
    3029#include <stdio.h>
    31 #include <stdlib.h>
    32 #include <time.h>
    3330#include <ipc_test.h>
    3431#include <async.h>
    3532#include <errno.h>
     33#include <str_error.h>
     34#include "../benchlist.h"
    3635#include "../perf.h"
    3736
    38 #define MIN_DURATION_SECS  10
    39 #define NUM_SAMPLES 10
     37static ipc_test_t *test = NULL;
    4038
    41 static errno_t ping_pong_measure(ipc_test_t *test, uint64_t niter,
    42     uint64_t *rduration)
     39static bool setup(char *error, size_t error_size)
    4340{
    44         struct timespec start;
    45         uint64_t count;
     41        errno_t rc = ipc_test_create(&test);
     42        if (rc != EOK) {
     43                snprintf(error, error_size,
     44                    "failed contacting IPC test server: %s (%d)",
     45                    str_error(rc), rc);
     46                return false;
     47        }
    4648
    47         getuptime(&start);
     49        return true;
     50}
    4851
    49         for (count = 0; count < niter; count++) {
    50                 errno_t retval = ipc_test_ping(test);
     52static bool teardown(char *error, size_t error_size)
     53{
     54        ipc_test_destroy(test);
     55        return true;
     56}
    5157
    52                 if (retval != EOK) {
    53                         printf("Error sending ping message.\n");
    54                         return EIO;
     58static bool runner(stopwatch_t *stopwatch, uint64_t niter,
     59    char *error, size_t error_size)
     60{
     61        stopwatch_start(stopwatch);
     62
     63        for (uint64_t count = 0; count < niter; count++) {
     64                errno_t rc = ipc_test_ping(test);
     65
     66                if (rc != EOK) {
     67                        snprintf(error, error_size,
     68                            "failed sending ping message: %s (%d)",
     69                            str_error(rc), rc);
     70                        return false;
    5571                }
    5672        }
    5773
    58         struct timespec now;
    59         getuptime(&now);
     74        stopwatch_stop(stopwatch);
    6075
    61         *rduration = ts_sub_diff(&now, &start) / 1000;
    62         return EOK;
     76        return true;
    6377}
    6478
    65 static void ping_pong_report(uint64_t niter, uint64_t duration)
    66 {
    67         printf("Completed %" PRIu64 " round trips in %" PRIu64 " us",
    68             niter, duration);
    69 
    70         if (duration > 0) {
    71                 printf(", %" PRIu64 " rt/s.\n", niter * 1000 * 1000 / duration);
    72         } else {
    73                 printf(".\n");
    74         }
    75 }
    76 
    77 const char *bench_ping_pong(void)
    78 {
    79         errno_t rc;
    80         uint64_t duration;
    81         uint64_t dsmp[NUM_SAMPLES];
    82         ipc_test_t *test;
    83         const char *msg;
    84 
    85         rc = ipc_test_create(&test);
    86         if (rc != EOK)
    87                 return "Failed contacting IPC test server.";
    88 
    89         printf("Warm up and determine work size...\n");
    90 
    91         struct timespec start;
    92         getuptime(&start);
    93 
    94         uint64_t niter = 1;
    95 
    96         while (true) {
    97                 rc = ping_pong_measure(test, niter, &duration);
    98                 if (rc != EOK) {
    99                         msg = "Failed.";
    100                         goto error;
    101                 }
    102 
    103                 ping_pong_report(niter, duration);
    104 
    105                 if (duration >= MIN_DURATION_SECS * 1000000)
    106                         break;
    107 
    108                 niter *= 2;
    109         }
    110 
    111         printf("Measure %d samples...\n", NUM_SAMPLES);
    112 
    113         int i;
    114 
    115         for (i = 0; i < NUM_SAMPLES; i++) {
    116                 rc = ping_pong_measure(test, niter, &dsmp[i]);
    117                 if (rc != EOK) {
    118                         msg = "Failed.";
    119                         goto error;
    120                 }
    121 
    122                 ping_pong_report(niter, dsmp[i]);
    123         }
    124 
    125         double sum = 0.0;
    126 
    127         for (i = 0; i < NUM_SAMPLES; i++)
    128                 sum += (double)niter / ((double)dsmp[i] / 1000000.0l);
    129 
    130         double avg = sum / NUM_SAMPLES;
    131 
    132         double qd = 0.0;
    133         double d;
    134         for (i = 0; i < NUM_SAMPLES; i++) {
    135                 d = (double)niter / ((double)dsmp[i] / 1000000.0l) - avg;
    136                 qd += d * d;
    137         }
    138 
    139         double stddev = qd / (NUM_SAMPLES - 1); // XXX sqrt
    140 
    141         printf("Average: %.0f rt/s Std.dev^2: %.0f rt/s Samples: %d\n",
    142             avg, stddev, NUM_SAMPLES);
    143 
    144         ipc_test_destroy(test);
    145         return NULL;
    146 error:
    147         ipc_test_destroy(test);
    148         return msg;
    149 }
     79benchmark_t bench_ping_pong = {
     80        .name = "ping_pong",
     81        .desc = "IPC ping-pong benchmark",
     82        .entry = &runner,
     83        .setup = &setup,
     84        .teardown = &teardown
     85};
  • uspace/app/perf/malloc/malloc1.c

    r7acd787 rb9f1585  
    3030#include <stdio.h>
    3131#include <stdlib.h>
    32 #include <time.h>
    33 #include <errno.h>
     32#include "../benchlist.h"
    3433#include "../perf.h"
    3534
    36 #define MIN_DURATION_SECS  10
    37 #define NUM_SAMPLES 10
    38 
    39 static errno_t malloc1_measure(uint64_t niter, uint64_t *rduration)
     35static bool runner(stopwatch_t *stopwatch, uint64_t size,
     36    char *error, size_t error_size)
    4037{
    41         struct timespec start;
    42         uint64_t count;
    43         void *p;
    44 
    45         getuptime(&start);
    46 
    47         for (count = 0; count < niter; count++) {
    48                 p = malloc(1);
    49                 if (p == NULL)
    50                         return ENOMEM;
     38        stopwatch_start(stopwatch);
     39        for (uint64_t i = 0; i < size; i++) {
     40                void *p = malloc(1);
     41                if (p == NULL) {
     42                        snprintf(error, error_size,
     43                            "failed to allocate 1B in run %" PRIu64 " (out of %" PRIu64 ")",
     44                            i, size);
     45                        return false;
     46                }
    5147                free(p);
    5248        }
     49        stopwatch_stop(stopwatch);
    5350
    54         struct timespec now;
    55         getuptime(&now);
    56 
    57         *rduration = ts_sub_diff(&now, &start) / 1000;
    58         return EOK;
     51        return true;
    5952}
    6053
    61 static void malloc1_report(uint64_t niter, uint64_t duration)
    62 {
    63         printf("Completed %" PRIu64 " allocations and deallocations in %" PRIu64 " us",
    64             niter, duration);
    65 
    66         if (duration > 0) {
    67                 printf(", %" PRIu64 " cycles/s.\n", niter * 1000 * 1000 / duration);
    68         } else {
    69                 printf(".\n");
    70         }
    71 }
    72 
    73 const char *bench_malloc1(void)
    74 {
    75         errno_t rc;
    76         uint64_t duration;
    77         uint64_t dsmp[NUM_SAMPLES];
    78         const char *msg;
    79 
    80         printf("Warm up and determine work size...\n");
    81 
    82         struct timespec start;
    83         getuptime(&start);
    84 
    85         uint64_t niter = 1;
    86 
    87         while (true) {
    88                 rc = malloc1_measure(niter, &duration);
    89                 if (rc != EOK) {
    90                         msg = "Failed.";
    91                         goto error;
    92                 }
    93 
    94                 malloc1_report(niter, duration);
    95 
    96                 if (duration >= MIN_DURATION_SECS * 1000000)
    97                         break;
    98 
    99                 niter *= 2;
    100         }
    101 
    102         printf("Measure %d samples...\n", NUM_SAMPLES);
    103 
    104         int i;
    105 
    106         for (i = 0; i < NUM_SAMPLES; i++) {
    107                 rc = malloc1_measure(niter, &dsmp[i]);
    108                 if (rc != EOK) {
    109                         msg = "Failed.";
    110                         goto error;
    111                 }
    112 
    113                 malloc1_report(niter, dsmp[i]);
    114         }
    115 
    116         double sum = 0.0;
    117 
    118         for (i = 0; i < NUM_SAMPLES; i++)
    119                 sum += (double)niter / ((double)dsmp[i] / 1000000.0l);
    120 
    121         double avg = sum / NUM_SAMPLES;
    122 
    123         double qd = 0.0;
    124         double d;
    125         for (i = 0; i < NUM_SAMPLES; i++) {
    126                 d = (double)niter / ((double)dsmp[i] / 1000000.0l) - avg;
    127                 qd += d * d;
    128         }
    129 
    130         double stddev = qd / (NUM_SAMPLES - 1); // XXX sqrt
    131 
    132         printf("Average: %.0f cycles/s Std.dev^2: %.0f cycles/s Samples: %d\n",
    133             avg, stddev, NUM_SAMPLES);
    134 
    135         return NULL;
    136 error:
    137         return msg;
    138 }
     54benchmark_t bench_malloc1 = {
     55        .name = "malloc1",
     56        .desc = "User-space memory allocator benchmark, repeatedly allocate one block",
     57        .entry = &runner,
     58        .setup = NULL,
     59        .teardown = NULL
     60};
  • uspace/app/perf/malloc/malloc2.c

    r7acd787 rb9f1585  
    2727 */
    2828
    29 #include <math.h>
     29#include <stdlib.h>
    3030#include <stdio.h>
    31 #include <stdlib.h>
    32 #include <time.h>
    33 #include <errno.h>
     31#include "../benchlist.h"
    3432#include "../perf.h"
    3533
    36 #define MIN_DURATION_SECS  10
    37 #define NUM_SAMPLES 10
     34static bool runner(stopwatch_t *stopwatch, uint64_t niter,
     35    char *error, size_t error_size)
     36{
     37        stopwatch_start(stopwatch);
    3838
    39 static errno_t malloc2_measure(uint64_t niter, uint64_t *rduration)
    40 {
    41         struct timespec start;
    42         uint64_t count;
    43         void **p;
    44 
    45         getuptime(&start);
    46 
    47         p = malloc(niter * sizeof(void *));
    48         if (p == NULL)
    49                 return ENOMEM;
    50 
    51         for (count = 0; count < niter; count++) {
    52                 p[count] = malloc(1);
    53                 if (p[count] == NULL)
    54                         return ENOMEM;
     39        void **p = malloc(niter * sizeof(void *));
     40        if (p == NULL) {
     41                snprintf(error, error_size,
     42                    "failed to allocate backend array (%" PRIu64 "B)",
     43                    niter * sizeof(void *));
     44                return false;
    5545        }
    5646
    57         for (count = 0; count < niter; count++)
     47        for (uint64_t count = 0; count < niter; count++) {
     48                p[count] = malloc(1);
     49                if (p[count] == NULL) {
     50                        snprintf(error, error_size,
     51                            "failed to allocate 1B in run %" PRIu64 " (out of %" PRIu64 ")",
     52                            count, niter);
     53                        for (uint64_t j = 0; j < count; j++) {
     54                                free(p[j]);
     55                        }
     56                        free(p);
     57                        return false;
     58                }
     59        }
     60
     61        for (uint64_t count = 0; count < niter; count++)
    5862                free(p[count]);
    5963
    6064        free(p);
    6165
    62         struct timespec now;
    63         getuptime(&now);
     66        stopwatch_stop(stopwatch);
    6467
    65         *rduration = ts_sub_diff(&now, &start) / 1000;
    66         return EOK;
     68        return true;
    6769}
    6870
    69 static void malloc2_report(uint64_t niter, uint64_t duration)
    70 {
    71         printf("Completed %" PRIu64 " allocations and deallocations in %" PRIu64 " us",
    72             niter, duration);
    73 
    74         if (duration > 0) {
    75                 printf(", %" PRIu64 " cycles/s.\n", niter * 1000 * 1000 / duration);
    76         } else {
    77                 printf(".\n");
    78         }
    79 }
    80 
    81 const char *bench_malloc2(void)
    82 {
    83         errno_t rc;
    84         uint64_t duration;
    85         uint64_t dsmp[NUM_SAMPLES];
    86         const char *msg;
    87 
    88         printf("Warm up and determine work size...\n");
    89 
    90         struct timespec start;
    91         getuptime(&start);
    92 
    93         uint64_t niter = 1;
    94 
    95         while (true) {
    96                 rc = malloc2_measure(niter, &duration);
    97                 if (rc != EOK) {
    98                         msg = "Failed.";
    99                         goto error;
    100                 }
    101 
    102                 malloc2_report(niter, duration);
    103 
    104                 if (duration >= MIN_DURATION_SECS * 1000000)
    105                         break;
    106 
    107                 niter *= 2;
    108         }
    109 
    110         printf("Measure %d samples...\n", NUM_SAMPLES);
    111 
    112         int i;
    113 
    114         for (i = 0; i < NUM_SAMPLES; i++) {
    115                 rc = malloc2_measure(niter, &dsmp[i]);
    116                 if (rc != EOK) {
    117                         msg = "Failed.";
    118                         goto error;
    119                 }
    120 
    121                 malloc2_report(niter, dsmp[i]);
    122         }
    123 
    124         double sum = 0.0;
    125 
    126         for (i = 0; i < NUM_SAMPLES; i++)
    127                 sum += (double)niter / ((double)dsmp[i] / 1000000.0l);
    128 
    129         double avg = sum / NUM_SAMPLES;
    130 
    131         double qd = 0.0;
    132         double d;
    133         for (i = 0; i < NUM_SAMPLES; i++) {
    134                 d = (double)niter / ((double)dsmp[i] / 1000000.0l) - avg;
    135                 qd += d * d;
    136         }
    137 
    138         double stddev = qd / (NUM_SAMPLES - 1); // XXX sqrt
    139 
    140         printf("Average: %.0f cycles/s Std.dev^2: %.0f cycles/s Samples: %d\n",
    141             avg, stddev, NUM_SAMPLES);
    142 
    143         return NULL;
    144 error:
    145         return msg;
    146 }
     71benchmark_t bench_malloc2 = {
     72        .name = "malloc2",
     73        .desc = "User-space memory allocator benchmark, allocate many small blocks",
     74        .entry = &runner,
     75        .setup = NULL,
     76        .teardown = NULL
     77};
  • uspace/app/perf/perf.c

    r7acd787 rb9f1585  
    11/*
    22 * Copyright (c) 2018 Jiri Svoboda
     3 * Copyright (c) 2018 Vojtech Horky
    34 * All rights reserved.
    45 *
     
    3435 */
    3536
     37#include <assert.h>
     38#include <math.h>
    3639#include <stdio.h>
    3740#include <stddef.h>
    3841#include <stdlib.h>
    3942#include <str.h>
     43#include <time.h>
     44#include <errno.h>
     45#include <perf.h>
     46#include <types/casting.h>
    4047#include "perf.h"
    41 
    42 benchmark_t benchmarks[] = {
    43 #include "ipc/ns_ping.def"
    44 #include "ipc/ping_pong.def"
    45 #include "malloc/malloc1.def"
    46 #include "malloc/malloc2.def"
    47         { NULL, NULL, NULL }
    48 };
     48#include "benchlist.h"
     49
     50#define MIN_DURATION_SECS 10
     51#define NUM_SAMPLES 10
     52#define MAX_ERROR_STR_LENGTH 1024
     53
     54static void short_report(stopwatch_t *stopwatch, int run_index,
     55    benchmark_t *bench, uint64_t workload_size)
     56{
     57        usec_t duration_usec = NSEC2USEC(stopwatch_get_nanos(stopwatch));
     58
     59        printf("Completed %" PRIu64 " operations in %llu us",
     60            workload_size, duration_usec);
     61        if (duration_usec > 0) {
     62                double nanos = stopwatch_get_nanos(stopwatch);
     63                double thruput = (double) workload_size / (nanos / 1000000000.0l);
     64                printf(", %.0f ops/s.\n", thruput);
     65        } else {
     66                printf(".\n");
     67        }
     68}
     69
     70/*
     71 * This is a temporary solution until we have proper sqrt() implementation
     72 * in libmath.
     73 *
     74 * The algorithm uses Babylonian method [1].
     75 *
     76 * [1] https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
     77 */
     78static double estimate_square_root(double value, double precision)
     79{
     80        double estimate = 1.;
     81        double prev_estimate = estimate + 10 * precision;
     82
     83        while (fabs(estimate - prev_estimate) > precision) {
     84                prev_estimate = estimate;
     85                estimate = (prev_estimate + value / prev_estimate) / 2.;
     86        }
     87
     88        return estimate;
     89}
     90
     91/*
     92 * Compute available statistics from given stopwatches.
     93 *
     94 * We compute normal mean for average duration of the workload and geometric
     95 * mean for average thruput. Note that geometric mean is necessary to compute
     96 * average throughput correctly - consider the following example:
     97 *  - we run always 60 operations,
     98 *  - first run executes in 30 s (i.e. 2 ops/s)
     99 *  - and second one in 10 s (6 ops/s).
     100 * Then, naively, average throughput would be (2+6)/2 = 4 [ops/s]. However, we
     101 * actually executed 60 + 60 ops in 30 + 10 seconds. So the actual average
     102 * throughput is 3 ops/s (which is exactly what geometric mean means).
     103 *
     104 */
     105static void compute_stats(stopwatch_t *stopwatch, size_t stopwatch_count,
     106    uint64_t workload_size, double precision, double *out_duration_avg,
     107    double *out_duration_sigma, double *out_thruput_avg)
     108{
     109        double inv_thruput_sum = 0.0;
     110        double nanos_sum = 0.0;
     111        double nanos_sum2 = 0.0;
     112
     113        for (size_t i = 0; i < stopwatch_count; i++) {
     114                double nanos = stopwatch_get_nanos(&stopwatch[i]);
     115                double thruput = (double) workload_size / nanos;
     116
     117                inv_thruput_sum += 1.0 / thruput;
     118                nanos_sum += nanos;
     119                nanos_sum2 += nanos * nanos;
     120        }
     121        *out_duration_avg = nanos_sum / stopwatch_count;
     122        double sigma2 = (nanos_sum2 - nanos_sum * (*out_duration_avg)) /
     123            ((double) stopwatch_count - 1);
     124        // FIXME: implement sqrt properly
     125        *out_duration_sigma = estimate_square_root(sigma2, precision);
     126        *out_thruput_avg = 1.0 / (inv_thruput_sum / stopwatch_count);
     127}
     128
     129static void summary_stats(stopwatch_t *stopwatch, size_t stopwatch_count,
     130    benchmark_t *bench, uint64_t workload_size)
     131{
     132        double duration_avg, duration_sigma, thruput_avg;
     133        compute_stats(stopwatch, stopwatch_count, workload_size, 0.001,
     134            &duration_avg, &duration_sigma, &thruput_avg);
     135
     136        printf("Average: %" PRIu64 " ops in %.0f us (sd %.0f us); "
     137            "%.0f ops/s; Samples: %zu\n",
     138            workload_size, duration_avg / 1000.0, duration_sigma / 1000.0,
     139            thruput_avg * 1000000000.0, stopwatch_count);
     140}
    49141
    50142static bool run_benchmark(benchmark_t *bench)
    51143{
    52         /* Execute the benchmarl */
    53         const char *ret = bench->entry();
    54 
    55         if (ret == NULL) {
    56                 printf("\nBenchmark completed\n");
    57                 return true;
    58         }
    59 
    60         printf("\n%s\n", ret);
    61         return false;
     144        printf("Warm up and determine workload size...\n");
     145
     146        char *error_msg = malloc(MAX_ERROR_STR_LENGTH + 1);
     147        if (error_msg == NULL) {
     148                printf("Out of memory!\n");
     149                return false;
     150        }
     151        str_cpy(error_msg, MAX_ERROR_STR_LENGTH, "");
     152
     153        bool ret = true;
     154
     155        if (bench->setup != NULL) {
     156                ret = bench->setup(error_msg, MAX_ERROR_STR_LENGTH);
     157                if (!ret) {
     158                        goto leave_error;
     159                }
     160        }
     161
     162        /*
     163         * Find workload size that is big enough to last few seconds.
     164         * We also check that uint64_t is big enough.
     165         */
     166        uint64_t workload_size = 0;
     167        for (size_t bits = 0; bits <= 64; bits++) {
     168                if (bits == 64) {
     169                        str_cpy(error_msg, MAX_ERROR_STR_LENGTH, "Workload too small even for 1 << 63");
     170                        goto leave_error;
     171                }
     172                workload_size = ((uint64_t) 1) << bits;
     173
     174                stopwatch_t stopwatch = STOPWATCH_INITIALIZE_STATIC;
     175
     176                bool ok = bench->entry(&stopwatch, workload_size,
     177                    error_msg, MAX_ERROR_STR_LENGTH);
     178                if (!ok) {
     179                        goto leave_error;
     180                }
     181                short_report(&stopwatch, -1, bench, workload_size);
     182
     183                nsec_t duration = stopwatch_get_nanos(&stopwatch);
     184                if (duration > SEC2NSEC(MIN_DURATION_SECS)) {
     185                        break;
     186                }
     187        }
     188
     189        printf("Workload size set to %" PRIu64 ", measuring %d samples.\n", workload_size, NUM_SAMPLES);
     190
     191        stopwatch_t *stopwatch = calloc(NUM_SAMPLES, sizeof(stopwatch_t));
     192        if (stopwatch == NULL) {
     193                snprintf(error_msg, MAX_ERROR_STR_LENGTH, "failed allocating memory");
     194                goto leave_error;
     195        }
     196        for (int i = 0; i < NUM_SAMPLES; i++) {
     197                stopwatch_init(&stopwatch[i]);
     198
     199                bool ok = bench->entry(&stopwatch[i], workload_size,
     200                    error_msg, MAX_ERROR_STR_LENGTH);
     201                if (!ok) {
     202                        free(stopwatch);
     203                        goto leave_error;
     204                }
     205                short_report(&stopwatch[i], i, bench, workload_size);
     206        }
     207
     208        summary_stats(stopwatch, NUM_SAMPLES, bench, workload_size);
     209        printf("\nBenchmark completed\n");
     210
     211        free(stopwatch);
     212
     213        goto leave;
     214
     215leave_error:
     216        printf("Error: %s\n", error_msg);
     217        ret = false;
     218
     219leave:
     220        if (bench->teardown != NULL) {
     221                bool ok = bench->teardown(error_msg, MAX_ERROR_STR_LENGTH);
     222                if (!ok) {
     223                        printf("Error: %s\n", error_msg);
     224                        ret = false;
     225                }
     226        }
     227
     228        free(error_msg);
     229
     230        return ret;
    62231}
    63232
    64233static int run_benchmarks(void)
    65234{
    66         benchmark_t *bench;
    67         unsigned int i = 0;
    68         unsigned int n = 0;
     235        unsigned int count_ok = 0;
     236        unsigned int count_fail = 0;
    69237
    70238        char *failed_names = NULL;
     
    72240        printf("\n*** Running all benchmarks ***\n\n");
    73241
    74         for (bench = benchmarks; bench->name != NULL; bench++) {
    75                 printf("%s (%s)\n", bench->name, bench->desc);
    76                 if (run_benchmark(bench)) {
    77                         i++;
     242        for (size_t it = 0; it < benchmark_count; it++) {
     243                printf("%s (%s)\n", benchmarks[it]->name, benchmarks[it]->desc);
     244                if (run_benchmark(benchmarks[it])) {
     245                        count_ok++;
    78246                        continue;
    79247                }
    80248
    81249                if (!failed_names) {
    82                         failed_names = str_dup(bench->name);
     250                        failed_names = str_dup(benchmarks[it]->name);
    83251                } else {
    84252                        char *f = NULL;
    85                         asprintf(&f, "%s, %s", failed_names, bench->name);
     253                        asprintf(&f, "%s, %s", failed_names, benchmarks[it]->name);
    86254                        if (!f) {
    87255                                printf("Out of memory.\n");
     
    91259                        failed_names = f;
    92260                }
    93                 n++;
    94         }
    95 
    96         printf("\nCompleted, %u benchmarks run, %u succeeded.\n", i + n, i);
     261                count_fail++;
     262        }
     263
     264        printf("\nCompleted, %u benchmarks run, %u succeeded.\n",
     265            count_ok + count_fail, count_ok);
    97266        if (failed_names)
    98267                printf("Failed benchmarks: %s\n", failed_names);
    99268
    100         return n;
     269        return count_fail;
    101270}
    102271
     
    104273{
    105274        size_t len = 0;
    106         benchmark_t *bench;
    107         for (bench = benchmarks; bench->name != NULL; bench++) {
    108                 if (str_length(bench->name) > len)
    109                         len = str_length(bench->name);
    110         }
    111 
    112         unsigned int _len = (unsigned int) len;
    113         if ((_len != len) || (((int) _len) < 0)) {
    114                 printf("Command length overflow\n");
    115                 return;
    116         }
    117 
    118         for (bench = benchmarks; bench->name != NULL; bench++)
    119                 printf("%-*s %s\n", _len, bench->name, bench->desc);
    120 
    121         printf("%-*s Run all benchmarks\n", _len, "*");
     275        for (size_t i = 0; i < benchmark_count; i++) {
     276                size_t len_now = str_length(benchmarks[i]->name);
     277                if (len_now > len)
     278                        len = len_now;
     279        }
     280
     281        assert(can_cast_size_t_to_int(len) && "benchmark name length overflow");
     282
     283        for (size_t i = 0; i < benchmark_count; i++)
     284                printf("%-*s %s\n", (int) len, benchmarks[i]->name, benchmarks[i]->desc);
     285
     286        printf("%-*s Run all benchmarks\n", (int) len, "*");
    122287}
    123288
     
    135300        }
    136301
    137         benchmark_t *bench;
    138         for (bench = benchmarks; bench->name != NULL; bench++) {
    139                 if (str_cmp(argv[1], bench->name) == 0) {
    140                         return (run_benchmark(bench) ? 0 : -1);
     302        for (size_t i = 0; i < benchmark_count; i++) {
     303                if (str_cmp(argv[1], benchmarks[i]->name) == 0) {
     304                        return (run_benchmark(benchmarks[i]) ? 0 : -1);
    141305                }
    142306        }
  • uspace/app/perf/perf.h

    r7acd787 rb9f1585  
    3737
    3838#include <stdbool.h>
     39#include <perf.h>
    3940
    40 typedef const char *(*benchmark_entry_t)(void);
     41typedef bool (*benchmark_entry_t)(stopwatch_t *, uint64_t,
     42    char *, size_t);
     43typedef bool (*benchmark_helper_t)(char *, size_t);
    4144
    4245typedef struct {
     
    4447        const char *desc;
    4548        benchmark_entry_t entry;
     49        benchmark_helper_t setup;
     50        benchmark_helper_t teardown;
    4651} benchmark_t;
    47 
    48 extern const char *bench_malloc1(void);
    49 extern const char *bench_malloc2(void);
    50 extern const char *bench_ns_ping(void);
    51 extern const char *bench_ping_pong(void);
    52 
    53 extern benchmark_t benchmarks[];
    5452
    5553#endif
  • uspace/app/tester/tester.c

    r7acd787 rb9f1585  
    3535 */
    3636
     37#include <assert.h>
    3738#include <stdio.h>
    3839#include <stddef.h>
     
    4041#include <str.h>
    4142#include <io/log.h>
     43#include <types/casting.h>
    4244#include "tester.h"
    4345
     
    144146        }
    145147
    146         unsigned int _len = (unsigned int) len;
    147         if ((_len != len) || (((int) _len) < 0)) {
    148                 printf("Command length overflow\n");
    149                 return;
    150         }
     148        assert(can_cast_size_t_to_int(len) && "test name length overflow");
    151149
    152150        for (test = tests; test->name != NULL; test++)
    153                 printf("%-*s %s%s\n", _len, test->name, test->desc,
     151                printf("%-*s %s%s\n", (int) len, test->name, test->desc,
    154152                    (test->safe ? "" : " (unsafe)"));
    155153
    156         printf("%-*s Run all safe tests\n", _len, "*");
     154        printf("%-*s Run all safe tests\n", (int) len, "*");
    157155}
    158156
  • uspace/lib/c/Makefile

    r7acd787 rb9f1585  
    189189TEST_SOURCES = \
    190190        test/adt/circ_buf.c \
     191        test/casting.c \
    191192        test/fibril/timer.c \
    192193        test/main.c \
     
    196197        test/stdio/scanf.c \
    197198        test/odict.c \
     199        test/perf.c \
    198200        test/perm.c \
    199201        test/qsort.c \
  • uspace/lib/c/test/main.c

    r7acd787 rb9f1585  
    3232PCUT_INIT;
    3333
     34PCUT_IMPORT(casting);
    3435PCUT_IMPORT(circ_buf);
    3536PCUT_IMPORT(fibril_timer);
     
    3738PCUT_IMPORT(mem);
    3839PCUT_IMPORT(odict);
     40PCUT_IMPORT(perf);
    3941PCUT_IMPORT(perm);
    4042PCUT_IMPORT(qsort);
Note: See TracChangeset for help on using the changeset viewer.