DO NO COMMIT - randhammer test app
Change-Id: Ia3b456f394225feb0ac5f0b71a5e10feae47fa9a
diff --git a/system/uapp/randhammer/randhammer b/system/uapp/randhammer/randhammer
new file mode 100755
index 0000000..fe2befa
--- /dev/null
+++ b/system/uapp/randhammer/randhammer
Binary files differ
diff --git a/system/uapp/randhammer/randhammer-host.cpp b/system/uapp/randhammer/randhammer-host.cpp
new file mode 100644
index 0000000..c7c043b
--- /dev/null
+++ b/system/uapp/randhammer/randhammer-host.cpp
@@ -0,0 +1,123 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#define ZX_CPRNG_DRAW_MAX_LEN 256
+
+const int kDefaultMaxWorkers = 64;
+const size_t kTotalDrawLen = 1UL << 24;
+
+typedef struct {
+ std::mutex mtx;
+ std::condition_variable cnd;
+ bool waved;
+} green_flag_t;
+
+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);
+}
+
+void worker(green_flag_t* green_flag) {
+ ssize_t rc;
+
+ uint8_t buf[ZX_CPRNG_DRAW_MAX_LEN];
+ size_t iters = kTotalDrawLen / ZX_CPRNG_DRAW_MAX_LEN;
+ size_t actual;
+
+ int fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ perror("open('udev/random', O_RDONLY)");
+ return;
+ }
+
+ {
+ std::unique_lock<std::mutex> guard(green_flag->mtx);
+ if (!green_flag->waved && green_flag->cnd.wait_for(guard, std::chrono::seconds(10)) == std::cv_status::timeout) {
+ printf("timeout\n");
+ return;
+ }
+ }
+
+ for (size_t i = 0; i < iters; ++i) {
+ if ((rc = read(fd, buf, sizeof(buf))) < 0) {
+ perror("read");
+ return;
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+ 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 EINVAL;
+ }
+
+ green_flag_t green_flag;
+ std::vector<std::thread> threads;
+ struct timespec tp;
+ uint64_t start, finish, per_call;
+ for (int num_workers = 1; num_workers <= max_workers; ++num_workers) {
+ {
+ std::unique_lock<std::mutex> guard(green_flag.mtx);
+ threads.clear();
+ green_flag.waved = false;
+
+ for (int i = 0; i < num_workers; ++i) {
+ threads.push_back(std::thread(worker, &green_flag));
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) < 0) {
+ perror("clock_gettime");
+ return errno;
+ }
+ start = (tp.tv_sec * 1000000000) + tp.tv_nsec;
+ green_flag.waved = true;
+ green_flag.cnd.notify_all();
+ }
+
+ for (auto& thrd : threads) {
+ thrd.join();
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) < 0) {
+ perror("clock_gettime");
+ return errno;
+ }
+ finish = (tp.tv_sec * 1000000000) + tp.tv_nsec;
+ 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);
+ }
+
+ return 0;
+}
diff --git a/system/uapp/randhammer/randhammer.cpp b/system/uapp/randhammer/randhammer.cpp
new file mode 100644
index 0000000..94ce797
--- /dev/null
+++ b/system/uapp/randhammer/randhammer.cpp
@@ -0,0 +1,115 @@
+// 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;
+}
diff --git a/system/uapp/randhammer/rules.mk b/system/uapp/randhammer/rules.mk
new file mode 100644
index 0000000..346abee
--- /dev/null
+++ b/system/uapp/randhammer/rules.mk
@@ -0,0 +1,22 @@
+# 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.
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_TYPE := userapp
+MODULE_GROUP := core
+
+MODULE_SRCS += $(LOCAL_DIR)/randhammer.cpp
+
+MODULE_STATIC_LIBS := \
+ system/ulib/zx \
+
+MODULE_LIBS := \
+ system/ulib/fdio \
+ system/ulib/zircon \
+ system/ulib/c \
+
+include make/module.mk