Return-Path: X-Original-To: apmail-couchdb-commits-archive@www.apache.org Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 29FAF18BE0 for ; Fri, 17 Jul 2015 16:52:55 +0000 (UTC) Received: (qmail 94355 invoked by uid 500); 17 Jul 2015 16:52:55 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 94297 invoked by uid 500); 17 Jul 2015 16:52:55 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 94284 invoked by uid 99); 17 Jul 2015 16:52:55 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 17 Jul 2015 16:52:55 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E2FFAE050A; Fri, 17 Jul 2015 16:52:54 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: rnewson@apache.org To: commits@couchdb.apache.org Date: Fri, 17 Jul 2015 16:52:54 -0000 Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: [1/2] couch commit: updated refs/heads/master to 9f45cf1 Repository: couchdb-couch Updated Branches: refs/heads/master 8b4af2160 -> 9f45cf180 Optimize couch_ejson_compare NIF The old nif was allocating a set of collators that were reserved and released by each scheduler thread. This coordination and the accompanying mutex turned into a global point of contention when many schedulers were using couch_ejson_compare. This change removes the stack based concurrency control in favor of a `__thread variable`. We end up with the same number of collators but without any overhead around locking a central mutex. This increases performance by roughly a factor of five. COUCHDB-2732 Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/6b38dfac Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/6b38dfac Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/6b38dfac Branch: refs/heads/master Commit: 6b38dfacbb97c5cb7c89a27115d1227c7c52dbba Parents: b3d1028 Author: Paul J. Davis Authored: Mon Jul 13 12:14:09 2015 -0500 Committer: Paul J. Davis Committed: Mon Jul 13 12:14:28 2015 -0500 ---------------------------------------------------------------------- priv/couch_ejson_compare/couch_ejson_compare.c | 70 ++++++++------------- 1 file changed, 25 insertions(+), 45 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/6b38dfac/priv/couch_ejson_compare/couch_ejson_compare.c ---------------------------------------------------------------------- diff --git a/priv/couch_ejson_compare/couch_ejson_compare.c b/priv/couch_ejson_compare/couch_ejson_compare.c index 9d20a7e..df001a1 100644 --- a/priv/couch_ejson_compare/couch_ejson_compare.c +++ b/priv/couch_ejson_compare/couch_ejson_compare.c @@ -41,9 +41,10 @@ typedef struct { UCollator* coll; } ctx_t; +static __thread UCollator* collator = NULL; static UCollator** collators = NULL; -static int collStackTop = 0; static int numCollators = 0; +static int numSchedulers = 0; static ErlNifMutex* collMutex = NULL; static ERL_NIF_TERM less_json_nif(ErlNifEnv*, int, const ERL_NIF_TERM []); @@ -54,35 +55,34 @@ static __inline int atom_sort_order(ErlNifEnv*, ERL_NIF_TERM); static __inline int compare_strings(ctx_t*, ErlNifBinary, ErlNifBinary); static __inline int compare_lists(int, ctx_t*, ERL_NIF_TERM, ERL_NIF_TERM); static __inline int compare_props(int, ctx_t*, ERL_NIF_TERM, ERL_NIF_TERM); -static __inline void reserve_coll(ctx_t*); -static __inline void release_coll(ctx_t*); +static __inline UCollator* get_collator(); -void -reserve_coll(ctx_t *ctx) +UCollator* +get_collator() { - if (ctx->coll == NULL) { - enif_mutex_lock(collMutex); - assert(collStackTop < numCollators); - ctx->coll = collators[collStackTop]; - collStackTop += 1; - enif_mutex_unlock(collMutex); + UErrorCode status = U_ZERO_ERROR; + + if(collator != NULL) { + return collator; } -} + collator = ucol_open("", &status); -void -release_coll(ctx_t *ctx) -{ - if (ctx->coll != NULL) { - enif_mutex_lock(collMutex); - collStackTop -= 1; - assert(collStackTop >= 0); - enif_mutex_unlock(collMutex); + if (U_FAILURE(status)) { + ucol_close(collator); + return NULL; } -} + enif_mutex_lock(collMutex); + collators[numCollators] = collator; + numCollators++; + enif_mutex_unlock(collMutex); + assert(numCollators <= numSchedulers && "Number of schedulers shrank."); + + return collator; +} ERL_NIF_TERM less_json_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -92,10 +92,9 @@ less_json_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ctx.env = env; ctx.error = 0; - ctx.coll = NULL; + ctx.coll = get_collator(); result = less_json(1, &ctx, argv[0], argv[1]); - release_coll(&ctx); /* * There are 2 possible failure reasons: @@ -357,7 +356,6 @@ compare_strings(ctx_t* ctx, ErlNifBinary a, ErlNifBinary b) uiter_setUTF8(&iterA, (const char *) a.data, (uint32_t) a.size); uiter_setUTF8(&iterB, (const char *) b.data, (uint32_t) b.size); - reserve_coll(ctx); result = ucol_strcollIter(ctx->coll, &iterA, &iterB, &status); if (U_FAILURE(status)) { @@ -375,14 +373,11 @@ compare_strings(ctx_t* ctx, ErlNifBinary a, ErlNifBinary b) int on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info) { - UErrorCode status = U_ZERO_ERROR; - int i, j; - - if (!enif_get_int(env, info, &numCollators)) { + if (!enif_get_int(env, info, &numSchedulers)) { return 1; } - if (numCollators < 1) { + if (numSchedulers < 1) { return 2; } @@ -392,28 +387,13 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info) return 3; } - collators = enif_alloc(sizeof(UCollator*) * numCollators); + collators = enif_alloc(sizeof(UCollator*) * numSchedulers); if (collators == NULL) { enif_mutex_destroy(collMutex); return 4; } - for (i = 0; i < numCollators; i++) { - collators[i] = ucol_open("", &status); - - if (U_FAILURE(status)) { - for (j = 0; j < i; j++) { - ucol_close(collators[j]); - } - - enif_free(collators); - enif_mutex_destroy(collMutex); - - return 5; - } - } - ATOM_TRUE = enif_make_atom(env, "true"); ATOM_FALSE = enif_make_atom(env, "false"); ATOM_NULL = enif_make_atom(env, "null");