From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Alex Gramiak Newsgroups: gmane.emacs.bugs Subject: bug#31138: Native json slower than json.el Date: Mon, 22 Apr 2019 21:06:26 -0600 Message-ID: <877ebl5sjx.fsf@gmail.com> References: <87ftq96gww.fsf@gmail.com> <83imv56gke.fsf@gnu.org> <87bm0x6cnq.fsf@gmail.com> <12721b41-c493-8193-b820-9ab4b229f102@yandex.ru> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="5072"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) Cc: 31138@debbugs.gnu.org To: Dmitry Gutov Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Tue Apr 23 05:10:18 2019 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hIlp3-00018z-Cg for geb-bug-gnu-emacs@m.gmane.org; Tue, 23 Apr 2019 05:10:17 +0200 Original-Received: from localhost ([127.0.0.1]:47250 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hIlp2-00066F-7i for geb-bug-gnu-emacs@m.gmane.org; Mon, 22 Apr 2019 23:10:16 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:47688) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hIlos-00065q-G8 for bug-gnu-emacs@gnu.org; Mon, 22 Apr 2019 23:10:08 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hIllu-0005xG-Kc for bug-gnu-emacs@gnu.org; Mon, 22 Apr 2019 23:07:04 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:38569) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hIllu-0005xA-GD for bug-gnu-emacs@gnu.org; Mon, 22 Apr 2019 23:07:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1hIllt-0004Yh-V8 for bug-gnu-emacs@gnu.org; Mon, 22 Apr 2019 23:07:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Alex Gramiak Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 23 Apr 2019 03:07:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 31138 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: moreinfo Original-Received: via spool by 31138-submit@debbugs.gnu.org id=B31138.155598880117492 (code B ref 31138); Tue, 23 Apr 2019 03:07:01 +0000 Original-Received: (at 31138) by debbugs.gnu.org; 23 Apr 2019 03:06:41 +0000 Original-Received: from localhost ([127.0.0.1]:52112 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hIllX-0004Y1-2q for submit@debbugs.gnu.org; Mon, 22 Apr 2019 23:06:39 -0400 Original-Received: from mail-pg1-f179.google.com ([209.85.215.179]:37402) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hIllS-0004Xl-QW for 31138@debbugs.gnu.org; Mon, 22 Apr 2019 23:06:37 -0400 Original-Received: by mail-pg1-f179.google.com with SMTP id e6so6810935pgc.4 for <31138@debbugs.gnu.org>; Mon, 22 Apr 2019 20:06:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=nCxl5liqJAVrIul7v3V9om+OtdppXN4ulz8JXzZLEds=; b=f+4QkYR+USC4v9mn6/DryxQIO2Lt85JepM5ilv+owK0aBOBXq6bAiRqAh4W/s5VUbN fwDcrqgOdaLY8moWSmn/F845jEr1n/5f5AYyxAF1SRCn8+WnajgMsEOnpkXzgmVAfpRH DK5EIzMEjWfnr7CUHm7A/FjB/pUOTKBS6qD90E4edinaSdSIITzPYdvnBl6JKwCIBCvL sNkETV9adzZcImK7qPLm0aZFHzV0fvQWQ0WyKg/Nj3xvP6gLko4IFPBLnbZtG2z6deRX X5fOCwN/n1TD0M/KiU+lD1PyH2F/Y4shhgsRKw2/wgG5xWkWlp0BJ6cmRyNwzyyz/Hcx TshQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=nCxl5liqJAVrIul7v3V9om+OtdppXN4ulz8JXzZLEds=; b=tTbla+es+iEq6KR+/Urib1cruSXmhJqAOdPXgHbzU2fYqWoWXhzm8RPq5HBx2B0AD8 VStEmHfLWhWXROV80KLqTCxXwPmEYHj9kBfZFZLbxyhDx8IPZYPOsLJEipMtN3GaKx8M GVGMfLkJM0W/K9qY1usNiVaEF7RbfhBZCxT70t/zbH8k1lFk/kBiXIkT94z1+9tUQYYy G3BBf41hl3MEWq1NCZkIO5mjTtClIlNl+AHBARlr7gxeqU6MvcEVluJH3HeJ6AD3uHOT ksmiZVSZy8SFjJVvZ11zM0VPqWthYuFAAUsAGx/a/uKoPn4WKT/gqs6gEaR5IuslHsyL WBAw== X-Gm-Message-State: APjAAAVCz1iNGIUizPHsfI6/VkR3eOMNLxoxMalDzbmWaflodk96Xiv3 I4aJXuPsER+8382WtUUAayDxQwNL X-Google-Smtp-Source: APXvYqzG3fY3peTDSiGmu4zanHX91UZTj/b7LGdYwbOZdG/yTNtGlkZD1PrIOHZRl9zu81unAX8f0A== X-Received: by 2002:a63:360c:: with SMTP id d12mr21986765pga.404.1555988788507; Mon, 22 Apr 2019 20:06:28 -0700 (PDT) Original-Received: from lylat ([2604:3d09:e37f:1500:1a72:4878:e793:7302]) by smtp.gmail.com with ESMTPSA id i10sm32419566pfj.7.2019.04.22.20.06.26 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 22 Apr 2019 20:06:27 -0700 (PDT) In-Reply-To: <12721b41-c493-8193-b820-9ab4b229f102@yandex.ru> (Dmitry Gutov's message of "Mon, 22 Apr 2019 23:05:30 +0300") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:158097 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Dmitry Gutov writes: > On 22.04.2019 22:52, Alex Gramiak wrote: >> The following might work, though I'm not >> sure how applicable this is now to the jansson library: > > Peformance patches are 200% better when they come together with benchmark > results. Right, I should have explained: I meant that since AFAIU the size of json_int_t is usually going to be the same size as EMACS_INT, the same code will usually be generated for json.c. It might bring a very slight benefit to other parts of Emacs, but not worth fussing over. I tried making a couple patches in other areas to json.c that I hoped would slightly improve performance, which I'll include here for posterity. The first one uses json_dumpb over json_dumps, but from what I can tell using it is either slower or just within error. The second uses the *_nocheck functions where applicable, but the results seemed to be quite similar. I suppose this means that jansson's utf-8 checking is performant. Benchmark for the first patch: (setq v ["\nasd=D1=84=D1=8B=D0=B2\u001f\u007ffgh\t"]) =20=20 (progn (garbage-collect) (benchmark-run-compiled 100000 (json-serialize v))) Results for the first patch: 1.1050s applied vs. 1.1078s without. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=json-dumpb.diff Content-Description: json_dumpb diff --git a/configure.ac b/configure.ac index b4a9b30691..2dba99838f 100644 --- a/configure.ac +++ b/configure.ac @@ -2982,6 +2982,10 @@ AC_DEFUN if test "${HAVE_JSON}" = yes; then AC_DEFINE(HAVE_JSON, 1, [Define if using Jansson.]) JSON_OBJ=json.o + OLDLIBS="$LIBS" + LIBS="$LIBS $JSON_LIBS" + AC_CHECK_FUNCS(json_dumpb) + LIBS="$OLDLIBS" fi # Windows loads libjansson dynamically diff --git a/src/json.c b/src/json.c index 928825e034..361581c2f4 100644 --- a/src/json.c +++ b/src/json.c @@ -31,7 +31,7 @@ along with GNU Emacs. If not, see . */ #include "coding.h" #define JSON_HAS_ERROR_CODE (JANSSON_VERSION_HEX >= 0x020B00) - +#undef HAVE_JSON_DUMPB #ifdef WINDOWSNT # include # include "w32common.h" @@ -53,6 +53,11 @@ DEF_DLL_FN (json_t *, json_integer, (json_int_t value)); DEF_DLL_FN (json_t *, json_real, (double value)); DEF_DLL_FN (json_t *, json_stringn, (const char *value, size_t len)); DEF_DLL_FN (char *, json_dumps, (const json_t *json, size_t flags)); +# ifdef HAVE_JSON_DUMPB +DEF_DLL_FN (void, json_dumpb, (const json_t *json, char *buffer, + size_t size, + size_t flags)); +# endif DEF_DLL_FN (int, json_dump_callback, (const json_t *json, json_dump_callback_t callback, void *data, size_t flags)); @@ -104,6 +109,9 @@ init_json_functions (void) LOAD_DLL_FN (library, json_real); LOAD_DLL_FN (library, json_stringn); LOAD_DLL_FN (library, json_dumps); +# ifdef HAVE_JSON_DUMPB + LOAD_DLL_FN (library, json_dumpb); +# endif LOAD_DLL_FN (library, json_dump_callback); LOAD_DLL_FN (library, json_integer_value); LOAD_DLL_FN (library, json_real_value); @@ -605,6 +613,10 @@ usage: (json-serialize OBJECT &rest ARGS) */) { ptrdiff_t count = SPECPDL_INDEX (); +#ifdef HAVE_JSON_DUMPB + USE_SAFE_ALLOCA; +#endif + #ifdef WINDOWSNT if (!json_initialized) { @@ -625,16 +637,34 @@ usage: (json-serialize OBJECT &rest ARGS) */) json_parse_args (nargs - 1, args + 1, &conf, false); json_t *json = lisp_to_json_toplevel (args[0], &conf); - record_unwind_protect_ptr (json_release_object, json); +#ifdef HAVE_JSON_DUMPB + /* Called with NULL to determine the size of buffer needed. */ + size_t size = json_dumpb (json, NULL, 0, 0); + char *string = SAFE_ALLOCA (size); + + size = json_dumpb (json, string, size, JSON_COMPACT); + + json_release_object (json); + + if (!size) + json_out_of_memory (); + + + return SAFE_FREE_UNBIND_TO (count, json_make_string (string, size)); +#else /* If desired, we might want to add the following flags: JSON_DECODE_ANY, JSON_ALLOW_NUL. */ char *string = json_dumps (json, JSON_COMPACT); + + json_release_object (json); + if (string == NULL) json_out_of_memory (); record_unwind_protect_ptr (json_free, string); return unbind_to (count, json_build_string (string)); +#endif } struct json_buffer_and_size --=-=-= Content-Type: text/plain Benchmark for the second patch: (setq v (with-current-buffer (find-file-noselect "~/emacs/test/src/json-tests.el") (vector (buffer-substring-no-properties (point-min) (point-max))))) (progn (garbage-collect) (benchmark-run-compiled 1000 (json-serialize v))) Results for the second patch: 0.7815s applied vs. 0.7962s without. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=json_*_nocheck.diff Content-Description: nocheck diff --git a/src/json.c b/src/json.c index 928825e034..3aa6be7212 100644 --- a/src/json.c +++ b/src/json.c @@ -46,12 +46,14 @@ DEF_DLL_FN (size_t, json_array_size, (const json_t *array)); DEF_DLL_FN (json_t *, json_object, (void)); DEF_DLL_FN (int, json_object_set_new, (json_t *object, const char *key, json_t *value)); +DEF_DLL_FN (int, json_object_set_new_nocheck, + (json_t *object, const char *key, json_t *value)); DEF_DLL_FN (json_t *, json_null, (void)); DEF_DLL_FN (json_t *, json_true, (void)); DEF_DLL_FN (json_t *, json_false, (void)); DEF_DLL_FN (json_t *, json_integer, (json_int_t value)); DEF_DLL_FN (json_t *, json_real, (double value)); -DEF_DLL_FN (json_t *, json_stringn, (const char *value, size_t len)); +DEF_DLL_FN (json_t *, json_stringn_nocheck, (const char *value, size_t len)); DEF_DLL_FN (char *, json_dumps, (const json_t *json, size_t flags)); DEF_DLL_FN (int, json_dump_callback, (const json_t *json, json_dump_callback_t callback, void *data, @@ -97,12 +99,13 @@ init_json_functions (void) LOAD_DLL_FN (library, json_array_size); LOAD_DLL_FN (library, json_object); LOAD_DLL_FN (library, json_object_set_new); + LOAD_DLL_FN (library, json_object_set_new_nocheck); LOAD_DLL_FN (library, json_null); LOAD_DLL_FN (library, json_true); LOAD_DLL_FN (library, json_false); LOAD_DLL_FN (library, json_integer); LOAD_DLL_FN (library, json_real); - LOAD_DLL_FN (library, json_stringn); + LOAD_DLL_FN (library, json_stringn_nocheck); LOAD_DLL_FN (library, json_dumps); LOAD_DLL_FN (library, json_dump_callback); LOAD_DLL_FN (library, json_integer_value); @@ -131,12 +134,13 @@ init_json_functions (void) #define json_array_size fn_json_array_size #define json_object fn_json_object #define json_object_set_new fn_json_object_set_new +#define json_object_set_new_nocheck fn_json_object_set_new_nocheck #define json_null fn_json_null #define json_true fn_json_true #define json_false fn_json_false #define json_integer fn_json_integer #define json_real fn_json_real -#define json_stringn fn_json_stringn +#define json_stringn_nocheck fn_json_stringn_nocheck #define json_dumps fn_json_dumps #define json_dump_callback fn_json_dump_callback #define json_integer_value fn_json_integer_value @@ -394,9 +398,10 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, table test is not `equal'. */ if (json_object_get (json, key_str) != NULL) wrong_type_argument (Qjson_value_p, lisp); - int status = json_object_set_new (json, key_str, - lisp_to_json (HASH_VALUE (h, i), - conf)); + int status + = json_object_set_new_nocheck (json, key_str, + lisp_to_json (HASH_VALUE (h, i), + conf)); if (status == -1) { /* A failure can be caused either by an invalid key or @@ -508,12 +513,9 @@ lisp_to_json (Lisp_Object lisp, struct json_configuration *conf) else if (STRINGP (lisp)) { Lisp_Object encoded = json_encode (lisp); - json_t *json = json_stringn (SSDATA (encoded), SBYTES (encoded)); + json_t *json = json_stringn_nocheck (SSDATA (encoded), SBYTES (encoded)); if (json == NULL) { - /* A failure can be caused either by an invalid string or by - low memory. */ - json_check_utf8 (encoded); json_out_of_memory (); } return json; --=-=-=--