Index: third_party/grpc/test/core/statistics/trace_test.c |
diff --git a/third_party/grpc/test/core/statistics/trace_test.c b/third_party/grpc/test/core/statistics/trace_test.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..75904040ff7fc7379bdf9efa7dd16f0b2eb3e734 |
--- /dev/null |
+++ b/third_party/grpc/test/core/statistics/trace_test.c |
@@ -0,0 +1,255 @@ |
+/* |
+ * |
+ * Copyright 2015, Google Inc. |
+ * All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions are |
+ * met: |
+ * |
+ * * Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * * Redistributions in binary form must reproduce the above |
+ * copyright notice, this list of conditions and the following disclaimer |
+ * in the documentation and/or other materials provided with the |
+ * distribution. |
+ * * Neither the name of Google Inc. nor the names of its |
+ * contributors may be used to endorse or promote products derived from |
+ * this software without specific prior written permission. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ * |
+ */ |
+ |
+#include <string.h> |
+#include <stdio.h> |
+ |
+#include "src/core/statistics/census_interface.h" |
+#include "src/core/statistics/census_tracing.h" |
+#include "src/core/statistics/census_tracing.h" |
+#include <grpc/support/alloc.h> |
+#include <grpc/support/log.h> |
+#include <grpc/support/port_platform.h> |
+#include <grpc/support/sync.h> |
+#include <grpc/support/thd.h> |
+#include <grpc/support/time.h> |
+#include <grpc/support/useful.h> |
+#include "test/core/util/test_config.h" |
+ |
+/* Ensure all possible state transitions are called without causing problem */ |
+static void test_init_shutdown(void) { |
+ census_tracing_init(); |
+ census_tracing_init(); |
+ census_tracing_shutdown(); |
+ census_tracing_shutdown(); |
+ census_tracing_init(); |
+} |
+ |
+static void test_start_op_generates_locally_unique_ids(void) { |
+/* Check that ids generated within window size of 1000 are unique. |
+ TODO(hongyu): Replace O(n^2) duplicate detection algorithm with O(nlogn) |
+ algorithm. Enhance the test to larger window size (>10^6) */ |
+#define WINDOW_SIZE 1000 |
+ census_op_id ids[WINDOW_SIZE]; |
+ int i; |
+ census_init(); |
+ for (i = 0; i < WINDOW_SIZE; i++) { |
+ ids[i] = census_tracing_start_op(); |
+ census_tracing_end_op(ids[i]); |
+ } |
+ for (i = 0; i < WINDOW_SIZE - 1; i++) { |
+ int j; |
+ for (j = i + 1; j < WINDOW_SIZE; j++) { |
+ GPR_ASSERT(ids[i].upper != ids[j].upper || ids[i].lower != ids[j].lower); |
+ } |
+ } |
+#undef WINDOW_SIZE |
+ census_shutdown(); |
+} |
+ |
+static void test_get_trace_method_name(void) { |
+ census_op_id id; |
+ const char write_name[] = "service/method"; |
+ census_tracing_init(); |
+ id = census_tracing_start_op(); |
+ census_add_method_tag(id, write_name); |
+ census_internal_lock_trace_store(); |
+ { |
+ const char *read_name = |
+ census_get_trace_method_name(census_get_trace_obj_locked(id)); |
+ GPR_ASSERT(strcmp(read_name, write_name) == 0); |
+ } |
+ census_internal_unlock_trace_store(); |
+ census_tracing_shutdown(); |
+} |
+ |
+typedef struct thd_arg { |
+ int num_done; |
+ gpr_cv done; |
+ gpr_mu mu; |
+} thd_arg; |
+ |
+static void mimic_trace_op_sequences(void *arg) { |
+ census_op_id id; |
+ const char *method_name = "service_foo/method_bar"; |
+ int i = 0; |
+ const int num_iter = 200; |
+ thd_arg *args = (thd_arg *)arg; |
+ GPR_ASSERT(args != NULL); |
+ gpr_log(GPR_INFO, "Start trace op sequence thread."); |
+ for (i = 0; i < num_iter; i++) { |
+ id = census_tracing_start_op(); |
+ census_add_method_tag(id, method_name); |
+ /* pretend doing 1us work. */ |
+ gpr_sleep_until(GRPC_TIMEOUT_MICROS_TO_DEADLINE(1)); |
+ census_tracing_end_op(id); |
+ } |
+ gpr_log(GPR_INFO, "End trace op sequence thread."); |
+ gpr_mu_lock(&args->mu); |
+ args->num_done += 1; |
+ gpr_cv_broadcast(&args->done); |
+ gpr_mu_unlock(&args->mu); |
+} |
+ |
+static void test_concurrency(void) { |
+#define NUM_THREADS 1000 |
+ gpr_thd_id tid[NUM_THREADS]; |
+ int i = 0; |
+ thd_arg arg; |
+ arg.num_done = 0; |
+ gpr_mu_init(&arg.mu); |
+ gpr_cv_init(&arg.done); |
+ census_tracing_init(); |
+ for (i = 0; i < NUM_THREADS; ++i) { |
+ gpr_thd_new(tid + i, mimic_trace_op_sequences, &arg, NULL); |
+ } |
+ gpr_mu_lock(&arg.mu); |
+ while (arg.num_done < NUM_THREADS) { |
+ gpr_log(GPR_INFO, "num done %d", arg.num_done); |
+ gpr_cv_wait(&arg.done, &arg.mu, gpr_inf_future(GPR_CLOCK_REALTIME)); |
+ } |
+ gpr_mu_unlock(&arg.mu); |
+ census_tracing_shutdown(); |
+#undef NUM_THREADS |
+} |
+ |
+static void test_add_method_tag_to_unknown_op_id(void) { |
+ census_op_id unknown_id = {0xDEAD, 0xBEEF}; |
+ int ret = 0; |
+ census_tracing_init(); |
+ ret = census_add_method_tag(unknown_id, "foo"); |
+ GPR_ASSERT(ret != 0); |
+ census_tracing_shutdown(); |
+} |
+ |
+static void test_trace_print(void) { |
+ census_op_id id; |
+ int i; |
+ const char *annotation_txt[4] = {"abc", "", "$%^ *()_"}; |
+ char long_txt[CENSUS_MAX_ANNOTATION_LENGTH + 10]; |
+ |
+ memset(long_txt, 'a', GPR_ARRAY_SIZE(long_txt)); |
+ long_txt[CENSUS_MAX_ANNOTATION_LENGTH + 9] = '\0'; |
+ annotation_txt[3] = long_txt; |
+ |
+ census_tracing_init(); |
+ id = census_tracing_start_op(); |
+ /* Adds large number of annotations to each trace */ |
+ for (i = 0; i < 1000; i++) { |
+ census_tracing_print(id, |
+ annotation_txt[i % GPR_ARRAY_SIZE(annotation_txt)]); |
+ } |
+ census_tracing_end_op(id); |
+ |
+ census_tracing_shutdown(); |
+} |
+ |
+/* Returns 1 if two ids are equal, otherwise returns 0. */ |
+static int ids_equal(census_op_id id1, census_op_id id2) { |
+ return (id1.upper == id2.upper) && (id1.lower == id2.lower); |
+} |
+ |
+static void test_get_active_ops(void) { |
+ census_op_id id_1, id_2, id_3; |
+ census_trace_obj **active_ops; |
+ const char *annotation_txt[] = {"annotation 1", "a2"}; |
+ int i = 0; |
+ int n = 0; |
+ |
+ gpr_log(GPR_INFO, "test_get_active_ops"); |
+ census_tracing_init(); |
+ /* No active ops before calling start_op(). */ |
+ active_ops = census_get_active_ops(&n); |
+ GPR_ASSERT(active_ops == NULL); |
+ GPR_ASSERT(n == 0); |
+ |
+ /* Starts one op */ |
+ id_1 = census_tracing_start_op(); |
+ census_add_method_tag(id_1, "foo_1"); |
+ active_ops = census_get_active_ops(&n); |
+ GPR_ASSERT(active_ops != NULL); |
+ GPR_ASSERT(n == 1); |
+ GPR_ASSERT(ids_equal(active_ops[0]->id, id_1)); |
+ census_trace_obj_destroy(active_ops[0]); |
+ gpr_free(active_ops); |
+ active_ops = NULL; |
+ |
+ /* Start the second and the third ops */ |
+ id_2 = census_tracing_start_op(); |
+ census_add_method_tag(id_2, "foo_2"); |
+ id_3 = census_tracing_start_op(); |
+ census_add_method_tag(id_3, "foo_3"); |
+ |
+ active_ops = census_get_active_ops(&n); |
+ GPR_ASSERT(n == 3); |
+ for (i = 0; i < 3; i++) { |
+ census_trace_obj_destroy(active_ops[i]); |
+ } |
+ gpr_free(active_ops); |
+ active_ops = NULL; |
+ |
+ /* End the second op and add annotations to the third ops */ |
+ census_tracing_end_op(id_2); |
+ census_tracing_print(id_3, annotation_txt[0]); |
+ census_tracing_print(id_3, annotation_txt[1]); |
+ |
+ active_ops = census_get_active_ops(&n); |
+ GPR_ASSERT(active_ops != NULL); |
+ GPR_ASSERT(n == 2); |
+ for (i = 0; i < 2; i++) { |
+ census_trace_obj_destroy(active_ops[i]); |
+ } |
+ gpr_free(active_ops); |
+ active_ops = NULL; |
+ |
+ /* End all ops. */ |
+ census_tracing_end_op(id_1); |
+ census_tracing_end_op(id_3); |
+ active_ops = census_get_active_ops(&n); |
+ GPR_ASSERT(active_ops == NULL); |
+ GPR_ASSERT(n == 0); |
+ |
+ census_tracing_shutdown(); |
+} |
+ |
+int main(int argc, char **argv) { |
+ grpc_test_init(argc, argv); |
+ test_init_shutdown(); |
+ test_start_op_generates_locally_unique_ids(); |
+ test_get_trace_method_name(); |
+ test_concurrency(); |
+ test_add_method_tag_to_unknown_op_id(); |
+ test_trace_print(); |
+ test_get_active_ops(); |
+ return 0; |
+} |