aboutsummaryrefslogtreecommitdiffstats
path: root/libparc/parc/developer
diff options
context:
space:
mode:
Diffstat (limited to 'libparc/parc/developer')
-rw-r--r--libparc/parc/developer/parc_Stopwatch.c266
-rw-r--r--libparc/parc/developer/parc_Stopwatch.h446
-rwxr-xr-xlibparc/parc/developer/parc_Timing.h238
-rwxr-xr-xlibparc/parc/developer/parc_TimingDarwin.h66
-rwxr-xr-xlibparc/parc/developer/parc_TimingGeneric.h56
-rwxr-xr-xlibparc/parc/developer/parc_TimingIntel.c89
-rwxr-xr-xlibparc/parc/developer/parc_TimingIntel.h102
-rwxr-xr-xlibparc/parc/developer/parc_TimingLinux.h62
-rw-r--r--libparc/parc/developer/test/.gitignore2
-rw-r--r--libparc/parc/developer/test/CMakeLists.txt14
-rw-r--r--libparc/parc/developer/test/test_parc_Stopwatch.c251
-rwxr-xr-xlibparc/parc/developer/test/test_parc_Timing.c127
12 files changed, 1719 insertions, 0 deletions
diff --git a/libparc/parc/developer/parc_Stopwatch.c b/libparc/parc/developer/parc_Stopwatch.c
new file mode 100644
index 00000000..dfd8a200
--- /dev/null
+++ b/libparc/parc/developer/parc_Stopwatch.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <sys/time.h>
+#include <inttypes.h>
+
+#if __APPLE__
+#include <mach/mach.h>
+#include <mach/clock.h>
+#include <mach/mach_time.h>
+#endif
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/developer/parc_Stopwatch.h>
+
+struct PARCStopwatch {
+ uint64_t start;
+// uint64_t stop;
+};
+
+static bool
+_parcStopwatch_Destructor(PARCStopwatch **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCStopwatch pointer.");
+
+ /* cleanup the instance fields here */
+ return true;
+}
+
+parcObject_ImplementAcquire(parcStopwatch, PARCStopwatch);
+
+parcObject_ImplementRelease(parcStopwatch, PARCStopwatch);
+
+parcObject_Override(PARCStopwatch, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcStopwatch_Destructor,
+ .release = (PARCObjectRelease *) parcStopwatch_Release,
+ .copy = (PARCObjectCopy *) parcStopwatch_Copy,
+ .toString = (PARCObjectToString *) parcStopwatch_ToString,
+ .equals = (PARCObjectEquals *) parcStopwatch_Equals,
+ .hashCode = (PARCObjectHashCode *) parcStopwatch_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcStopwatch_ToJSON,
+ .display = (PARCObjectDisplay *) parcStopwatch_Display);
+
+void
+parcStopwatch_AssertValid(const PARCStopwatch *instance)
+{
+ assertTrue(parcStopwatch_IsValid(instance),
+ "PARCStopwatch is not valid.");
+}
+
+
+PARCStopwatch *
+parcStopwatch_Create(void)
+{
+ PARCStopwatch *result = parcObject_CreateInstance(PARCStopwatch);
+
+ if (result != NULL) {
+ result->start = 0;
+ }
+
+ return result;
+}
+
+PARCStopwatch *
+parcStopwatch_Copy(const PARCStopwatch *original)
+{
+ PARCStopwatch *result = parcStopwatch_Create();
+ result->start = original->start;
+
+ return result;
+}
+
+void
+parcStopwatch_Display(const PARCStopwatch *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCStopwatch@%p { .start=%" PRIu64 " }", instance, instance->start);
+}
+
+bool
+parcStopwatch_Equals(const PARCStopwatch *x, const PARCStopwatch *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (memcmp(&x->start, &y->start, sizeof(x->start)) == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcStopwatch_HashCode(const PARCStopwatch *timer)
+{
+ PARCHashCode result = parcHashCode_Hash((uint8_t *) timer, sizeof(PARCStopwatch *));
+ return result;
+}
+
+bool
+parcStopwatch_IsValid(const PARCStopwatch *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcStopwatch_ToJSON(const PARCStopwatch *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ PARCJSON *start = parcJSON_Create();
+ parcJSON_AddInteger(start, "nanoseconds", instance->start);
+
+ parcJSON_AddObject(result, "start", start);
+ parcJSON_Release(&start);
+ }
+
+ return result;
+}
+
+char *
+parcStopwatch_ToString(const PARCStopwatch *instance)
+{
+ char *result = parcMemory_Format("PARCStopwatch@%p={ .start=%" PRIu64 " }", instance, instance->start);
+
+ return result;
+}
+
+#if __linux__
+void
+parcStopwatch_StartImpl(PARCStopwatch *timer, ...)
+{
+ struct timespec theTime;
+ clock_gettime(CLOCK_REALTIME_COARSE, &theTime);
+
+ timer->start = (uint64_t) (theTime.tv_sec * 1000000000) + theTime.tv_nsec;
+
+ va_list ap;
+ va_start(ap, timer);
+ PARCStopwatch *t;
+
+ while ((t = va_arg(ap, PARCStopwatch *)) != NULL) {
+ t->start = timer->start;
+ }
+}
+
+static inline uint64_t
+_parcStopwatch_Stop(PARCStopwatch *timer)
+{
+ struct timespec theTime;
+ clock_gettime(CLOCK_REALTIME_COARSE, &theTime);
+
+ uint64_t result = (uint64_t) (theTime.tv_sec * 1000000000) + theTime.tv_nsec;
+ return result;
+}
+#elif __APPLE__
+
+static mach_timebase_info_data_t _parcStopWatch_TimeBaseInfo;
+
+void
+parcStopwatch_StartImpl(PARCStopwatch *timer, ...)
+{
+ if (_parcStopWatch_TimeBaseInfo.denom == 0) {
+ mach_timebase_info(&_parcStopWatch_TimeBaseInfo);
+ }
+
+ timer->start = mach_absolute_time() * _parcStopWatch_TimeBaseInfo.numer / _parcStopWatch_TimeBaseInfo.denom;
+
+ va_list ap;
+ va_start(ap, timer);
+ PARCStopwatch *t;
+
+ while ((t = va_arg(ap, PARCStopwatch *)) != NULL) {
+ t->start = timer->start;
+ }
+}
+
+static inline uint64_t
+_parcStopwatch_Stop(PARCStopwatch *timer)
+{
+ uint64_t result = mach_absolute_time() * _parcStopWatch_TimeBaseInfo.numer / _parcStopWatch_TimeBaseInfo.denom;
+
+ return result;
+}
+#else
+void
+parcStopwatch_StartImpl(PARCStopwatch *timer, ...)
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ timer->start = (uint64_t) (theTime.tv_sec * 1000000000) + theTime.tv_usec * 1000;
+ va_list ap;
+ va_start(ap, timer);
+ PARCStopwatch *t;
+
+ while ((t = va_arg(ap, PARCStopwatch *)) != NULL) {
+ t->start = timer->start;
+ }
+}
+
+static inline uint64_t
+_parcStopwatch_Stop(PARCStopwatch *timer)
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ uint64_t result = theTime.tv_sec * 1000000000 + theTime.tv_usec * 1000;
+
+ return result;
+}
+#endif
+
+static inline uint64_t
+_parcStopWatch_ElapsedTimeNanos(PARCStopwatch *timer)
+{
+ return (_parcStopwatch_Stop(timer) - timer->start);
+}
+
+uint64_t
+parcStopwatch_ElapsedTimeNanos(PARCStopwatch *timer)
+{
+ return _parcStopWatch_ElapsedTimeNanos(timer);
+}
+
+uint64_t
+parcStopwatch_ElapsedTimeMicros(PARCStopwatch *timer)
+{
+ return _parcStopWatch_ElapsedTimeNanos(timer) / 1000;
+}
+
+uint64_t
+parcStopwatch_ElapsedTimeMillis(PARCStopwatch *timer)
+{
+ return _parcStopWatch_ElapsedTimeNanos(timer) / 1000000;
+}
diff --git a/libparc/parc/developer/parc_Stopwatch.h b/libparc/parc/developer/parc_Stopwatch.h
new file mode 100644
index 00000000..566bd314
--- /dev/null
+++ b/libparc/parc/developer/parc_Stopwatch.h
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Stopwatch.h
+ * @ingroup developer
+ * @brief Measure elapsed time
+ *
+ * A `PARCStopwatch` measures the time elapsed between the invocation of `parcStopwatch_Start()`
+ * and a subsequent invocation of one of the `parcStopwatch_ElapsedTime` functions.
+ * The `parcStopwatch_Start()` function may be called for a stopwatch effectively resetting the stopwatch to a new starting time.
+ *
+ */
+#ifndef PARCLibrary_parc_Stopwatch
+#define PARCLibrary_parc_Stopwatch
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct PARCStopwatch;
+typedef struct PARCStopwatch PARCStopwatch;
+
+/**
+ * Increase the number of references to a `PARCStopwatch` instance.
+ *
+ * Note that new `PARCStopwatch` is not created,
+ * only that the given `PARCStopwatch` reference count is incremented.
+ * Discard the reference by invoking `parcStopwatch_Release`.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCStopwatch *b = parcStopwatch_Acquire();
+ *
+ * parcStopwatch_Release(&a);
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ */
+PARCStopwatch *parcStopwatch_Acquire(const PARCStopwatch *stopwatch);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcStopwatch_OptionalAssertValid(_instance_)
+#else
+# define parcStopwatch_OptionalAssertValid(_instance_) parcStopwatch_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCStopwatch` instance is valid.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ */
+void parcStopwatch_AssertValid(const PARCStopwatch *stopwatch);
+
+/**
+ * Create an instance of PARCStopwatch
+ *
+ * @return non-NULL A pointer to a valid PARCStopwatch instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+PARCStopwatch *parcStopwatch_Create(void);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] other A pointer to a valid PARCStopwatch instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ * PARCStopwatch *b = parcStopwatch_Create();
+ *
+ * if (parcStopwatch_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcStopwatch_Release(&a);
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcStopwatch_Equals
+ */
+int parcStopwatch_Compare(const PARCStopwatch *stopwatch, const PARCStopwatch *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCStopwatch instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCStopwatch` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCStopwatch *copy = parcStopwatch_Copy(&b);
+ *
+ * parcStopwatch_Release(&b);
+ * parcStopwatch_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCStopwatch *parcStopwatch_Copy(const PARCStopwatch *original);
+
+/**
+ * Print a human readable representation of the given `PARCStopwatch`.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_Display(a, 0);
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+void parcStopwatch_Display(const PARCStopwatch *stopwatch, int indentation);
+
+/**
+ * Determine if two `PARCStopwatch` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCStopwatch` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcStopwatch_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcStopwatch_Equals(x, y)` must return true if and only if
+ * `parcStopwatch_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcStopwatch_Equals(x, y)` returns true and
+ * `parcStopwatch_Equals(y, z)` returns true,
+ * then `parcStopwatch_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcStopwatch_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcStopwatch_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCStopwatch instance.
+ * @param [in] y A pointer to a valid PARCStopwatch instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ * PARCStopwatch *b = parcStopwatch_Create();
+ *
+ * if (parcStopwatch_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcStopwatch_Release(&a);
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ * @see parcStopwatch_HashCode
+ */
+bool parcStopwatch_Equals(const PARCStopwatch *x, const PARCStopwatch *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcStopwatch_Equals} method,
+ * then calling the {@link parcStopwatch_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcStopwatch_Equals} function,
+ * then calling the `parcStopwatch_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCHashCode hashValue = parcStopwatch_HashCode(buffer);
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcStopwatch_HashCode(const PARCStopwatch *stopwatch);
+
+/**
+ * Determine if an instance of `PARCStopwatch` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * if (parcStopwatch_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcStopwatch_IsValid(const PARCStopwatch *stopwatch);
+
+/**
+ * Release a previously acquired reference to the given `PARCStopwatch` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+void parcStopwatch_Release(PARCStopwatch **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCStopwatch instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCJSON *json = parcStopwatch_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcStopwatch_ToJSON(const PARCStopwatch *stopwatch);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCStopwatch`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * char *string = parcStopwatch_ToString(a);
+ *
+ * parcStopwatch_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcStopwatch_Display
+ */
+char *parcStopwatch_ToString(const PARCStopwatch *stopwatch);
+
+/**
+ * Start one or more PARCStopwatch instances.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] ... A variable argument list consisting of pointers to valid PARCStopwatch instances.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *A = parcStopwatch_Create();
+ * PARCStopwatch *B = parcStopwatch_Create();
+ * PARCStopwatch *C = parcStopwatch_Create();
+ *
+ * parcStopwatch_Start(A, B, C);
+ *
+ * }
+ * @endcode
+ */
+#define parcStopwatch_Start(...) parcStopwatch_StartImpl(__VA_ARGS__, NULL)
+
+/**
+ * Start one or more PARCStopwatch instances.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] ... A NULL termianted argument list consisting of pointers to valid PARCStopwatch instances.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *stopWatch = parcStopwatch_Create();
+ * parcStopwatch_StartImpl(stopWatch, NULL);
+ * }
+ * @endcode
+ */
+void parcStopwatch_StartImpl(PARCStopwatch *stopwatch, ...);
+
+/**
+ * Get the number of nanoseconds between the time the PARCStopwatch was started and the time of this function call.
+ *
+ * The accuracy is dependant upon the operating environment's time resolution.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The difference between the start and stop times nanoseconds.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcStopwatch_ElapsedTimeNanos(PARCStopwatch *stopwatch);
+
+/**
+ * Get the number of microseconds between the time the PARCStopwatch was started and the time of this function call.
+ *
+ * The accuracy is dependant upon the operating environment's time resolution.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The difference between the start and stop times in microseconds.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcStopwatch_ElapsedTimeMicros(PARCStopwatch *stopwatch);
+
+/**
+ * Get the number of milliseconds between the time the PARCStopwatch was started and the time of this function call.
+ *
+ * The accuracy is dependant upon the operating environment's time resolution.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The difference between the start and stop times in milliseconds.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcStopwatch_ElapsedTimeMillis(PARCStopwatch *stopwatch);
+#endif
diff --git a/libparc/parc/developer/parc_Timing.h b/libparc/parc/developer/parc_Timing.h
new file mode 100755
index 00000000..bd5c3340
--- /dev/null
+++ b/libparc/parc/developer/parc_Timing.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_Timing.h
+ * @ingroup developer
+ * @brief Macros for timing code
+ *
+ * These macros allow the developer to measure time spent in sections of code.
+ * On Intel platforms (i386 or x86_64), the timing is done with the TSC counter, so it will be measured in CPU cycles.
+ * On non-Intel Linux platforms, it will be be done with the nano-second oscillator clock (CLOCK_MONOTONIC_RAW).
+ * On Darwin, it will use the nano-second SYSTEM_CLOCK.
+ * Otherwise, uses gettimeofday(), which will be micro-second timing.
+ *
+ * This set of headers will define several macros for timing:
+ * parcTiming_Init(prefix)
+ * parcTiming_Fini(prefix)
+ * parcTiming_Start(prefix)
+ * parcTiming_Stop(prefix)
+ * (uint64_t) parcTiming_Delta(prefix)
+ *
+ * The units returned from parcTiming_Delta() will be consistent, but not necessarily
+ * related to wall clock time, real time, or any discernable time unit. For example, they
+ * may be in CPU instruction cycles or raw oscillator ticks or nano-seconds.
+ *
+ * These macros only work if the user defines PARCTIMING_ENABLE. Otherwise, they do not
+ * generate any instructions and parcTiming_Delta will always return 0.
+ *
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * // ... other stuff ..
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_Timing_h
+#define libparc_parc_Timing_h
+
+#if defined(PARCTIMING_ENABLE)
+// begin platform detection
+#if defined(__i386__) || defined(__x86_64__)
+#define PARCTIMING_INTEL
+#include <parc/developer/parc_TimingIntel.h>
+#elif defined(__APPLE__)
+#define PARCTIMING_DARWIN
+#include <parc/developer/parc_TimingDarwin.h>
+#elif defined(__linux__)
+#define PARCTIMING_LINUX
+#include <parc/developer/parc_TimingLinux.h>
+#else
+#define PARCTIMING_GENERIC
+#include <parc/developer/parc_TimingGeneric.h>
+#endif // platform detection
+#else // PARCTIMING_ENABLE
+#define _private_parcTiming_Init(prefix)
+#define _private_parcTiming_Start(prefix)
+#define _private_parcTiming_Stop(prefix)
+#define _private_parcTiming_Delta(prefix) ((uint64_t) 0)
+#define _private_parcTiming_Fini(prefix)
+#endif // PARCTIMING_ENABLE
+
+/**
+ * Initialize the timing facility for namespace prefix `prefix`
+ *
+ * Used inside a code block, this macro will define several variables prefixed with
+ * the name `prefix`. It may also allocate memory or system resources. It must be used
+ * within a function scope, not at a global scope.
+ *
+ * You must use parcTiming_Fini(prefix) when done with the timing facility.
+ *
+ * If `PARCTIMING_ENABLE` is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Init(prefix) _private_parcTiming_Init(prefix)
+
+/**
+ * Marks the time in the start variable
+ *
+ * Records the current time in the start variable for use by parcTiming_Delta().
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Start(prefix) _private_parcTiming_Start(prefix)
+
+/**
+ * Marks the time in the stop variable
+ *
+ * Records the current time in the stop variable for use by parcTiming_Delta().
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Stop(prefix) _private_parcTiming_Stop(prefix)
+
+/**
+ * Returns the number of ticks between calls to start and stop.
+ *
+ * The delta will be in whatever units the best clock and provide. It may be CPU cycles
+ * or oscillator ticks, or nanos, or in the worst case micros.
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * @return uint64_t The number of ticks between start and stop
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Delta(prefix) _private_parcTiming_Delta(prefix)
+
+/**
+ * Finalized the timing, releasing any system resources or memory
+ *
+ * Must be called when done with each namespace initialized by parcTiming_Init().
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Fini(prefix) _private_parcTiming_Fini(prefix)
+#endif // libparc_parc_Timing_h
+
diff --git a/libparc/parc/developer/parc_TimingDarwin.h b/libparc/parc/developer/parc_TimingDarwin.h
new file mode 100755
index 00000000..7b2a100e
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingDarwin.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_TimingDarwin.h
+ * @brief Macros for timing code
+ *
+ * On linux will use clock_gettime with the MONOTONIC RAW clock, which does not speed up or slow down based on adj_time().
+ *
+ */
+#ifndef libparc_parc_TimingDarwin_h
+#define libparc_parc_TimingDarwin_h
+
+#ifdef PARCTIMING_DARWIN
+#include <stdint.h>
+#include <time.h>
+#include <mach/mach.h>
+#include <mach/clock.h>
+#include <mach/mach_time.h>
+
+/*
+ * This allocates the clock service which must be released in the Fini macro
+ */
+#define _private_parcTiming_Init(prefix) \
+ clock_serv_t prefix ## _clockService; \
+ mach_timespec_t prefix ## _ts0, prefix ## _ts1; \
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &(prefix ## _clockService));
+
+#define _private_parcTiming_Start(prefix) \
+ clock_get_time((prefix ## _clockService), &(prefix ## _ts0));
+
+#define _private_parcTiming_Stop(prefix) \
+ clock_get_time((prefix ## _clockService), &(prefix ## _ts1));
+
+static inline uint64_t
+_parcTiming_Delta(const mach_timespec_t *t0, const mach_timespec_t *t1)
+{
+ // SUB_MACH_TIMESPEC(t1, t2) => t1 -= t2
+
+ mach_timespec_t delta;
+ memcpy(&delta, t1, sizeof(delta));
+ SUB_MACH_TIMESPEC(&delta, t0);
+
+ return (uint64_t) delta.tv_sec * 1000000000ULL + delta.tv_nsec;
+}
+
+#define _private_parcTiming_Delta(prefix) _parcTiming_Delta(&(prefix ## _ts0), &(prefix ## _ts1))
+
+#define _private_parcTiming_Fini(prefix) \
+ mach_port_deallocate(mach_task_self(), &(prefix ## _clockService));
+
+#endif // PARCTIMING_DARWIN
+#endif // libparc_parc_TimingDarwin_h
+
diff --git a/libparc/parc/developer/parc_TimingGeneric.h b/libparc/parc/developer/parc_TimingGeneric.h
new file mode 100755
index 00000000..8c1d4468
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingGeneric.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_TimingGeneric.h
+ * @brief Macros for timing code
+ *
+ * We cannot do any better than gettimeofday
+ *
+ */
+#ifndef libparc_parc_TimingLinux_h
+#define libparc_parc_TimingLinux_h
+
+#include <stdint.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef PARCTIMING_GENERIC
+
+#define _private_parcTiming_Init(prefix) \
+ struct timeval prefix ## _ts0, prefix ## _ts1, prefix ## _delta;
+
+#define _private_parcTiming_Start(prefix) \
+ gettimeofday(&(prefix ## _ts0), NULL);
+
+#define _private_parcTiming_Stop(prefix) \
+ gettimeofday(&(prefix ## _ts1), NULL);
+
+static inline uint64_t
+_parcTimingGeneric_Delta(const struct timeval *t0, const struct timeval *t1)
+{
+ struct timeval delta;
+ timersub(t1, t0, &delta);
+ return (uint64_t) delta.tv_sec * 1000000ULL + delta.tv_usec;
+}
+
+#define _private_parcTiming_Delta(prefix) _parcTimingGeneric_Delta(&(prefix ## _ts0), &(prefix ## _ts1))
+
+// No teardown work that we need to do
+#define _private_parcTiming_Fini(prefix)
+
+#endif // PARCTIMING_GENERIC
+#endif // libparc_parc_TimingLinux_h
+
diff --git a/libparc/parc/developer/parc_TimingIntel.c b/libparc/parc/developer/parc_TimingIntel.c
new file mode 100755
index 00000000..c690515c
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingIntel.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Executes either the RDTSC or RDTSCP instruction, depending on platform availability
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#define PARCTIMING_ENABLE
+#include <parc/developer/parc_Timing.h>
+
+#ifdef PARCTIMING_INTEL
+static bool _useRdtscp = false;
+static bool _needCheckRdtscp = true;
+
+#include <cpuid.h>
+
+static void
+_checkRdtscp(void)
+{
+ // See the CPUID instruction for description of the codes.
+
+ // determine the maximum extended information set
+ unsigned maxextended = __get_cpuid_max(0x80000000, NULL);
+
+ // RDTSCP status flag is in the 0x800000001 feature set
+ const unsigned feature = 0x80000001;
+ const unsigned rdtscp_feature = 1 << 27;
+
+ if (maxextended >= feature) {
+ unsigned eax, ebx, ecx, edx;
+
+ int success = __get_cpuid(feature, &eax, &ebx, &ecx, &edx);
+ if (success) {
+ _useRdtscp = (edx & rdtscp_feature ? true : false);
+ }
+ }
+}
+#endif // PARCTIMING_INTEL
+
+void
+parcTiminIntel_RuntimeInit(void)
+{
+#ifdef PARCTIMING_INTEL
+ if (_needCheckRdtscp) {
+ _needCheckRdtscp = false;
+ _checkRdtscp();
+ }
+#endif // PARCTIMING_INTEL
+}
+
+void
+parcTimingIntel_rdtsc(unsigned *hi, unsigned *lo)
+{
+ /*
+ * Older CPUs do not support RDTSCP, which is the better instruction to use.
+ * If we did not detect this opcode in autoconf, use the older RDTSC
+ */
+
+#ifdef PARCTIMING_INTEL
+ if (_useRdtscp) {
+ __asm volatile ("RDTSCP\n\t"
+ "mov %%edx,%0\n\t"
+ "mov %%eax,%1\n\t"
+ "CPUID\n\t" : "=r" (*hi), "=r" (*lo):: "%rax", "%rbx", "%rcx", "%rdx");
+ } else {
+ __asm volatile ("RDTSC\n\t"
+ "mov %%edx,%0\n\t"
+ "mov %%eax,%1\n\t"
+ "CPUID\n\t" : "=r" (*hi), "=r" (*lo):: "%rax", "%rbx", "%rcx", "%rdx");
+ }
+#endif // PARCTIMING_INTEL
+}
+
diff --git a/libparc/parc/developer/parc_TimingIntel.h b/libparc/parc/developer/parc_TimingIntel.h
new file mode 100755
index 00000000..4a90896d
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingIntel.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_TimingIntel.h
+ * @ingroup developer
+ * @brief Macros for timing code
+ *
+ * This code uses the Intel recommended benchmarking techniques described
+ * in the whitepaper "How to Benchmakr Code Execution Times on Intel (R) IA-32 and
+ * IA-64 Instruction Set Architectures" available at:
+ *
+ * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf
+ *
+ *
+ */
+#ifndef libparc_parc_TimingIntel_h
+#define libparc_parc_TimingIntel_h
+
+#ifdef PARCTIMING_INTEL
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * Reads the TSC via the best available CPU instruction
+ *
+ * Will execute a RDTSC or RDTSCP instruction followed by an instruction pipeline block
+ * CPUID instruction.
+ *
+ * @param [out] hi The high-order 32-bits
+ * @param [out] lo The low-order 32-bits
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcTimingIntel_rdtsc(unsigned *hi, unsigned *lo);
+
+/**
+ * Checks initialization for RDTSCP instruction availability
+ *
+ * Checks if RDTSCP is availalbe on the system and sets a global.
+ *
+ * Example:
+ * @code
+ * {
+ * parcTiminIntel_RuntimeInit();
+ * }
+ * @endcode
+ */
+void parcTiminIntel_RuntimeInit(void);
+
+#define _private_parcTiming_Init(prefix) \
+ parcTiminIntel_RuntimeInit(); \
+ static unsigned prefix ## _cycles_low0, prefix ## _cycles_high0; \
+ static unsigned prefix ## _cycles_low1, prefix ## _cycles_high1; \
+ \
+ __asm volatile ("CPUID\n\t" "RDTSC\n\t" \
+ "mov %%edx, %0\n\t" \
+ "mov %%eax, %1\n\t" : "=r" (prefix ## _cycles_high0), "=r" (prefix ## _cycles_low0):: \
+ "%rax", "%rbx", "%rcx", "%rdx"); \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high1), &(prefix ## _cycles_low1)); \
+ __asm volatile ("CPUID\n\t" \
+ "RDTSC\n\t" \
+ "mov %%edx, %0\n\t" \
+ "mov %%eax, %1\n\t" : "=r" (prefix ## _cycles_high0), "=r" (prefix ## _cycles_low0):: \
+ "%rax", "%rbx", "%rcx", "%rdx"); \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high1), &(prefix ## _cycles_low1));
+
+#define _private_parcTiming_Start(prefix) \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high0), &(prefix ## _cycles_low0));
+
+#define _private_parcTiming_Stop(prefix) \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high1), &(prefix ## _cycles_low1));
+
+#define _private_parcTiming_CalculateStartTime(prefix) (((uint64_t) prefix ## _cycles_high0 << 32) | prefix ## _cycles_low0)
+#define _private_parcTiming_CalculateStopTime(prefix) (((uint64_t) prefix ## _cycles_high1 << 32) | prefix ## _cycles_low1)
+
+#define _private_parcTiming_Delta(prefix) \
+ (_private_parcTiming_CalculateStopTime(prefix) - _private_parcTiming_CalculateStartTime(prefix))
+
+// No teardown work that we need to do
+#define _private_parcTiming_Fini(prefix)
+
+#endif // PARCTIMING_INTEL
+#endif // libparc_parc_TimingIntel_h
+
diff --git a/libparc/parc/developer/parc_TimingLinux.h b/libparc/parc/developer/parc_TimingLinux.h
new file mode 100755
index 00000000..3dd36205
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingLinux.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file parc_TimingLinux.h
+ * @brief Macros for timing code
+ *
+ * On linux will use clock_gettime with the MONOTONIC RAW clock, which does not speed up or slow down based on adj_time().
+ *
+ */
+#ifndef libparc_parc_TimingLinux_h
+#define libparc_parc_TimingLinux_h
+
+#ifdef PARCTIMING_LINUX
+#include <stdint.h>
+#include <time.h>
+#include <sys/time.h>
+
+#define _private_parcTiming_Init(prefix) \
+ struct timespec prefix ## _ts0, prefix ## _ts1;
+
+#define _private_parcTiming_Start(prefix) \
+ clock_gettime(CLOCK_MONOTONIC_RAW, &(prefix ## _ts0));
+
+#define _private_parcTiming_Stop(prefix) \
+ clock_gettime(CLOCK_MONOTONIC_RAW, &(prefix ## _ts1));
+
+static inline uint64_t
+_parcTimingLinux_Delta(const struct timespec *t0, const struct timespec *t1)
+{
+ struct timespec delta;
+
+ delta.tv_sec = t1->tv_sec - t0->tv_sec;
+ delta.tv_nsec = t1->tv_nsec - t0->tv_nsec;
+ if (delta.tv_nsec < 0) {
+ --delta.tv_sec;
+ delta.tv_nsec += 1000000000;
+ }
+
+ return (uint64_t) delta.tv_sec * 1000000000ULL + delta.tv_nsec;
+}
+
+#define _private_parcTiming_Delta(prefix) _parcTimingLinux_Delta(&(prefix ## _ts0), &(prefix ## _ts1))
+
+// No teardown work that we need to do
+#define _private_parcTiming_Fini(prefix)
+
+#endif // PARCTIMING_LINUX
+#endif // libparc_parc_TimingLinux_h
+
diff --git a/libparc/parc/developer/test/.gitignore b/libparc/parc/developer/test/.gitignore
new file mode 100644
index 00000000..a6e5249b
--- /dev/null
+++ b/libparc/parc/developer/test/.gitignore
@@ -0,0 +1,2 @@
+test_parc_Timing
+test_parc_Timer
diff --git a/libparc/parc/developer/test/CMakeLists.txt b/libparc/parc/developer/test/CMakeLists.txt
new file mode 100644
index 00000000..82cb60e6
--- /dev/null
+++ b/libparc/parc/developer/test/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(TestsExpectedToPass
+ test_parc_Stopwatch
+ test_parc_Timing
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/developer/test/test_parc_Stopwatch.c b/libparc/parc/developer/test/test_parc_Stopwatch.c
new file mode 100644
index 00000000..0f205ec7
--- /dev/null
+++ b/libparc/parc/developer/test/test_parc_Stopwatch.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_Stopwatch.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Timer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Timer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Timer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ assertNotNull(instance, "Expected non-null result from parcStopwatch_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcStopwatch_Acquire, instance);
+
+ parcStopwatch_Release(&instance);
+ assertNull(instance, "Expected null result from parcStopwatch_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_Copy)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ PARCStopwatch *copy = parcStopwatch_Copy(instance);
+ assertTrue(parcStopwatch_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcStopwatch_Release(&instance);
+ parcStopwatch_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_Display)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ parcStopwatch_Display(instance, 0);
+ parcStopwatch_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_Equals)
+{
+ PARCStopwatch *x = parcStopwatch_Create();
+ PARCStopwatch *y = parcStopwatch_Create();
+ PARCStopwatch *z = parcStopwatch_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcStopwatch_Release(&x);
+ parcStopwatch_Release(&y);
+ parcStopwatch_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_HashCode)
+{
+ PARCStopwatch *x = parcStopwatch_Create();
+ PARCStopwatch *y = parcStopwatch_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcStopwatch_Release(&x);
+ parcStopwatch_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_IsValid)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ assertTrue(parcStopwatch_IsValid(instance), "Expected parcStopwatch_Create to result in a valid instance.");
+
+ parcStopwatch_Release(&instance);
+ assertFalse(parcStopwatch_IsValid(instance), "Expected parcStopwatch_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_ToJSON)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+
+ PARCJSON *json = parcStopwatch_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcStopwatch_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_ToString)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+
+ char *string = parcStopwatch_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcStopwatch_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcStopwatch_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcStopwatch_Multi);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcStopwatch_ElapsedTimeNanos);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcStopwatch_Multi)
+{
+ PARCStopwatch *a = parcStopwatch_Create();
+ PARCStopwatch *b = parcStopwatch_Create();
+ PARCStopwatch *c = parcStopwatch_Create();
+
+ parcStopwatch_Start(a, b, c);
+ sleep(2);
+ uint64_t nanos = parcStopwatch_ElapsedTimeNanos(a);
+ printf("%llu %llu\n", nanos, nanos / 1000000000);
+ if (nanos > (3000000000)) {
+ parcStopwatch_Display(a, 0);
+ }
+
+ parcStopwatch_Release(&a);
+ parcStopwatch_Release(&b);
+ parcStopwatch_Release(&c);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcStopwatch_ElapsedTimeNanos)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+
+ parcStopwatch_StartImpl(instance, NULL);
+ sleep(2);
+ uint64_t nanos = parcStopwatch_ElapsedTimeNanos(instance);
+ printf("%llu %llu\n", nanos, nanos / 1000000000);
+ if (nanos > (3000000000)) {
+ parcStopwatch_Display(instance, 0);
+ }
+
+ parcStopwatch_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Timer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/developer/test/test_parc_Timing.c b/libparc/parc/developer/test/test_parc_Timing.c
new file mode 100755
index 00000000..eafa2350
--- /dev/null
+++ b/libparc/parc/developer/test/test_parc_Timing.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#define PARCTIMING_ENABLE 1
+#include "../parc_Timing.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Timing)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Timing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Timing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcTiming_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcTiming_Two);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+_delay(void)
+{
+ int count = 0;
+ for (int i = 0; i < 100000; i++) {
+ count++;
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcTiming_One)
+{
+ parcTiming_Init(foo);
+ parcTiming_Start(foo);
+ _delay();
+ parcTiming_Stop(foo);
+
+ uint64_t delta = parcTiming_Delta(foo);
+
+ assertTrue(delta > 0, "Did not measure a delta, expected positive");
+ parcTiming_Fini(foo);
+}
+
+/*
+ * Test two clocks at the same time
+ */
+LONGBOW_TEST_CASE(Global, parcTiming_Two)
+{
+ parcTiming_Init(outer);
+ parcTiming_Init(inner);
+
+ parcTiming_Start(outer);
+ _delay();
+
+ parcTiming_Start(inner);
+ _delay();
+ parcTiming_Stop(inner);
+
+ parcTiming_Stop(outer);
+
+ uint64_t deltaOuter = parcTiming_Delta(outer);
+ uint64_t deltaInner = parcTiming_Delta(inner);
+
+ assertTrue(deltaOuter > deltaInner,
+ "expected the outer timer to be greater than the inner timer: outer %" PRIu64 ", inner %" PRIu64,
+ deltaOuter, deltaInner);
+
+ printf("outer %" PRIu64 ", inner %" PRIu64, deltaOuter, deltaInner);
+
+ parcTiming_Fini(outer);
+ parcTiming_Fini(inner);
+}
+
+// ===============================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Timing);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}