diff options
author | vjpai <vpai@google.com> | 2015-11-02 09:22:10 -0800 |
---|---|---|
committer | vjpai <vpai@google.com> | 2015-11-02 09:22:10 -0800 |
commit | 11537dc71c2ceabf0a1e7f999f6c0e97f90c9f24 (patch) | |
tree | 988df3540106ca35309f2cfc8f91e14474e03564 /test/core | |
parent | 72a633213815f19ac04b51331287e3f7b075dcc1 (diff) | |
parent | 89ea0c78151b5bdc4c9236ae7100a7b97b32e499 (diff) |
Merge remote-tracking branch 'upstream/master' into protosplit
Diffstat (limited to 'test/core')
-rw-r--r-- | test/core/client_config/lb_policies_test.c | 63 | ||||
-rw-r--r-- | test/core/end2end/fixtures/h2_uchannel.c | 314 | ||||
-rwxr-xr-x | test/core/end2end/gen_build_yaml.py | 1 | ||||
-rw-r--r-- | test/core/support/cpu_test.c | 141 |
4 files changed, 490 insertions, 29 deletions
diff --git a/test/core/client_config/lb_policies_test.c b/test/core/client_config/lb_policies_test.c index a9edf38157..3eb6f11bf7 100644 --- a/test/core/client_config/lb_policies_test.c +++ b/test/core/client_config/lb_policies_test.c @@ -211,29 +211,32 @@ static void teardown_servers(servers_fixture *f) { gpr_free(f); } +typedef struct request_data { + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + char *details; + size_t details_capacity; + grpc_status_code status; + grpc_call_details *call_details; +} request_data; + /** Returns connection sequence (server indices), which must be freed */ int *perform_request(servers_fixture *f, grpc_channel *client, - const test_spec *spec) { + request_data *rdata, const test_spec *spec) { grpc_call *c; int s_idx; int *s_valid; gpr_timespec deadline; grpc_op ops[6]; grpc_op *op; - grpc_status_code status; - char *details; - size_t details_capacity; int was_cancelled; - grpc_call_details *call_details; size_t i, iter_num; grpc_event ev; int read_tag; int *connection_sequence; - grpc_metadata_array initial_metadata_recv; - grpc_metadata_array trailing_metadata_recv; s_valid = gpr_malloc(sizeof(int) * f->num_servers); - call_details = gpr_malloc(sizeof(grpc_call_details) * f->num_servers); + rdata->call_details = gpr_malloc(sizeof(grpc_call_details) * f->num_servers); connection_sequence = gpr_malloc(sizeof(int) * spec->num_iters); /* Send a trivial request. */ @@ -241,8 +244,8 @@ int *perform_request(servers_fixture *f, grpc_channel *client, for (iter_num = 0; iter_num < spec->num_iters; iter_num++) { cq_verifier *cqv = cq_verifier_create(f->cq); - details = NULL; - details_capacity = 0; + rdata->details = NULL; + rdata->details_capacity = 0; was_cancelled = 2; for (i = 0; i < f->num_servers; i++) { @@ -255,11 +258,11 @@ int *perform_request(servers_fixture *f, grpc_channel *client, } connection_sequence[iter_num] = -1; - grpc_metadata_array_init(&initial_metadata_recv); - grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&rdata->initial_metadata_recv); + grpc_metadata_array_init(&rdata->trailing_metadata_recv); for (i = 0; i < f->num_servers; i++) { - grpc_call_details_init(&call_details[i]); + grpc_call_details_init(&rdata->call_details[i]); } memset(s_valid, 0, f->num_servers * sizeof(int)); @@ -278,15 +281,15 @@ int *perform_request(servers_fixture *f, grpc_channel *client, op->reserved = NULL; op++; op->op = GRPC_OP_RECV_INITIAL_METADATA; - op->data.recv_initial_metadata = &initial_metadata_recv; + op->data.recv_initial_metadata = &rdata->initial_metadata_recv; op->flags = 0; op->reserved = NULL; op++; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; - op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; - op->data.recv_status_on_client.status = &status; - op->data.recv_status_on_client.status_details = &details; - op->data.recv_status_on_client.status_details_capacity = &details_capacity; + op->data.recv_status_on_client.trailing_metadata = &rdata->trailing_metadata_recv; + op->data.recv_status_on_client.status = &rdata->status; + op->data.recv_status_on_client.status_details = &rdata->details; + op->data.recv_status_on_client.status_details_capacity = &rdata->details_capacity; op->flags = 0; op->reserved = NULL; op++; @@ -299,7 +302,7 @@ int *perform_request(servers_fixture *f, grpc_channel *client, if (f->servers[i] != NULL) { GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f->servers[i], &f->server_calls[i], - &call_details[i], + &rdata->call_details[i], &f->request_metadata_recv[i], f->cq, f->cq, tag(1000 + (int)i))); } @@ -348,11 +351,12 @@ int *perform_request(servers_fixture *f, grpc_channel *client, cq_expect_completion(cqv, tag(1), 1); cq_verify(cqv); - GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); - GPR_ASSERT(0 == strcmp(details, "xyz")); - GPR_ASSERT(0 == strcmp(call_details[s_idx].method, "/foo")); - GPR_ASSERT(0 == strcmp(call_details[s_idx].host, "foo.test.google.fr")); + GPR_ASSERT(rdata->status == GRPC_STATUS_UNIMPLEMENTED); + GPR_ASSERT(0 == strcmp(rdata->details, "xyz")); + GPR_ASSERT(0 == strcmp(rdata->call_details[s_idx].method, "/foo")); + GPR_ASSERT(0 == strcmp(rdata->call_details[s_idx].host, "foo.test.google.fr")); GPR_ASSERT(was_cancelled == 1); + } else { } for (i = 0; i < f->num_servers; i++) { @@ -361,20 +365,20 @@ int *perform_request(servers_fixture *f, grpc_channel *client, } grpc_metadata_array_destroy(&f->request_metadata_recv[i]); } - grpc_metadata_array_destroy(&initial_metadata_recv); - grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&rdata->initial_metadata_recv); + grpc_metadata_array_destroy(&rdata->trailing_metadata_recv); cq_verifier_destroy(cqv); grpc_call_destroy(c); for (i = 0; i < f->num_servers; i++) { - grpc_call_details_destroy(&call_details[i]); + grpc_call_details_destroy(&rdata->call_details[i]); } - gpr_free(details); + gpr_free(rdata->details); } - gpr_free(call_details); + gpr_free(rdata->call_details); gpr_free(s_valid); return connection_sequence; @@ -436,6 +440,7 @@ void run_spec(const test_spec *spec) { char *client_hostport; char *servers_hostports_str; int *actual_connection_sequence; + request_data rdata; servers_fixture *f = setup_servers("127.0.0.1", spec->num_servers); /* Create client. */ @@ -448,7 +453,7 @@ void run_spec(const test_spec *spec) { gpr_log(GPR_INFO, "Testing '%s' with servers=%s client=%s", spec->description, servers_hostports_str, client_hostport); - actual_connection_sequence = perform_request(f, client, spec); + actual_connection_sequence = perform_request(f, client, &rdata, spec); spec->verifier(f, client, actual_connection_sequence, spec->num_iters); diff --git a/test/core/end2end/fixtures/h2_uchannel.c b/test/core/end2end/fixtures/h2_uchannel.c new file mode 100644 index 0000000000..d1f9d38b82 --- /dev/null +++ b/test/core/end2end/fixtures/h2_uchannel.c @@ -0,0 +1,314 @@ +/* + * + * 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 "test/core/end2end/end2end_tests.h" + +#include <string.h> + +#include "src/core/channel/channel_args.h" +#include "src/core/channel/client_channel.h" +#include "src/core/channel/client_uchannel.h" +#include "src/core/channel/connected_channel.h" +#include "src/core/channel/http_client_filter.h" +#include "src/core/channel/http_server_filter.h" +#include "src/core/client_config/resolver_registry.h" +#include "src/core/iomgr/tcp_client.h" +#include "src/core/surface/channel.h" +#include "src/core/surface/server.h" +#include "src/core/transport/chttp2_transport.h" +#include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <grpc/support/sync.h> +#include <grpc/support/thd.h> +#include <grpc/support/useful.h> +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +typedef struct { + grpc_connector base; + gpr_refcount refs; + + grpc_closure *notify; + grpc_connect_in_args args; + grpc_connect_out_args *result; + + grpc_endpoint *tcp; + + grpc_mdctx *mdctx; + + grpc_closure connected; +} connector; + +static void connector_ref(grpc_connector *con) { + connector *c = (connector *)con; + gpr_ref(&c->refs); +} + +static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) { + connector *c = (connector *)con; + if (gpr_unref(&c->refs)) { + grpc_mdctx_unref(c->mdctx); + gpr_free(c); + } +} + +static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) { + connector *c = arg; + grpc_closure *notify; + grpc_endpoint *tcp = c->tcp; + if (tcp != NULL) { + c->result->transport = grpc_create_chttp2_transport( + exec_ctx, c->args.channel_args, tcp, c->mdctx, 1); + grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL, + 0); + GPR_ASSERT(c->result->transport); + c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *)); + c->result->filters[0] = &grpc_http_client_filter; + c->result->num_filters = 1; + } else { + memset(c->result, 0, sizeof(*c->result)); + } + notify = c->notify; + c->notify = NULL; + notify->cb(exec_ctx, notify->cb_arg, 1); +} + +static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {} + +static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con, + const grpc_connect_in_args *args, + grpc_connect_out_args *result, + grpc_closure *notify) { + connector *c = (connector *)con; + GPR_ASSERT(c->notify == NULL); + GPR_ASSERT(notify->cb); + c->notify = notify; + c->args = *args; + c->result = result; + c->tcp = NULL; + grpc_closure_init(&c->connected, connected, c); + grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp, + args->interested_parties, args->addr, args->addr_len, + args->deadline); +} + +static const grpc_connector_vtable connector_vtable = { + connector_ref, connector_unref, connector_shutdown, connector_connect}; + +typedef struct { + grpc_subchannel_factory base; + gpr_refcount refs; + grpc_mdctx *mdctx; + grpc_channel_args *merge_args; + grpc_channel *master; + grpc_subchannel **sniffed_subchannel; +} subchannel_factory; + +static void subchannel_factory_ref(grpc_subchannel_factory *scf) { + subchannel_factory *f = (subchannel_factory *)scf; + gpr_ref(&f->refs); +} + +static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx, + grpc_subchannel_factory *scf) { + subchannel_factory *f = (subchannel_factory *)scf; + if (gpr_unref(&f->refs)) { + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory"); + grpc_channel_args_destroy(f->merge_args); + grpc_mdctx_unref(f->mdctx); + gpr_free(f); + } +} + +static grpc_subchannel *subchannel_factory_create_subchannel( + grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *scf, + grpc_subchannel_args *args) { + subchannel_factory *f = (subchannel_factory *)scf; + connector *c = gpr_malloc(sizeof(*c)); + grpc_channel_args *final_args = + grpc_channel_args_merge(args->args, f->merge_args); + grpc_subchannel *s; + memset(c, 0, sizeof(*c)); + c->base.vtable = &connector_vtable; + c->mdctx = f->mdctx; + grpc_mdctx_ref(c->mdctx); + gpr_ref_init(&c->refs, 1); + args->mdctx = f->mdctx; + args->args = final_args; + args->master = f->master; + s = grpc_subchannel_create(&c->base, args); + grpc_connector_unref(exec_ctx, &c->base); + grpc_channel_args_destroy(final_args); + *f->sniffed_subchannel = s; + return s; +} + +static const grpc_subchannel_factory_vtable test_subchannel_factory_vtable = { + subchannel_factory_ref, subchannel_factory_unref, + subchannel_factory_create_subchannel}; + +/* The evil twin of grpc_insecure_channel_create. It allows the test to use the + * custom-built sniffing subchannel_factory */ +grpc_channel *channel_create(const char *target, const grpc_channel_args *args, + grpc_subchannel **sniffed_subchannel) { + grpc_channel *channel = NULL; +#define MAX_FILTERS 1 + const grpc_channel_filter *filters[MAX_FILTERS]; + grpc_resolver *resolver; + subchannel_factory *f; + grpc_mdctx *mdctx = grpc_mdctx_create(); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + size_t n = 0; + + filters[n++] = &grpc_client_channel_filter; + GPR_ASSERT(n <= MAX_FILTERS); + + channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n, + args, mdctx, 1); + + f = gpr_malloc(sizeof(*f)); + f->sniffed_subchannel = sniffed_subchannel; + f->base.vtable = &test_subchannel_factory_vtable; + gpr_ref_init(&f->refs, 1); + grpc_mdctx_ref(mdctx); + f->mdctx = mdctx; + f->merge_args = grpc_channel_args_copy(args); + f->master = channel; + GRPC_CHANNEL_INTERNAL_REF(f->master, "test_subchannel_factory"); + resolver = grpc_resolver_create(target, &f->base); + if (!resolver) { + return NULL; + } + + grpc_client_channel_set_resolver( + &exec_ctx, grpc_channel_get_channel_stack(channel), resolver); + GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_create"); + grpc_subchannel_factory_unref(&exec_ctx, &f->base); + + grpc_exec_ctx_finish(&exec_ctx); + + return channel; +} + +typedef struct micro_fullstack_fixture_data { + char *localaddr; + grpc_channel *master_channel; + grpc_subchannel *sniffed_subchannel; +} micro_fullstack_fixture_data; + +static grpc_end2end_test_fixture chttp2_create_fixture_micro_fullstack( + grpc_channel_args *client_args, grpc_channel_args *server_args) { + grpc_end2end_test_fixture f; + int port = grpc_pick_unused_port_or_die(); + micro_fullstack_fixture_data *ffd = + gpr_malloc(sizeof(micro_fullstack_fixture_data)); + memset(&f, 0, sizeof(f)); + + gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port); + + f.fixture_data = ffd; + f.cq = grpc_completion_queue_create(NULL); + + return f; +} + +static void chttp2_init_client_micro_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *client_args) { + micro_fullstack_fixture_data *ffd = f->fixture_data; + grpc_connectivity_state conn_state; + char *ipv4_localaddr; + + gpr_asprintf(&ipv4_localaddr, "ipv4:%s", ffd->localaddr); + ffd->master_channel = + channel_create(ipv4_localaddr, client_args, &ffd->sniffed_subchannel); + gpr_free(ipv4_localaddr); + gpr_log(GPR_INFO, "MASTER CHANNEL %p ", ffd->master_channel); + /* the following will block. That's ok for this test */ + conn_state = grpc_channel_check_connectivity_state(ffd->master_channel, + 1 /* try to connect */); + GPR_ASSERT(conn_state == GRPC_CHANNEL_IDLE); + + /* here sniffed_subchannel should be ready to use */ + GPR_ASSERT(conn_state == GRPC_CHANNEL_IDLE); + GPR_ASSERT(ffd->sniffed_subchannel != NULL); + f->client = grpc_client_uchannel_create(ffd->sniffed_subchannel, client_args); + grpc_client_uchannel_set_subchannel(f->client, ffd->sniffed_subchannel); + gpr_log(GPR_INFO, "CHANNEL WRAPPING SUBCHANNEL: %p(%p)", f->client, + ffd->sniffed_subchannel); + + GPR_ASSERT(f->client); +} + +static void chttp2_init_server_micro_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *server_args) { + micro_fullstack_fixture_data *ffd = f->fixture_data; + if (f->server) { + grpc_server_destroy(f->server); + } + f->server = grpc_server_create(server_args, NULL); + grpc_server_register_completion_queue(f->server, f->cq, NULL); + GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr)); + grpc_server_start(f->server); +} + +static void chttp2_tear_down_micro_fullstack(grpc_end2end_test_fixture *f) { + micro_fullstack_fixture_data *ffd = f->fixture_data; + grpc_channel_destroy(ffd->master_channel); + ffd->master_channel = NULL; + gpr_free(ffd->localaddr); + gpr_free(ffd); +} + +/* All test configurations */ +static grpc_end2end_test_config configs[] = { + {"chttp2/micro_fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION, + chttp2_create_fixture_micro_fullstack, chttp2_init_client_micro_fullstack, + chttp2_init_server_micro_fullstack, chttp2_tear_down_micro_fullstack}, +}; + +int main(int argc, char **argv) { + size_t i; + + grpc_test_init(argc, argv); + grpc_init(); + + for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) { + grpc_end2end_tests(configs[i]); + } + + grpc_shutdown(); + + return 0; +} diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index 9988950a6e..af8f48576c 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -48,6 +48,7 @@ uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=Fal END2END_FIXTURES = { 'h2_fakesec': default_secure_fixture_options._replace(ci_mac=False), 'h2_full': default_unsecure_fixture_options, + 'h2_uchannel': default_unsecure_fixture_options, 'h2_compress': default_unsecure_fixture_options, 'h2_uds': uds_fixture_options, 'h2_uds+poll': uds_fixture_options._replace(platforms=['linux']), diff --git a/test/core/support/cpu_test.c b/test/core/support/cpu_test.c new file mode 100644 index 0000000000..fa83878a15 --- /dev/null +++ b/test/core/support/cpu_test.c @@ -0,0 +1,141 @@ +/* + * + * 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. + * + */ + +/* Test gpr per-cpu support: + gpr_cpu_num_cores() + gpr_cpu_current_cpu() +*/ + +#include <grpc/support/alloc.h> +#include <grpc/support/cpu.h> +#include <grpc/support/log.h> +#include <grpc/support/sync.h> +#include <grpc/support/thd.h> +#include <grpc/support/time.h> +#include <stdio.h> +#include <string.h> +#include "test/core/util/test_config.h" + +/* Test structure is essentially: + 1) Figure out how many cores are present on the test system + 2) Create 3 times that many threads + 3) Have each thread do some amount of work (basically want to + gaurantee that all threads are running at once, and enough of them + to run on all cores). + 4) Each thread checks what core it is running on, and marks that core + as "used" in the test. + 5) Count number of "used" cores. + + The test will fail if: + 1) gpr_cpu_num_cores() == 0 + 2) Any result from gpr_cpu_current_cpu() >= gpr_cpu_num_cores() + 3) Ideally, we would fail if not all cores were seen as used. Unfortunately, + this is only probabilistically true, and depends on the OS, it's + scheduler, etc. So we just print out an indication of how many were seen; + hopefully developers can use this to sanity check their system. +*/ + +/* Status shared across threads */ +struct cpu_test { + gpr_mu mu; + int nthreads; + gpr_uint32 ncores; + int is_done; + gpr_cv done_cv; + int *used; /* is this core used? */ + int r; /* random number */ +}; + +static void worker_thread(void *arg) { + struct cpu_test *ct = (struct cpu_test *)arg; + gpr_uint32 cpu; + int r = 12345678; + int i, j; + for (i = 0; i < 1000 / GRPC_TEST_SLOWDOWN_FACTOR; i++) { + /* run for a bit - just calculate something random. */ + for (j = 0; j < 1000000 / GRPC_TEST_SLOWDOWN_FACTOR; j++) { + r = (r * 17) & ((r - i) | (r * i)); + } + cpu = gpr_cpu_current_cpu(); + GPR_ASSERT(cpu < ct->ncores); + gpr_mu_lock(&ct->mu); + ct->used[cpu] = 1; + gpr_mu_unlock(&ct->mu); + } + gpr_mu_lock(&ct->mu); + ct->r = r; /* make it look like we care about r's value... */ + ct->nthreads--; + if (ct->nthreads == 0) { + ct->is_done = 1; + gpr_cv_signal(&ct->done_cv); + } + gpr_mu_unlock(&ct->mu); +} + +static void cpu_test(void) { + gpr_uint32 i; + int cores_seen = 0; + struct cpu_test ct; + gpr_thd_id thd; + ct.ncores = gpr_cpu_num_cores(); + GPR_ASSERT(ct.ncores > 0); + ct.nthreads = (int)ct.ncores * 3; + ct.used = gpr_malloc(ct.ncores * sizeof(int)); + memset(ct.used, 0, ct.ncores * sizeof(int)); + gpr_mu_init(&ct.mu); + gpr_cv_init(&ct.done_cv); + ct.is_done = 0; + for (i = 0; i < ct.ncores * 3; i++) { + GPR_ASSERT(gpr_thd_new(&thd, &worker_thread, &ct, NULL)); + } + gpr_mu_lock(&ct.mu); + while (!ct.is_done) { + gpr_cv_wait(&ct.done_cv, &ct.mu, gpr_inf_future(GPR_CLOCK_REALTIME)); + } + gpr_mu_unlock(&ct.mu); + fprintf(stderr, "Saw cores ["); + for (i = 0; i < ct.ncores; i++) { + if (ct.used[i]) { + fprintf(stderr, "%d,", i); + cores_seen++; + } + } + fprintf(stderr, "] (%d/%d)\n", cores_seen, ct.ncores); + gpr_free(ct.used); +} + +int main(int argc, char *argv[]) { + grpc_test_init(argc, argv); + cpu_test(); + return 0; +} |