[perftest] Add test for zx_nanosleep() using a range of sleep times

This acts as an example of a parameterized test.  It's also useful in
its own right for measuring the overhead and variation of sleeping.

Add a convenience function for registering parameterized tests.

ZX-1715

Change-Id: I9f0b25e86e9488016d0783577bfa8ef980f848bc
diff --git a/system/ulib/perftest/include/perftest/perftest.h b/system/ulib/perftest/include/perftest/perftest.h
index c6bcfc2..68ab3fb 100644
--- a/system/ulib/perftest/include/perftest/perftest.h
+++ b/system/ulib/perftest/include/perftest/perftest.h
@@ -71,6 +71,15 @@
 
 void RegisterTest(const char* name, fbl::Function<TestFunc> test_func);
 
+// Convenience routine for registering parameterized perf tests.
+template <typename Func, typename Arg, typename... Args>
+void RegisterTest(const char* name, Func test_func, Arg arg, Args... args) {
+    auto wrapper_func = [=](RepeatState* state) {
+        return test_func(state, arg, args...);
+    };
+    RegisterTest(name, wrapper_func);
+}
+
 // Convenience routine for registering a perf test that is specified by a
 // function.  This is for tests that don't set up any fixtures that are
 // shared across invocations of the function.
diff --git a/system/utest/perftest/rules.mk b/system/utest/perftest/rules.mk
index 047fda4..c5e8abe 100644
--- a/system/utest/perftest/rules.mk
+++ b/system/utest/perftest/rules.mk
@@ -11,6 +11,7 @@
 MODULE_SRCS += \
     $(LOCAL_DIR)/results-test.cpp \
     $(LOCAL_DIR)/runner-test.cpp \
+    $(LOCAL_DIR)/sleep-test.cpp \
     $(LOCAL_DIR)/syscalls-test.cpp \
 
 MODULE_NAME := perf-test
diff --git a/system/utest/perftest/sleep-test.cpp b/system/utest/perftest/sleep-test.cpp
new file mode 100644
index 0000000..d860657
--- /dev/null
+++ b/system/utest/perftest/sleep-test.cpp
@@ -0,0 +1,48 @@
+// 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 <fbl/string_printf.h>
+#include <perftest/perftest.h>
+#include <zircon/assert.h>
+#include <zircon/syscalls.h>
+
+namespace {
+
+// Test sleeping for different lengths of time.
+//
+// This serves an example of a parameterized perf test.
+//
+// This can be useful for measuring the overhead of sleeping.  It can also
+// be used to measure the variation in actual sleep times.  Checking for
+// under-sleeps and over-sleeps can serve as a sanity check for the
+// perftest framework.
+//
+// Ideally we would be able to test a continuous range of sleep times,
+// which might reveal discontinuities in the actual sleep times.  The
+// perftest framework does not support this yet.
+bool SleepTest(perftest::RepeatState* state, zx_duration_t delay_ns) {
+    while (state->KeepRunning()) {
+        ZX_ASSERT(zx_nanosleep(zx_deadline_after(delay_ns)) == ZX_OK);
+    }
+    return true;
+}
+
+void RegisterTests() {
+    static const zx_duration_t kTimesNs[] = {
+        0,
+        1,
+        10,
+        100,
+        1000,
+        10000,
+    };
+    for (auto time_ns : kTimesNs) {
+        auto name = fbl::StringPrintf(
+            "Sleep/%lluns", static_cast<unsigned long long>(time_ns));
+        perftest::RegisterTest(name.c_str(), SleepTest, time_ns);
+    }
+}
+PERFTEST_CTOR(RegisterTests);
+
+}  // namespace