diff options
Diffstat (limited to 'test/core/statistics')
-rw-r--r-- | test/core/statistics/census_stub_test.c | 6 | ||||
-rw-r--r-- | test/core/statistics/rpc_stats_test.c | 197 | ||||
-rw-r--r-- | test/core/statistics/trace_test.c | 158 |
3 files changed, 359 insertions, 2 deletions
diff --git a/test/core/statistics/census_stub_test.c b/test/core/statistics/census_stub_test.c index 7d85550f70..a86676fbb1 100644 --- a/test/core/statistics/census_stub_test.c +++ b/test/core/statistics/census_stub_test.c @@ -44,7 +44,8 @@ void test_census_stubs() { census_op_id op_id; census_rpc_stats* stats = census_rpc_stats_create_empty(); - census_aggregated_rpc_stats data_map; + census_aggregated_rpc_stats data_map = {0, NULL}; + /* Initializes census library at server start up time. */ census_init(); /* Starts tracing at the beginning of a rpc. */ @@ -62,8 +63,9 @@ void test_census_stubs() { census_tracing_end_op(op_id); /* In process stats queries. */ census_get_server_stats(&data_map); + census_aggregated_rpc_stats_set_empty(&data_map); census_get_client_stats(&data_map); - census_aggregated_rpc_stats_destroy(&data_map); + census_aggregated_rpc_stats_set_empty(&data_map); gpr_free(stats); census_shutdown(); } diff --git a/test/core/statistics/rpc_stats_test.c b/test/core/statistics/rpc_stats_test.c new file mode 100644 index 0000000000..c101403450 --- /dev/null +++ b/test/core/statistics/rpc_stats_test.c @@ -0,0 +1,197 @@ +/* + * + * 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 "src/core/statistics/census_interface.h" +#include "src/core/statistics/census_rpc_stats.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/string.h> +#include <grpc/support/thd.h> +#include <grpc/support/time.h> +#include "test/core/util/test_config.h" + +/* Ensure all possible state transitions are called without causing problem */ +static void test_init_shutdown() { + census_stats_store_init(); + census_stats_store_init(); + census_stats_store_shutdown(); + census_stats_store_shutdown(); + census_stats_store_init(); +} + +static void test_create_and_destroy() { + census_rpc_stats* stats = NULL; + census_aggregated_rpc_stats agg_stats = {0, NULL}; + + stats = census_rpc_stats_create_empty(); + GPR_ASSERT(stats != NULL); + GPR_ASSERT(stats->cnt == 0 && stats->rpc_error_cnt == 0 && + stats->app_error_cnt == 0 && stats->elapsed_time_ms == 0.0 && + stats->api_request_bytes == 0 && stats->wire_request_bytes == 0 && + stats->api_response_bytes == 0 && stats->wire_response_bytes == 0); + gpr_free(stats); + + census_aggregated_rpc_stats_set_empty(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 0); + GPR_ASSERT(agg_stats.stats == NULL); + agg_stats.num_entries = 1; + agg_stats.stats = (census_per_method_rpc_stats*)gpr_malloc( + sizeof(census_per_method_rpc_stats)); + agg_stats.stats[0].method = gpr_strdup("foo"); + census_aggregated_rpc_stats_set_empty(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 0); + GPR_ASSERT(agg_stats.stats == NULL); +} + +#define ASSERT_NEAR(a, b) \ + GPR_ASSERT((a - b) * (a - b) < 1e-24 * (a + b) * (a + b)) + +static void test_record_and_get_stats() { + census_rpc_stats stats = {1, 2, 3, 4, 5.1, 6.2, 7.3, 8.4}; + census_op_id id; + census_aggregated_rpc_stats agg_stats = {0, NULL}; + + /* Record client stats twice with the same op_id. */ + census_init(); + id = census_tracing_start_op(); + census_add_method_tag(id, "m1"); + census_record_rpc_client_stats(id, &stats); + census_record_rpc_client_stats(id, &stats); + census_tracing_end_op(id); + /* Server stats expect to be empty */ + census_get_server_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 0); + GPR_ASSERT(agg_stats.stats == NULL); + /* Client stats expect to have one entry */ + census_get_client_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 1); + GPR_ASSERT(agg_stats.stats != NULL); + GPR_ASSERT(strcmp(agg_stats.stats[0].method, "m1") == 0); + GPR_ASSERT(agg_stats.stats[0].minute_stats.cnt == 2 && + agg_stats.stats[0].hour_stats.cnt == 2 && + agg_stats.stats[0].total_stats.cnt == 2); + ASSERT_NEAR(agg_stats.stats[0].minute_stats.wire_response_bytes, 16.8); + ASSERT_NEAR(agg_stats.stats[0].hour_stats.wire_response_bytes, 16.8); + ASSERT_NEAR(agg_stats.stats[0].total_stats.wire_response_bytes, 16.8); + /* Get stats again, results should be the same. */ + census_get_client_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 1); + census_aggregated_rpc_stats_set_empty(&agg_stats); + census_shutdown(); + + /* Record both server (once) and client (twice) stats with different op_ids.*/ + census_init(); + id = census_tracing_start_op(); + census_add_method_tag(id, "m2"); + census_record_rpc_client_stats(id, &stats); + census_tracing_end_op(id); + id = census_tracing_start_op(); + census_add_method_tag(id, "m3"); + census_record_rpc_server_stats(id, &stats); + census_tracing_end_op(id); + id = census_tracing_start_op(); + census_add_method_tag(id, "m4"); + census_record_rpc_client_stats(id, &stats); + census_tracing_end_op(id); + /* Check server stats */ + census_get_server_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 1); + GPR_ASSERT(strcmp(agg_stats.stats[0].method, "m3") == 0); + GPR_ASSERT(agg_stats.stats[0].minute_stats.app_error_cnt == 3 && + agg_stats.stats[0].hour_stats.app_error_cnt == 3 && + agg_stats.stats[0].total_stats.app_error_cnt == 3); + census_aggregated_rpc_stats_set_empty(&agg_stats); + /* Check client stats */ + census_get_client_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 2); + GPR_ASSERT(agg_stats.stats != NULL); + GPR_ASSERT((strcmp(agg_stats.stats[0].method, "m2") == 0 && + strcmp(agg_stats.stats[1].method, "m4") == 0) || + (strcmp(agg_stats.stats[0].method, "m4") == 0 && + strcmp(agg_stats.stats[1].method, "m2") == 0)); + GPR_ASSERT(agg_stats.stats[0].minute_stats.cnt == 1 && + agg_stats.stats[1].minute_stats.cnt == 1); + census_aggregated_rpc_stats_set_empty(&agg_stats); + census_shutdown(); +} + +static void test_record_stats_on_unknown_op_id() { + census_op_id unknown_id = {0xDEAD, 0xBEEF}; + census_rpc_stats stats = {1, 2, 3, 4, 5.1, 6.2, 7.3, 8.4}; + census_aggregated_rpc_stats agg_stats = {0, NULL}; + + census_init(); + /* Tests that recording stats against unknown id is noop. */ + census_record_rpc_client_stats(unknown_id, &stats); + census_record_rpc_server_stats(unknown_id, &stats); + census_get_server_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 0); + GPR_ASSERT(agg_stats.stats == NULL); + census_get_client_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 0); + GPR_ASSERT(agg_stats.stats == NULL); + census_aggregated_rpc_stats_set_empty(&agg_stats); + census_shutdown(); +} + +/* Test that record stats is noop when trace store is uninitialized. */ +static void test_record_stats_with_trace_store_uninitialized() { + census_rpc_stats stats = {1, 2, 3, 4, 5.1, 6.2, 7.3, 8.4}; + census_op_id id = {0, 0}; + census_aggregated_rpc_stats agg_stats = {0, NULL}; + + census_init(); + id = census_tracing_start_op(); + census_add_method_tag(id, "m"); + census_tracing_end_op(id); + /* shuts down trace store only. */ + census_tracing_shutdown(); + census_record_rpc_client_stats(id, &stats); + census_get_client_stats(&agg_stats); + GPR_ASSERT(agg_stats.num_entries == 0); + census_stats_store_shutdown(); +} + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + test_init_shutdown(); + test_create_and_destroy(); + test_record_and_get_stats(); + test_record_stats_on_unknown_op_id(); + test_record_stats_with_trace_store_uninitialized(); + return 0; +} diff --git a/test/core/statistics/trace_test.c b/test/core/statistics/trace_test.c new file mode 100644 index 0000000000..b06fbd574b --- /dev/null +++ b/test/core/statistics/trace_test.c @@ -0,0 +1,158 @@ +/* + * + * 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 "src/core/statistics/census_interface.h" +#include "src/core/statistics/census_tracing.h" +#include "src/core/statistics/census_tracing.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 "test/core/util/test_config.h" + +/* Ensure all possible state transitions are called without causing problem */ +static void test_init_shutdown() { + census_tracing_init(); + census_tracing_init(); + census_tracing_shutdown(); + census_tracing_shutdown(); + census_tracing_init(); +} + +static void test_start_op_generates_locally_unique_ids() { +/* 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() { + 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() { +#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); + } + 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); + } + census_tracing_shutdown(); +#undef NUM_THREADS +} + +static void test_add_method_tag_to_unknown_op_id() { + 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(); +} + +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(); + return 0; +} |