Merge github.com:grpc/grpc into grpc_slice

reviewable/pr8532/r1
Craig Tiller 8 years ago
commit b7982319c9
  1. 2
      package.json
  2. 4
      src/core/ext/client_channel/client_channel.c
  3. 3
      src/core/ext/client_channel/subchannel.c
  4. 2
      src/core/ext/client_channel/subchannel.h
  5. 6
      src/core/ext/lb_policy/pick_first/pick_first.c
  6. 13
      src/core/ext/lb_policy/round_robin/round_robin.c
  7. 7
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  8. 6
      src/core/lib/iomgr/ev_epoll_linux.c
  9. 26
      src/core/lib/iomgr/resource_quota.c
  10. 19
      src/core/lib/iomgr/resource_quota.h
  11. 3
      src/core/lib/iomgr/tcp_uv.c
  12. 1
      src/core/lib/surface/server.c
  13. 17
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  14. 2
      src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
  15. 291
      src/node/performance/benchmark_client_express.js
  16. 5
      src/node/performance/benchmark_server.js
  17. 109
      src/node/performance/benchmark_server_express.js
  18. 10
      src/node/performance/worker.js
  19. 34
      src/node/performance/worker_service_impl.js
  20. 2
      templates/package.json.template
  21. 10
      test/core/end2end/gen_build_yaml.py
  22. 6
      test/core/end2end/tests/resource_quota_server.c
  23. 10
      test/core/iomgr/resource_quota_test.c
  24. 2
      test/core/iomgr/udp_server_test.c
  25. 7
      test/cpp/qps/client_sync.cc
  26. 14
      tools/run_tests/build_python.sh
  27. 70
      tools/run_tests/performance/scenario_config.py
  28. 10
      tools/run_tests/run_performance_tests.py
  29. 48
      tools/run_tests/run_tests.py
  30. 92
      tools/run_tests/tests.json

@ -34,6 +34,8 @@
}, },
"devDependencies": { "devDependencies": {
"async": "^1.5.0", "async": "^1.5.0",
"body-parser": "^1.15.2",
"express": "^4.14.0",
"google-auth-library": "^0.9.2", "google-auth-library": "^0.9.2",
"google-protobuf": "^3.0.0", "google-protobuf": "^3.0.0",
"istanbul": "^0.3.21", "istanbul": "^0.3.21",

@ -1022,6 +1022,10 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
gpr_mu_destroy(&calld->mu); gpr_mu_destroy(&calld->mu);
GPR_ASSERT(calld->waiting_ops_count == 0); GPR_ASSERT(calld->waiting_ops_count == 0);
if (calld->connected_subchannel != NULL) {
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, calld->connected_subchannel,
"picked");
}
gpr_free(calld->waiting_ops); gpr_free(calld->waiting_ops);
gpr_free(and_free_memory); gpr_free(and_free_memory);
} }

@ -183,9 +183,10 @@ static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
gpr_free(c); gpr_free(c);
} }
void grpc_connected_subchannel_ref( grpc_connected_subchannel *grpc_connected_subchannel_ref(
grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON); GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
return c;
} }
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,

@ -97,7 +97,7 @@ grpc_subchannel *grpc_subchannel_weak_ref(
void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel grpc_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS); GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_connected_subchannel_ref( grpc_connected_subchannel *grpc_connected_subchannel_ref(
grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
grpc_connected_subchannel *channel grpc_connected_subchannel *channel

@ -209,7 +209,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
/* Check atomically for a selected channel */ /* Check atomically for a selected channel */
grpc_connected_subchannel *selected = GET_SELECTED(p); grpc_connected_subchannel *selected = GET_SELECTED(p);
if (selected != NULL) { if (selected != NULL) {
*target = selected; *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
return 1; return 1;
} }
@ -218,7 +218,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
selected = GET_SELECTED(p); selected = GET_SELECTED(p);
if (selected) { if (selected) {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
*target = selected; *target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
return 1; return 1;
} else { } else {
if (!p->started_picking) { if (!p->started_picking) {
@ -310,7 +310,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
/* update any calls that were waiting for a pick */ /* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = selected; *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp); gpr_free(pp);
} }

@ -397,7 +397,9 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) { if ((selected = peek_next_connected_locked(p))) {
/* readily available, report right away */ /* readily available, report right away */
*target = grpc_subchannel_get_connected_subchannel(selected->subchannel); *target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel),
"picked");
if (user_data != NULL) { if (user_data != NULL) {
*user_data = selected->user_data; *user_data = selected->user_data;
@ -463,8 +465,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel); grpc_subchannel_get_connected_subchannel(selected->subchannel),
"picked");
if (pp->user_data != NULL) { if (pp->user_data != NULL) {
*pp->user_data = selected->user_data; *pp->user_data = selected->user_data;
} }
@ -578,7 +581,9 @@ static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) { if ((selected = peek_next_connected_locked(p))) {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
target = grpc_subchannel_get_connected_subchannel(selected->subchannel); target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel),
"picked");
grpc_connected_subchannel_ping(exec_ctx, target, closure); grpc_connected_subchannel_ping(exec_ctx, target, closure);
} else { } else {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);

@ -1023,9 +1023,14 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
} }
if (!s->write_closed) { if (!s->write_closed) {
if (t->is_client) { if (t->is_client) {
if (!t->closed) {
GPR_ASSERT(s->id == 0); GPR_ASSERT(s->id == 0);
grpc_chttp2_list_add_waiting_for_concurrency(t, s); grpc_chttp2_list_add_waiting_for_concurrency(t, s);
maybe_start_some_streams(exec_ctx, t); maybe_start_some_streams(exec_ctx, t);
} else {
grpc_chttp2_cancel_stream(exec_ctx, t, s,
GRPC_ERROR_CREATE("Transport closed"));
}
} else { } else {
GPR_ASSERT(s->id != 0); GPR_ASSERT(s->id != 0);
grpc_chttp2_become_writable(exec_ctx, t, s, true, grpc_chttp2_become_writable(exec_ctx, t, s, true,
@ -2190,7 +2195,7 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_CHTTP2_ENHANCE_YOUR_CALM)); GRPC_CHTTP2_ENHANCE_YOUR_CALM));
if (n > 1) { if (n > 1) {
/* Since we cancel one stream per destructive reclaimation, if /* Since we cancel one stream per destructive reclamation, if
there are more streams left, we can immediately post a new there are more streams left, we can immediately post a new
reclaimer in case the resource quota needs to free more reclaimer in case the resource quota needs to free more
memory */ memory */

@ -1711,6 +1711,12 @@ retry:
"pollset_add_fd: Raced creating new polling island. pi_new: %p " "pollset_add_fd: Raced creating new polling island. pi_new: %p "
"(fd: %d, pollset: %p)", "(fd: %d, pollset: %p)",
(void *)pi_new, fd->fd, (void *)pollset); (void *)pi_new, fd->fd, (void *)pollset);
/* No need to lock 'pi_new' here since this is a new polling island and
* no one has a reference to it yet */
polling_island_remove_all_fds_locked(pi_new, true, &error);
/* Ref and unref so that the polling island gets deleted during unref */
PI_ADD_REF(pi_new, "dance_of_destruction"); PI_ADD_REF(pi_new, "dance_of_destruction");
PI_UNREF(exec_ctx, pi_new, "dance_of_destruction"); PI_UNREF(exec_ctx, pi_new, "dance_of_destruction");
goto retry; goto retry;

@ -89,6 +89,7 @@ static void rulist_add_head(grpc_resource_user *resource_user,
resource_user->links[list].prev = (*root)->links[list].prev; resource_user->links[list].prev = (*root)->links[list].prev;
resource_user->links[list].next->links[list].prev = resource_user->links[list].next->links[list].prev =
resource_user->links[list].prev->links[list].next = resource_user; resource_user->links[list].prev->links[list].next = resource_user;
*root = resource_user;
} }
} }
@ -105,7 +106,6 @@ static void rulist_add_tail(grpc_resource_user *resource_user,
resource_user->links[list].prev = *root; resource_user->links[list].prev = *root;
resource_user->links[list].next->links[list].prev = resource_user->links[list].next->links[list].prev =
resource_user->links[list].prev->links[list].next = resource_user; resource_user->links[list].prev->links[list].next = resource_user;
*root = resource_user;
} }
} }
@ -114,7 +114,7 @@ static bool rulist_empty(grpc_resource_quota *resource_quota,
return resource_quota->roots[list] == NULL; return resource_quota->roots[list] == NULL;
} }
static grpc_resource_user *rulist_pop_tail(grpc_resource_quota *resource_quota, static grpc_resource_user *rulist_pop_head(grpc_resource_quota *resource_quota,
grpc_rulist list) { grpc_rulist list) {
grpc_resource_user **root = &resource_quota->roots[list]; grpc_resource_user **root = &resource_quota->roots[list];
grpc_resource_user *resource_user = *root; grpc_resource_user *resource_user = *root;
@ -186,7 +186,7 @@ static void rq_step_sched(grpc_exec_ctx *exec_ctx,
static bool rq_alloc(grpc_exec_ctx *exec_ctx, static bool rq_alloc(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *resource_quota) { grpc_resource_quota *resource_quota) {
grpc_resource_user *resource_user; grpc_resource_user *resource_user;
while ((resource_user = rulist_pop_tail(resource_quota, while ((resource_user = rulist_pop_head(resource_quota,
GRPC_RULIST_AWAITING_ALLOCATION))) { GRPC_RULIST_AWAITING_ALLOCATION))) {
gpr_mu_lock(&resource_user->mu); gpr_mu_lock(&resource_user->mu);
if (resource_user->free_pool < 0 && if (resource_user->free_pool < 0 &&
@ -209,7 +209,7 @@ static bool rq_alloc(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx_enqueue_list(exec_ctx, &resource_user->on_allocated, NULL); grpc_exec_ctx_enqueue_list(exec_ctx, &resource_user->on_allocated, NULL);
gpr_mu_unlock(&resource_user->mu); gpr_mu_unlock(&resource_user->mu);
} else { } else {
rulist_add_tail(resource_user, GRPC_RULIST_AWAITING_ALLOCATION); rulist_add_head(resource_user, GRPC_RULIST_AWAITING_ALLOCATION);
gpr_mu_unlock(&resource_user->mu); gpr_mu_unlock(&resource_user->mu);
return false; return false;
} }
@ -221,7 +221,7 @@ static bool rq_alloc(grpc_exec_ctx *exec_ctx,
static bool rq_reclaim_from_per_user_free_pool( static bool rq_reclaim_from_per_user_free_pool(
grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) { grpc_exec_ctx *exec_ctx, grpc_resource_quota *resource_quota) {
grpc_resource_user *resource_user; grpc_resource_user *resource_user;
while ((resource_user = rulist_pop_tail(resource_quota, while ((resource_user = rulist_pop_head(resource_quota,
GRPC_RULIST_NON_EMPTY_FREE_POOL))) { GRPC_RULIST_NON_EMPTY_FREE_POOL))) {
gpr_mu_lock(&resource_user->mu); gpr_mu_lock(&resource_user->mu);
if (resource_user->free_pool > 0) { if (resource_user->free_pool > 0) {
@ -249,7 +249,7 @@ static bool rq_reclaim(grpc_exec_ctx *exec_ctx,
if (resource_quota->reclaiming) return true; if (resource_quota->reclaiming) return true;
grpc_rulist list = destructive ? GRPC_RULIST_RECLAIMER_DESTRUCTIVE grpc_rulist list = destructive ? GRPC_RULIST_RECLAIMER_DESTRUCTIVE
: GRPC_RULIST_RECLAIMER_BENIGN; : GRPC_RULIST_RECLAIMER_BENIGN;
grpc_resource_user *resource_user = rulist_pop_tail(resource_quota, list); grpc_resource_user *resource_user = rulist_pop_head(resource_quota, list);
if (resource_user == NULL) return false; if (resource_user == NULL) return false;
if (grpc_resource_quota_trace) { if (grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG, "RQ %s %s: initiate %s reclamation", gpr_log(GPR_DEBUG, "RQ %s %s: initiate %s reclamation",
@ -325,7 +325,7 @@ static void ru_allocate(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
GRPC_RULIST_AWAITING_ALLOCATION)) { GRPC_RULIST_AWAITING_ALLOCATION)) {
rq_step_sched(exec_ctx, resource_user->resource_quota); rq_step_sched(exec_ctx, resource_user->resource_quota);
} }
rulist_add_head(resource_user, GRPC_RULIST_AWAITING_ALLOCATION); rulist_add_tail(resource_user, GRPC_RULIST_AWAITING_ALLOCATION);
} }
static void ru_add_to_free_pool(grpc_exec_ctx *exec_ctx, void *ru, static void ru_add_to_free_pool(grpc_exec_ctx *exec_ctx, void *ru,
@ -337,7 +337,7 @@ static void ru_add_to_free_pool(grpc_exec_ctx *exec_ctx, void *ru,
GRPC_RULIST_NON_EMPTY_FREE_POOL)) { GRPC_RULIST_NON_EMPTY_FREE_POOL)) {
rq_step_sched(exec_ctx, resource_user->resource_quota); rq_step_sched(exec_ctx, resource_user->resource_quota);
} }
rulist_add_head(resource_user, GRPC_RULIST_NON_EMPTY_FREE_POOL); rulist_add_tail(resource_user, GRPC_RULIST_NON_EMPTY_FREE_POOL);
} }
static void ru_post_benign_reclaimer(grpc_exec_ctx *exec_ctx, void *ru, static void ru_post_benign_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
@ -351,7 +351,7 @@ static void ru_post_benign_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
GRPC_RULIST_RECLAIMER_BENIGN)) { GRPC_RULIST_RECLAIMER_BENIGN)) {
rq_step_sched(exec_ctx, resource_user->resource_quota); rq_step_sched(exec_ctx, resource_user->resource_quota);
} }
rulist_add_head(resource_user, GRPC_RULIST_RECLAIMER_BENIGN); rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
} }
static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru, static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
@ -367,7 +367,7 @@ static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
GRPC_RULIST_RECLAIMER_DESTRUCTIVE)) { GRPC_RULIST_RECLAIMER_DESTRUCTIVE)) {
rq_step_sched(exec_ctx, resource_user->resource_quota); rq_step_sched(exec_ctx, resource_user->resource_quota);
} }
rulist_add_head(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE); rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
} }
static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) { static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
@ -563,9 +563,6 @@ void grpc_resource_user_init(grpc_resource_user *resource_user,
for (int i = 0; i < GRPC_RULIST_COUNT; i++) { for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
resource_user->links[i].next = resource_user->links[i].prev = NULL; resource_user->links[i].next = resource_user->links[i].prev = NULL;
} }
#ifndef NDEBUG
resource_user->asan_canary = gpr_malloc(1);
#endif
if (name != NULL) { if (name != NULL) {
resource_user->name = gpr_strdup(name); resource_user->name = gpr_strdup(name);
} else { } else {
@ -592,9 +589,6 @@ void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx, void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user) { grpc_resource_user *resource_user) {
#ifndef NDEBUG
gpr_free(resource_user->asan_canary);
#endif
grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota); grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota);
gpr_mu_destroy(&resource_user->mu); gpr_mu_destroy(&resource_user->mu);
gpr_free(resource_user->name); gpr_free(resource_user->name);

@ -49,7 +49,8 @@
resource constrained, grpc_resource_user instances are asked (in turn) to resource constrained, grpc_resource_user instances are asked (in turn) to
free up whatever they can so that the system as a whole can make progress. free up whatever they can so that the system as a whole can make progress.
There are three kinds of reclamation that take place: There are three kinds of reclamation that take place, in order of increasing
invasiveness:
- an internal reclamation, where cached resource at the resource user level - an internal reclamation, where cached resource at the resource user level
is returned to the quota is returned to the quota
- a benign reclamation phase, whereby resources that are in use but are not - a benign reclamation phase, whereby resources that are in use but are not
@ -58,9 +59,14 @@
make progress may be enacted so that at least one part of the system can make progress may be enacted so that at least one part of the system can
complete. complete.
These reclamations are tried in priority order, and only one reclamation Only one reclamation will be outstanding for a given quota at a given time.
is outstanding for a quota at any given time (meaning that if a destructive On each reclamation attempt, the kinds of reclamation are tried in order of
reclamation makes progress, we may follow up with a benign reclamation). increasing invasiveness, stopping at the first one that succeeds. Thus, on a
given reclamation attempt, if internal and benign reclamation both fail, it
will wind up doing a destructive reclamation. However, the next reclamation
attempt may then be able to get what it needs via internal or benign
reclamation, due to resources that may have been freed up by the destructive
reclamation in the previous attempt.
Future work will be to expose the current resource pressure so that back Future work will be to expose the current resource pressure so that back
pressure can be applied to avoid reclamation phases starting. pressure can be applied to avoid reclamation phases starting.
@ -112,11 +118,6 @@ struct grpc_resource_user {
lock */ lock */
grpc_closure add_to_free_pool_closure; grpc_closure add_to_free_pool_closure;
#ifndef NDEBUG
/* Canary object to detect leaked resource users with ASAN */
void *asan_canary;
#endif
gpr_mu mu; gpr_mu mu;
/* Total allocated memory outstanding by this resource user in bytes; /* Total allocated memory outstanding by this resource user in bytes;
always positive */ always positive */

@ -315,6 +315,9 @@ grpc_endpoint *grpc_tcp_create(uv_tcp_t *handle, char *peer_string) {
gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", tcp); gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", tcp);
} }
/* Disable Nagle's Algorithm */
uv_tcp_nodelay(handle, 1);
memset(tcp, 0, sizeof(grpc_tcp)); memset(tcp, 0, sizeof(grpc_tcp));
tcp->base.vtable = &vtable; tcp->base.vtable = &vtable;
tcp->handle = handle; tcp->handle = handle;

@ -842,6 +842,7 @@ static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd,
grpc_call_stack_element(grpc_call_get_call_stack(call), 0); grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
got_initial_metadata(exec_ctx, elem, error); got_initial_metadata(exec_ctx, elem, error);
GRPC_ERROR_UNREF(error);
return; return;
} }
call_data *calld = elem->call_data; call_data *calld = elem->call_data;

@ -52,9 +52,8 @@ namespace Grpc.Core.Internal
// Completion of a pending unary response if not null. // Completion of a pending unary response if not null.
TaskCompletionSource<TResponse> unaryResponseTcs; TaskCompletionSource<TResponse> unaryResponseTcs;
// TODO(jtattermusch): this field doesn't need to be initialized for unary response calls. // Completion of a streaming response call if not null.
// Indicates that response streaming call has finished. TaskCompletionSource<object> streamingResponseCallFinishedTcs;
TaskCompletionSource<object> streamingCallFinishedTcs = new TaskCompletionSource<object>();
// TODO(jtattermusch): this field could be lazy-initialized (only if someone requests the response headers). // TODO(jtattermusch): this field could be lazy-initialized (only if someone requests the response headers).
// Response headers set here once received. // Response headers set here once received.
@ -198,6 +197,7 @@ namespace Grpc.Core.Internal
byte[] payload = UnsafeSerialize(msg); byte[] payload = UnsafeSerialize(msg);
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{ {
call.StartServerStreaming(HandleFinished, payload, metadataArray, GetWriteFlagsForCall()); call.StartServerStreaming(HandleFinished, payload, metadataArray, GetWriteFlagsForCall());
@ -219,6 +219,7 @@ namespace Grpc.Core.Internal
Initialize(details.Channel.CompletionQueue); Initialize(details.Channel.CompletionQueue);
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{ {
call.StartDuplexStreaming(HandleFinished, metadataArray); call.StartDuplexStreaming(HandleFinished, metadataArray);
@ -276,13 +277,13 @@ namespace Grpc.Core.Internal
} }
/// <summary> /// <summary>
/// Get the task that completes once if streaming call finishes with ok status and throws RpcException with given status otherwise. /// Get the task that completes once if streaming response call finishes with ok status and throws RpcException with given status otherwise.
/// </summary> /// </summary>
public Task StreamingCallFinishedTask public Task StreamingResponseCallFinishedTask
{ {
get get
{ {
return streamingCallFinishedTcs.Task; return streamingResponseCallFinishedTcs.Task;
} }
} }
@ -529,11 +530,11 @@ namespace Grpc.Core.Internal
var status = receivedStatus.Status; var status = receivedStatus.Status;
if (status.StatusCode != StatusCode.OK) if (status.StatusCode != StatusCode.OK)
{ {
streamingCallFinishedTcs.SetException(new RpcException(status)); streamingResponseCallFinishedTcs.SetException(new RpcException(status));
return; return;
} }
streamingCallFinishedTcs.SetResult(null); streamingResponseCallFinishedTcs.SetResult(null);
} }
} }
} }

@ -73,7 +73,7 @@ namespace Grpc.Core.Internal
if (result == null) if (result == null)
{ {
await call.StreamingCallFinishedTask.ConfigureAwait(false); await call.StreamingResponseCallFinishedTask.ConfigureAwait(false);
return false; return false;
} }
return true; return true;

@ -0,0 +1,291 @@
/*
*
* 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.
*
*/
/**
* Benchmark client module
* @module
*/
'use strict';
var fs = require('fs');
var path = require('path');
var util = require('util');
var EventEmitter = require('events');
var http = require('http');
var https = require('https');
var async = require('async');
var _ = require('lodash');
var PoissonProcess = require('poisson-process');
var Histogram = require('./histogram');
/**
* Convert a time difference, as returned by process.hrtime, to a number of
* nanoseconds.
* @param {Array.<number>} time_diff The time diff, represented as
* [seconds, nanoseconds]
* @return {number} The total number of nanoseconds
*/
function timeDiffToNanos(time_diff) {
return time_diff[0] * 1e9 + time_diff[1];
}
function BenchmarkClient(server_targets, channels, histogram_params,
security_params) {
var options = {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
}
};
var protocol;
if (security_params) {
var ca_path;
protocol = https;
this.request = _.bind(https.request, https);
if (security_params.use_test_ca) {
ca_path = path.join(__dirname, '../test/data/ca.pem');
var ca_data = fs.readFileSync(ca_path);
options.ca = ca_data;
}
if (security_params.server_host_override) {
var host_override = security_params.server_host_override;
options.servername = host_override;
}
} else {
protocol = http;
}
this.request = _.bind(protocol.request, protocol);
this.client_options = [];
for (var i = 0; i < channels; i++) {
var host_port;
host_port = server_targets[i % server_targets.length].split(':')
var new_options = _.assign({hostname: host_port[0], port: +host_port[1]}, options);
new_options.agent = new protocol.Agent(new_options);
this.client_options[i] = new_options;
}
this.histogram = new Histogram(histogram_params.resolution,
histogram_params.max_possible);
this.running = false;
this.pending_calls = 0;
}
util.inherits(BenchmarkClient, EventEmitter);
function startAllClients(client_options_list, outstanding_rpcs_per_channel,
makeCall, emitter) {
_.each(client_options_list, function(client_options) {
_.times(outstanding_rpcs_per_channel, function() {
makeCall(client_options);
});
});
}
BenchmarkClient.prototype.startClosedLoop = function(
outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, generic) {
var self = this;
var options = {};
self.running = true;
if (rpc_type == 'UNARY') {
options.path = '/serviceProto.BenchmarkService.service/unaryCall';
} else {
self.emit('error', new Error('Unsupported rpc_type: ' + rpc_type));
}
if (generic) {
self.emit('error', new Error('Generic client not supported'));
}
self.last_wall_time = process.hrtime();
var argument = {
response_size: resp_size,
payload: {
body: '0'.repeat(req_size)
}
};
function makeCall(client_options) {
if (self.running) {
self.pending_calls++;
var start_time = process.hrtime();
var req = self.request(client_options, function(res) {
var res_data = '';
res.on('data', function(data) {
res_data += data;
});
res.on('end', function() {
JSON.parse(res_data);
var time_diff = process.hrtime(start_time);
self.histogram.add(timeDiffToNanos(time_diff));
makeCall(client_options);
self.pending_calls--;
if ((!self.running) && self.pending_calls == 0) {
self.emit('finished');
}
});
});
req.write(JSON.stringify(argument));
req.end();
req.on('error', function(error) {
self.emit('error', new Error('Client error: ' + error.message));
self.running = false;
});
}
}
startAllClients(_.map(self.client_options, _.partial(_.assign, options)),
outstanding_rpcs_per_channel, makeCall, self);
};
BenchmarkClient.prototype.startPoisson = function(
outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, offered_load,
generic) {
var self = this;
var options = {};
self.running = true;
if (rpc_type == 'UNARY') {
options.path = '/serviceProto.BenchmarkService.service/unaryCall';
} else {
self.emit('error', new Error('Unsupported rpc_type: ' + rpc_type));
}
if (generic) {
self.emit('error', new Error('Generic client not supported'));
}
self.last_wall_time = process.hrtime();
var argument = {
response_size: resp_size,
payload: {
body: '0'.repeat(req_size)
}
};
function makeCall(client_options, poisson) {
if (self.running) {
self.pending_calls++;
var start_time = process.hrtime();
var req = self.request(client_options, function(res) {
var res_data = '';
res.on('data', function(data) {
res_data += data;
});
res.on('end', function() {
JSON.parse(res_data);
var time_diff = process.hrtime(start_time);
self.histogram.add(timeDiffToNanos(time_diff));
self.pending_calls--;
if ((!self.running) && self.pending_calls == 0) {
self.emit('finished');
}
});
});
req.write(JSON.stringify(argument));
req.end();
req.on('error', function(error) {
self.emit('error', new Error('Client error: ' + error.message));
self.running = false;
});
} else {
poisson.stop();
}
}
var averageIntervalMs = (1 / offered_load) * 1000;
startAllClients(_.map(self.client_options, _.partial(_.assign, options)),
outstanding_rpcs_per_channel, function(opts){
var p = PoissonProcess.create(averageIntervalMs, function() {
makeCall(opts, p);
});
p.start();
}, self);
};
/**
* Return curent statistics for the client. If reset is set, restart
* statistic collection.
* @param {boolean} reset Indicates that statistics should be reset
* @return {object} Client statistics
*/
BenchmarkClient.prototype.mark = function(reset) {
var wall_time_diff = process.hrtime(this.last_wall_time);
var histogram = this.histogram;
if (reset) {
this.last_wall_time = process.hrtime();
this.histogram = new Histogram(histogram.resolution,
histogram.max_possible);
}
return {
latencies: {
bucket: histogram.getContents(),
min_seen: histogram.minimum(),
max_seen: histogram.maximum(),
sum: histogram.getSum(),
sum_of_squares: histogram.sumOfSquares(),
count: histogram.getCount()
},
time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
// Not sure how to measure these values
time_user: 0,
time_system: 0
};
};
/**
* Stop the clients.
* @param {function} callback Called when the clients have finished shutting
* down
*/
BenchmarkClient.prototype.stop = function(callback) {
this.running = false;
this.on('finished', callback);
};
module.exports = BenchmarkClient;

@ -40,6 +40,8 @@
var fs = require('fs'); var fs = require('fs');
var path = require('path'); var path = require('path');
var EventEmitter = require('events');
var util = require('util');
var genericService = require('./generic_service'); var genericService = require('./generic_service');
@ -138,12 +140,15 @@ function BenchmarkServer(host, port, tls, generic, response_size) {
this.server = server; this.server = server;
} }
util.inherits(BenchmarkServer, EventEmitter);
/** /**
* Start the benchmark server. * Start the benchmark server.
*/ */
BenchmarkServer.prototype.start = function() { BenchmarkServer.prototype.start = function() {
this.server.start(); this.server.start();
this.last_wall_time = process.hrtime(); this.last_wall_time = process.hrtime();
this.emit('started');
}; };
/** /**

@ -0,0 +1,109 @@
/*
*
* Copyright 2016, 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.
*
*/
/**
* Benchmark server module
* @module
*/
'use strict';
var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var EventEmitter = require('events');
var util = require('util');
var express = require('express');
var bodyParser = require('body-parser')
function unaryCall(req, res) {
var reqObj = req.body;
var payload = {body: '0'.repeat(reqObj.response_size)};
res.json(payload);
}
function BenchmarkServer(host, port, tls, generic, response_size) {
var app = express();
app.use(bodyParser.json())
app.put('/serviceProto.BenchmarkService.service/unaryCall', unaryCall);
this.input_host = host;
this.input_port = port;
if (tls) {
var credentials = {};
var key_path = path.join(__dirname, '../test/data/server1.key');
var pem_path = path.join(__dirname, '../test/data/server1.pem');
var key_data = fs.readFileSync(key_path);
var pem_data = fs.readFileSync(pem_path);
credentials['key'] = key_data;
credentials['cert'] = pem_data;
this.server = https.createServer(credentials, app);
} else {
this.server = http.createServer(app);
}
}
util.inherits(BenchmarkServer, EventEmitter);
BenchmarkServer.prototype.start = function() {
var self = this;
this.server.listen(this.input_port, this.input_hostname, function() {
self.last_wall_time = process.hrtime();
self.emit('started');
});
};
BenchmarkServer.prototype.getPort = function() {
return this.server.address().port;
};
BenchmarkServer.prototype.mark = function(reset) {
var wall_time_diff = process.hrtime(this.last_wall_time);
if (reset) {
this.last_wall_time = process.hrtime();
}
return {
time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
// Not sure how to measure these values
time_user: 0,
time_system: 0
};
};
BenchmarkServer.prototype.stop = function(callback) {
this.server.close(callback);
};
module.exports = BenchmarkServer;

@ -34,18 +34,18 @@
'use strict'; 'use strict';
var console = require('console'); var console = require('console');
var worker_service_impl = require('./worker_service_impl'); var WorkerServiceImpl = require('./worker_service_impl');
var grpc = require('../../../'); var grpc = require('../../../');
var serviceProto = grpc.load({ var serviceProto = grpc.load({
root: __dirname + '/../../..', root: __dirname + '/../../..',
file: 'src/proto/grpc/testing/services.proto'}).grpc.testing; file: 'src/proto/grpc/testing/services.proto'}).grpc.testing;
function runServer(port) { function runServer(port, benchmark_impl) {
var server_creds = grpc.ServerCredentials.createInsecure(); var server_creds = grpc.ServerCredentials.createInsecure();
var server = new grpc.Server(); var server = new grpc.Server();
server.addProtoService(serviceProto.WorkerService.service, server.addProtoService(serviceProto.WorkerService.service,
worker_service_impl); new WorkerServiceImpl(benchmark_impl, server));
var address = '0.0.0.0:' + port; var address = '0.0.0.0:' + port;
server.bind(address, server_creds); server.bind(address, server_creds);
server.start(); server.start();
@ -57,9 +57,9 @@ if (require.main === module) {
Error.stackTraceLimit = Infinity; Error.stackTraceLimit = Infinity;
var parseArgs = require('minimist'); var parseArgs = require('minimist');
var argv = parseArgs(process.argv, { var argv = parseArgs(process.argv, {
string: ['driver_port'] string: ['driver_port', 'benchmark_impl']
}); });
runServer(argv.driver_port); runServer(argv.driver_port, argv.benchmark_impl);
} }
exports.runServer = runServer; exports.runServer = runServer;

@ -38,12 +38,29 @@ var console = require('console');
var BenchmarkClient = require('./benchmark_client'); var BenchmarkClient = require('./benchmark_client');
var BenchmarkServer = require('./benchmark_server'); var BenchmarkServer = require('./benchmark_server');
exports.quitWorker = function quitWorker(call, callback) { module.exports = function WorkerServiceImpl(benchmark_impl, server) {
callback(null, {}); var BenchmarkClient;
process.exit(0); var BenchmarkServer;
switch (benchmark_impl) {
case 'grpc':
BenchmarkClient = require('./benchmark_client');
BenchmarkServer = require('./benchmark_server');
break;
case 'express':
BenchmarkClient = require('./benchmark_client_express');
BenchmarkServer = require('./benchmark_server_express');
break;
default:
throw new Error('Unrecognized benchmark impl: ' + benchmark_impl);
} }
exports.runClient = function runClient(call) { this.quitWorker = function quitWorker(call, callback) {
server.tryShutdown(function() {
callback(null, {});
});
};
this.runClient = function runClient(call) {
var client; var client;
call.on('data', function(request) { call.on('data', function(request) {
var stats; var stats;
@ -114,7 +131,7 @@ exports.runClient = function runClient(call) {
}); });
}; };
exports.runServer = function runServer(call) { this.runServer = function runServer(call) {
var server; var server;
call.on('data', function(request) { call.on('data', function(request) {
var stats; var stats;
@ -123,12 +140,14 @@ exports.runServer = function runServer(call) {
console.log('ServerConfig %j', request.setup); console.log('ServerConfig %j', request.setup);
server = new BenchmarkServer('[::]', request.setup.port, server = new BenchmarkServer('[::]', request.setup.port,
request.setup.security_params); request.setup.security_params);
server.start(); server.on('started', function() {
stats = server.mark(); stats = server.mark();
call.write({ call.write({
stats: stats, stats: stats,
port: server.getPort() port: server.getPort()
}); });
});
server.start();
break; break;
case 'mark': case 'mark':
if (server) { if (server) {
@ -153,6 +172,7 @@ exports.runServer = function runServer(call) {
}); });
}; };
exports.coreCount = function coreCount(call, callback) { this.coreCount = function coreCount(call, callback) {
callback(null, {cores: os.cpus().length}); callback(null, {cores: os.cpus().length});
}; };
};

@ -36,6 +36,8 @@
}, },
"devDependencies": { "devDependencies": {
"async": "^1.5.0", "async": "^1.5.0",
"body-parser": "^1.15.2",
"express": "^4.14.0",
"google-auth-library": "^0.9.2", "google-auth-library": "^0.9.2",
"google-protobuf": "^3.0.0", "google-protobuf": "^3.0.0",
"istanbul": "^0.3.21", "istanbul": "^0.3.21",

@ -84,8 +84,8 @@ END2END_FIXTURES = {
TestOptions = collections.namedtuple( TestOptions = collections.namedtuple(
'TestOptions', 'TestOptions',
'needs_fullstack needs_dns proxyable secure traceable cpu_cost exclude_iomgrs large_writes') 'needs_fullstack needs_dns proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky')
default_test_options = TestOptions(False, False, True, False, True, 1.0, [], False) default_test_options = TestOptions(False, False, True, False, True, 1.0, [], False, False)
connectivity_test_options = default_test_options._replace(needs_fullstack=True) connectivity_test_options = default_test_options._replace(needs_fullstack=True)
LOWCPU = 0.1 LOWCPU = 0.1
@ -108,7 +108,7 @@ END2END_TESTS = {
proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']), proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
'default_host': default_test_options._replace(needs_fullstack=True, 'default_host': default_test_options._replace(needs_fullstack=True,
needs_dns=True), needs_dns=True),
'disappearing_server': connectivity_test_options, 'disappearing_server': connectivity_test_options._replace(flaky=True),
'empty_batch': default_test_options, 'empty_batch': default_test_options,
'filter_causes_close': default_test_options, 'filter_causes_close': default_test_options,
'filter_call_init_fails': default_test_options, 'filter_call_init_fails': default_test_options,
@ -263,7 +263,7 @@ def main():
'ci_platforms': (END2END_FIXTURES[f].platforms 'ci_platforms': (END2END_FIXTURES[f].platforms
if END2END_FIXTURES[f].ci_mac else without( if END2END_FIXTURES[f].ci_mac else without(
END2END_FIXTURES[f].platforms, 'mac')), END2END_FIXTURES[f].platforms, 'mac')),
'flaky': False, 'flaky': END2END_TESTS[t].flaky,
'language': 'c', 'language': 'c',
'cpu_cost': END2END_TESTS[t].cpu_cost, 'cpu_cost': END2END_TESTS[t].cpu_cost,
} }
@ -280,7 +280,7 @@ def main():
'ci_platforms': (END2END_FIXTURES[f].platforms 'ci_platforms': (END2END_FIXTURES[f].platforms
if END2END_FIXTURES[f].ci_mac else without( if END2END_FIXTURES[f].ci_mac else without(
END2END_FIXTURES[f].platforms, 'mac')), END2END_FIXTURES[f].platforms, 'mac')),
'flaky': False, 'flaky': END2END_TESTS[t].flaky,
'language': 'c', 'language': 'c',
'cpu_cost': END2END_TESTS[t].cpu_cost, 'cpu_cost': END2END_TESTS[t].cpu_cost,
} }

@ -340,9 +340,9 @@ void resource_quota_server(grpc_end2end_test_config config) {
"Done. %d total calls: %d cancelled at server, %d cancelled at client.", "Done. %d total calls: %d cancelled at server, %d cancelled at client.",
NUM_CALLS, cancelled_calls_on_server, cancelled_calls_on_client); NUM_CALLS, cancelled_calls_on_server, cancelled_calls_on_client);
/* The server call may be cancelled after it's received it's status, but /* The call may be cancelled after the server has sent its status but before
* before the client does: this means that we should see strictly more * the client has received it. This means that we should see strictly more
* failures on the client than on the server */ * failures on the client than on the server. */
GPR_ASSERT(cancelled_calls_on_client >= cancelled_calls_on_server); GPR_ASSERT(cancelled_calls_on_client >= cancelled_calls_on_server);
/* However, we shouldn't see radically more... 0.9 is a guessed bound on what /* However, we shouldn't see radically more... 0.9 is a guessed bound on what
* we'd want that ratio to be... to at least trigger some investigation should * we'd want that ratio to be... to at least trigger some investigation should

@ -553,9 +553,13 @@ static void test_resource_user_stays_allocated_until_memory_released(void) {
static void static void
test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released( test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_released(
void) { void) {
gpr_log(GPR_INFO, "** test_pools_merged_on_resource_user_deletion **"); gpr_log(GPR_INFO,
grpc_resource_quota *q = "** "
grpc_resource_quota_create("test_pools_merged_on_resource_user_deletion"); "test_resource_user_stays_allocated_and_reclaimers_unrun_until_"
"memory_released **");
grpc_resource_quota *q = grpc_resource_quota_create(
"test_resource_user_stays_allocated_and_reclaimers_unrun_until_memory_"
"released");
grpc_resource_quota_resize(q, 1024); grpc_resource_quota_resize(q, 1024);
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
grpc_resource_user usr; grpc_resource_user usr;

@ -185,7 +185,7 @@ static void test_receive(int number_of_clients) {
/* Create a socket, send a packet to the UDP server. */ /* Create a socket, send a packet to the UDP server. */
clifd = socket(addr->ss_family, SOCK_DGRAM, 0); clifd = socket(addr->ss_family, SOCK_DGRAM, 0);
GPR_ASSERT(clifd >= 0); GPR_ASSERT(clifd >= 0);
GPR_ASSERT(connect(clifd, (struct sockaddr *)&addr, GPR_ASSERT(connect(clifd, (struct sockaddr *)addr,
(socklen_t)resolved_addr.len) == 0); (socklen_t)resolved_addr.len) == 0);
GPR_ASSERT(5 == write(clifd, "hello", 5)); GPR_ASSERT(5 == write(clifd, "hello", 5));
while (g_number_of_reads == number_of_reads_before && while (g_number_of_reads == number_of_reads_before &&

@ -130,11 +130,8 @@ class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient {
grpc::Status s = grpc::Status s =
stub->UnaryCall(&context, request_, &responses_[thread_idx]); stub->UnaryCall(&context, request_, &responses_[thread_idx]);
entry->set_value((UsageTimer::Now() - start) * 1e9); entry->set_value((UsageTimer::Now() - start) * 1e9);
if (!s.ok()) { entry->set_status(s.error_code());
gpr_log(GPR_ERROR, "RPC error: %d: %s", s.error_code(), return true;
s.error_message().c_str());
}
return s.ok();
} }
}; };

@ -39,6 +39,14 @@ cd $(dirname $0)/../..
PLATFORM=`uname -s` PLATFORM=`uname -s`
function is_msys() {
if [ "${PLATFORM/MSYS}" != "$PLATFORM" ]; then
echo true
else
exit 1
fi
}
function is_mingw() { function is_mingw() {
if [ "${PLATFORM/MINGW}" != "$PLATFORM" ]; then if [ "${PLATFORM/MINGW}" != "$PLATFORM" ]; then
echo true echo true
@ -108,6 +116,12 @@ VENV=${2:-$(venv $PYTHON)}
VENV_RELATIVE_PYTHON=${3:-$(venv_relative_python)} VENV_RELATIVE_PYTHON=${3:-$(venv_relative_python)}
TOOLCHAIN=${4:-$(toolchain)} TOOLCHAIN=${4:-$(toolchain)}
if [ $(is_msys) ]; then
echo "MSYS doesn't directly provide the right compiler(s);"
echo "switch to a MinGW shell."
exit 1
fi
ROOT=`pwd` ROOT=`pwd`
export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv $CFLAGS" export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv $CFLAGS"
export GRPC_PYTHON_BUILD_WITH_CYTHON=1 export GRPC_PYTHON_BUILD_WITH_CYTHON=1

@ -232,6 +232,15 @@ class CXXLanguage:
secure=secure, secure=secure,
categories=smoketest_categories + [SCALABLE]) categories=smoketest_categories + [SCALABLE])
yield _ping_pong_scenario(
'cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_%s' % secstr,
rpc_type='STREAMING',
client_type='ASYNC_CLIENT',
server_type='SYNC_SERVER',
unconstrained_client='async',
secure=secure,
categories=smoketest_categories+[SCALABLE])
for rpc_type in ['unary', 'streaming']: for rpc_type in ['unary', 'streaming']:
for synchronicity in ['sync', 'async']: for synchronicity in ['sync', 'async']:
yield _ping_pong_scenario( yield _ping_pong_scenario(
@ -361,7 +370,8 @@ class NodeLanguage:
self.safename = str(self) self.safename = str(self)
def worker_cmdline(self): def worker_cmdline(self):
return ['tools/run_tests/performance/run_worker_node.sh'] return ['tools/run_tests/performance/run_worker_node.sh',
'--benchmark_impl=grpc']
def worker_port_offset(self): def worker_port_offset(self):
return 200 return 200
@ -664,11 +674,69 @@ class GoLanguage:
def __str__(self): def __str__(self):
return 'go' return 'go'
class NodeExpressLanguage:
def __init__(self):
pass
self.safename = str(self)
def worker_cmdline(self):
return ['tools/run_tests/performance/run_worker_node.sh',
'--benchmark_impl=express']
def worker_port_offset(self):
return 700
def scenarios(self):
# TODO(jtattermusch): make this scenario work
#yield _ping_pong_scenario(
# 'node_generic_async_streaming_ping_pong', rpc_type='STREAMING',
# client_type='ASYNC_CLIENT', server_type='ASYNC_GENERIC_SERVER',
# use_generic_payload=True)
# TODO(jtattermusch): make this scenario work
#yield _ping_pong_scenario(
# 'node_protobuf_async_streaming_ping_pong', rpc_type='STREAMING',
# client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER')
yield _ping_pong_scenario(
'node_protobuf_unary_ping_pong', rpc_type='UNARY',
client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
categories=[SCALABLE, SMOKETEST])
yield _ping_pong_scenario(
'node_protobuf_async_unary_qps_unconstrained', rpc_type='UNARY',
client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
unconstrained_client='async',
categories=[SCALABLE, SMOKETEST])
# TODO(jtattermusch): make this scenario work
#yield _ping_pong_scenario(
# 'node_protobuf_async_streaming_qps_unconstrained', rpc_type='STREAMING',
# client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
# unconstrained_client='async')
# TODO(jtattermusch): make this scenario work
#yield _ping_pong_scenario(
# 'node_to_cpp_protobuf_async_unary_ping_pong', rpc_type='UNARY',
# client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
# server_language='c++', server_core_limit=1, async_server_threads=1)
# TODO(jtattermusch): make this scenario work
#yield _ping_pong_scenario(
# 'node_to_cpp_protobuf_async_streaming_ping_pong', rpc_type='STREAMING',
# client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
# server_language='c++', server_core_limit=1, async_server_threads=1)
def __str__(self):
return 'node_express'
LANGUAGES = { LANGUAGES = {
'c++' : CXXLanguage(), 'c++' : CXXLanguage(),
'csharp' : CSharpLanguage(), 'csharp' : CSharpLanguage(),
'node' : NodeLanguage(), 'node' : NodeLanguage(),
'node_express': NodeExpressLanguage(),
'ruby' : RubyLanguage(), 'ruby' : RubyLanguage(),
'java' : JavaLanguage(), 'java' : JavaLanguage(),
'python' : PythonLanguage(), 'python' : PythonLanguage(),

@ -42,6 +42,7 @@ import os
import performance.scenario_config as scenario_config import performance.scenario_config as scenario_config
import pipes import pipes
import re import re
import report_utils
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
@ -453,6 +454,7 @@ if not scenarios:
total_scenario_failures = 0 total_scenario_failures = 0
qps_workers_killed = 0 qps_workers_killed = 0
merged_resultset = {}
for scenario in scenarios: for scenario in scenarios:
if args.dry_run: if args.dry_run:
print(scenario.name) print(scenario.name)
@ -460,14 +462,20 @@ for scenario in scenarios:
try: try:
for worker in scenario.workers: for worker in scenario.workers:
worker.start() worker.start()
scenario_failures, _ = jobset.run([scenario.jobspec, scenario_failures, resultset = jobset.run([scenario.jobspec,
create_quit_jobspec(scenario.workers, remote_host=args.remote_driver_host)], create_quit_jobspec(scenario.workers, remote_host=args.remote_driver_host)],
newline_on_success=True, maxjobs=1) newline_on_success=True, maxjobs=1)
total_scenario_failures += scenario_failures total_scenario_failures += scenario_failures
merged_resultset = dict(itertools.chain(merged_resultset.iteritems(),
resultset.iteritems()))
finally: finally:
# Consider qps workers that need to be killed as failures # Consider qps workers that need to be killed as failures
qps_workers_killed += finish_qps_workers(scenario.workers) qps_workers_killed += finish_qps_workers(scenario.workers)
report_utils.render_junit_xml_report(merged_resultset, 'report.xml',
suite_name='benchmarks')
if total_scenario_failures > 0 or qps_workers_killed > 0: if total_scenario_failures > 0 or qps_workers_killed > 0:
print ("%s scenarios failed and %s qps worker jobs killed" % (total_scenario_failures, qps_workers_killed)) print ("%s scenarios failed and %s qps worker jobs killed" % (total_scenario_failures, qps_workers_killed))
sys.exit(1) sys.exit(1)

@ -842,6 +842,53 @@ class Sanity(object):
def __str__(self): def __str__(self):
return 'sanity' return 'sanity'
class NodeExpressLanguage(object):
"""Dummy Node express test target to enable running express performance
benchmarks"""
def __init__(self):
self.platform = platform_string()
def configure(self, config, args):
self.config = config
self.args = args
_check_compiler(self.args.compiler, ['default', 'node0.12',
'node4', 'node5', 'node6'])
if self.args.compiler == 'default':
self.node_version = '4'
else:
# Take off the word "node"
self.node_version = self.args.compiler[4:]
def test_specs(self):
return []
def pre_build_steps(self):
if self.platform == 'windows':
return [['tools\\run_tests\\pre_build_node.bat']]
else:
return [['tools/run_tests/pre_build_node.sh', self.node_version]]
def make_targets(self):
return []
def make_options(self):
return []
def build_steps(self):
return []
def post_tests_steps(self):
return []
def makefile_name(self):
return 'Makefile'
def dockerfile_dir(self):
return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
def __str__(self):
return 'node_express'
# different configurations we can run under # different configurations we can run under
with open('tools/run_tests/configs.json') as f: with open('tools/run_tests/configs.json') as f:
@ -852,6 +899,7 @@ _LANGUAGES = {
'c++': CLanguage('cxx', 'c++'), 'c++': CLanguage('cxx', 'c++'),
'c': CLanguage('c', 'c'), 'c': CLanguage('c', 'c'),
'node': NodeLanguage(), 'node': NodeLanguage(),
'node_express': NodeExpressLanguage(),
'php': PhpLanguage(), 'php': PhpLanguage(),
'php7': Php7Language(), 'php7': Php7Language(),
'python': PythonLanguage(), 'python': PythonLanguage(),

@ -5156,7 +5156,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_census_test", "name": "h2_census_test",
"platforms": [ "platforms": [
@ -6193,7 +6193,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_compress_test", "name": "h2_compress_test",
"platforms": [ "platforms": [
@ -7230,7 +7230,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_fake_resolver_test", "name": "h2_fake_resolver_test",
"platforms": [ "platforms": [
@ -8254,7 +8254,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_fakesec_test", "name": "h2_fakesec_test",
"platforms": [ "platforms": [
@ -10179,7 +10179,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_full_test", "name": "h2_full_test",
"platforms": [ "platforms": [
@ -11165,7 +11165,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_full+pipe_test", "name": "h2_full+pipe_test",
"platforms": [ "platforms": [
@ -12071,7 +12071,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_full+trace_test", "name": "h2_full+trace_test",
"platforms": [ "platforms": [
@ -13073,7 +13073,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_http_proxy_test", "name": "h2_http_proxy_test",
"platforms": [ "platforms": [
@ -14142,7 +14142,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_load_reporting_test", "name": "h2_load_reporting_test",
"platforms": [ "platforms": [
@ -15190,7 +15190,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_oauth2_test", "name": "h2_oauth2_test",
"platforms": [ "platforms": [
@ -16222,7 +16222,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_proxy_test", "name": "h2_proxy_test",
"platforms": [ "platforms": [
@ -20033,7 +20033,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_ssl_test", "name": "h2_ssl_test",
"platforms": [ "platforms": [
@ -21070,7 +21070,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_ssl_cert_test", "name": "h2_ssl_cert_test",
"platforms": [ "platforms": [
@ -22070,7 +22070,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_ssl_proxy_test", "name": "h2_ssl_proxy_test",
"platforms": [ "platforms": [
@ -22995,7 +22995,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_uds_test", "name": "h2_uds_test",
"platforms": [ "platforms": [
@ -24008,7 +24008,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_census_nosec_test", "name": "h2_census_nosec_test",
"platforms": [ "platforms": [
@ -25022,7 +25022,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_compress_nosec_test", "name": "h2_compress_nosec_test",
"platforms": [ "platforms": [
@ -26036,7 +26036,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_fake_resolver_nosec_test", "name": "h2_fake_resolver_nosec_test",
"platforms": [ "platforms": [
@ -27947,7 +27947,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_full_nosec_test", "name": "h2_full_nosec_test",
"platforms": [ "platforms": [
@ -28914,7 +28914,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_full+pipe_nosec_test", "name": "h2_full+pipe_nosec_test",
"platforms": [ "platforms": [
@ -29797,7 +29797,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_full+trace_nosec_test", "name": "h2_full+trace_nosec_test",
"platforms": [ "platforms": [
@ -30775,7 +30775,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_http_proxy_nosec_test", "name": "h2_http_proxy_nosec_test",
"platforms": [ "platforms": [
@ -31821,7 +31821,7 @@
"cpu_cost": 1.0, "cpu_cost": 1.0,
"exclude_configs": [], "exclude_configs": [],
"exclude_iomgrs": [], "exclude_iomgrs": [],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_load_reporting_nosec_test", "name": "h2_load_reporting_nosec_test",
"platforms": [ "platforms": [
@ -32797,7 +32797,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_proxy_nosec_test", "name": "h2_proxy_nosec_test",
"platforms": [ "platforms": [
@ -36487,7 +36487,7 @@
"exclude_iomgrs": [ "exclude_iomgrs": [
"uv" "uv"
], ],
"flaky": false, "flaky": true,
"language": "c", "language": "c",
"name": "h2_uds_nosec_test", "name": "h2_uds_nosec_test",
"platforms": [ "platforms": [
@ -37316,6 +37316,27 @@
"shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_secure", "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_secure",
"timeout_seconds": 180 "timeout_seconds": 180
}, },
{
"args": [
"--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
],
"boringssl": true,
"ci_platforms": [
"linux"
],
"cpu_cost": 8,
"defaults": "boringssl",
"exclude_configs": [],
"flaky": false,
"language": "c++",
"name": "json_run_localhost",
"platforms": [
"linux"
],
"shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_secure",
"timeout_seconds": 180
},
{ {
"args": [ "args": [
"--scenarios_json", "--scenarios_json",
@ -37652,6 +37673,27 @@
"shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure", "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure",
"timeout_seconds": 180 "timeout_seconds": 180
}, },
{
"args": [
"--scenarios_json",
"{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"core_limit\": 0, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}, \"num_clients\": 0}]}"
],
"boringssl": true,
"ci_platforms": [
"linux"
],
"cpu_cost": 8,
"defaults": "boringssl",
"exclude_configs": [],
"flaky": false,
"language": "c++",
"name": "json_run_localhost",
"platforms": [
"linux"
],
"shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure",
"timeout_seconds": 180
},
{ {
"args": [ "args": [
"--scenarios_json", "--scenarios_json",

Loading…
Cancel
Save