blob: 94ce797a6b9c30ec8c2dc488bf3f7c6ca0008276 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <zx/event.h>
#include <zx/time.h>
const int kDefaultMaxWorkers = 64;
const size_t kTotalDrawLen = 1UL << 24;
void print_usage(const char* argv0) {
printf("usage: %s [-n <num_workers>]\n\n", argv0);
printf("Spawn threads to zx_crpng_draw %zu bytes.\n\n", kTotalDrawLen);
printf("-n <num_workers> Specifies the max number of threads.\n");
printf(" Defaults to %d.\n", kDefaultMaxWorkers);
}
int worker(void* arg) {
zx_status_t rc;
uint8_t buf[ZX_CPRNG_DRAW_MAX_LEN];
size_t iters = kTotalDrawLen / ZX_CPRNG_DRAW_MAX_LEN;
size_t actual;
zx::event* green_flag = static_cast<zx::event*>(arg);
zx_signals_t observed;
if ((rc = green_flag->wait_one(ZX_USER_SIGNAL_0,
zx::deadline_after(zx::sec(10)),
&observed)) != ZX_OK) {
printf("event::wait_one failed: %s\n", zx_status_get_string(rc));
return rc;
}
for (size_t i = 0; i < iters; ++i) {
if ((rc = zx_cprng_draw(buf, sizeof(buf), &actual)) != ZX_OK) {
return rc;
}
}
return ZX_OK;
}
int main(int argc, char** argv) {
zx_status_t rc;
int max_workers;
switch (argc) {
case 1:
max_workers = kDefaultMaxWorkers;
break;
case 3:
max_workers = atoi(argv[2]);
if (strcmp(argv[1], "-n") == 0 && max_workers > 0) {
break;
}
// fall through
default:
print_usage(argv[0]);
return ZX_ERR_INVALID_ARGS;
}
zx::event green_flag;
if ((rc = zx::event::create(0, &green_flag)) != ZX_OK) {
printf("zx::event::create failed: %s\n", zx_status_get_string(rc));
return rc;
}
for (int num_workers = 1; num_workers <= max_workers; ++num_workers) {
if ((rc = green_flag.signal(ZX_USER_SIGNAL_0, 0)) != ZX_OK) {
printf("zx::event::signal failed: %s\n", zx_status_get_string(rc));
return rc;
}
thrd_t tids[num_workers];
zx_status_t rcs[num_workers];
for (int i = 0; i < num_workers; ++i) {
if (thrd_create(&tids[i], worker, &green_flag) != thrd_success) {
printf("failed to start worker %d\n", i);
return ZX_ERR_NO_RESOURCES;
}
}
zx::time start = zx::clock::get(ZX_CLOCK_MONOTONIC);
if ((rc = green_flag.signal(0, ZX_USER_SIGNAL_0)) != ZX_OK) {
printf("zx::event::signal failed: %s\n", zx_status_get_string(rc));
return rc;
}
for (int i = 0; i < num_workers; ++i) {
thrd_join(tids[i], &rcs[i]);
}
zx::time finish = zx::clock::get(ZX_CLOCK_MONOTONIC);
for (int i = 0; i < num_workers; ++i) {
if (rcs[i] != ZX_OK) {
printf("worker %d returned %s\n", i, zx_status_get_string(rcs[i]));
}
}
zx::duration per_call = (finish - start) / ((kTotalDrawLen / 1024) * num_workers);
printf("%d workers, %zu bytes, %d bytes/call => %" PRIu64 " ns/kb.\n",
num_workers, kTotalDrawLen, ZX_CPRNG_DRAW_MAX_LEN, per_call.get());
}
return 0;
}