| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 | /* * * Copyright 2014, 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(gpr_time_add(gpr_now(), gpr_time_from_micros(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_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;  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));  trace_obj_destroy(active_ops[0]);  gpr_free(active_ops);  active_ops = NULL;  /* Start the second and 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++) {    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++) {    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;}
 |