rurban / Cpanel-JSON-XS

Improved fork of JSON-XS
http://search.cpan.org/dist/Cpanel-JSON-XS/
Other
40 stars 44 forks source link

add PERL_NO_GET_CONTEXT patches #16

Closed bulk88 closed 10 years ago

bulk88 commented 10 years ago

CJX/JX's design is unusual. For many functions, a enc/dec var mimmics the behavior of the my_perl * on threaded perls. So I wrote 2 different patches, this one https://github.com/bulk88/Cpanel-JSON-XS/commit/78988d331bafe328109cea624fade628adead769 on branch context_method2 deeply integrates into CJX/JX's design philosophy. A more generic patch that simply puts aTHX/pTHX everywhere, is at https://github.com/bulk88/Cpanel-JSON-XS/commit/4d93350354fa05f631e9152fac82a2c4e1852e07 on branch context_method1. I dont think I benchmark which is faster. I would WAG context_method2 is faster since there are less instructions in the final binary, and in some functions all traces of my_perl are removed in context_method2, so no reading my_perl from C stack, push my_perl onto C stack instructions. Instead my_perl moves along with enc/dec with no overhead .

threaded Win32 perl with VC 2003 32 bits, PE section sizes in bytes, .text is machine code

2.3404 master, no PERL_NO_GET_CONTEXT .text 0x492d .rdata 0x1b60 .data 0x140

context_method1 .text 0x427d .rdata 0x1b60 .data 0x140

context_method2 .text 0x419d .rdata 0x1b60 .data 0x140

CJX is still not thread safe since it doesn't use MY_CXT and has code like

static HV *json_stash, *json_boolean_stash; /* Cpanel::JSON::XS:: */
static SV *json_true, *json_false;

Also in the XSUBs there is needless X'es in XPUSHs, since the stack already has room since number of incoming params is >= 1 returned param and decode_json and encode_json the c funcs don't return anything on perl stack.

Also this code is silly. It looks to be trying to be EBCDIC compatible but increases startup time and is unshareable between perl processes.

MODULE = Cpanel::JSON::XS       PACKAGE = Cpanel::JSON::XS

BOOT:
{
    int i;

        for (i = 0; i < 256; ++i)
          decode_hexdigit [i] =
            i >= '0' && i <= '9' ? i - '0'
            : i >= 'a' && i <= 'f' ? i - 'a' + 10
            : i >= 'A' && i <= 'F' ? i - 'A' + 10
            : -1;

    json_stash         = gv_stashpv ("Cpanel::JSON::XS"         , 1);
    json_boolean_stash = gv_stashpv ("JSON::XS::Boolean", 1);

That should be static const data with an unrolled array initializer. A small perl script could generate the table once and forever.

rurban commented 10 years ago

I took #17. Thanks a lot. Now just the new JSON::XS interop needs to be fixed

bulk88 commented 10 years ago

This was prematurly closed. Ummmm, #17 DOES NOT have the PERL_NO_GET_CONTEXT code. This issue ( #16 ) is a separate pull req for different problem, but since github doesnt allow 2 branches in 1 PR, this isnt an official PR. Please review the 2 branches/commits in the OP of this ticket. The code in this ticket did not make it into your 3.0101 release.

rurban commented 10 years ago

Oops, I didn't have a close look. Will bump a new release tomorrow with the normal way (method1), but I'll check before. Keeping my_perl on the stack doesn't cost on normal API calls. Normalizing the API is good.

bulk88 commented 10 years ago

There will be a xsub optimization patch coming soon, so hold off on the cpan release, but in the meantime decide what to do about PERL_NO_GET_CONTEXT. Method1 maintains binary compatibility with JSON::XS's blessed C structs objects. I modified the JSON struct. Is that a requirement of CJX? If so, method1 must be used. Method 2 is slimmer and faster, than method 1, but breaks object code/C struct ABI between CJX and JX. Also hold off on the CPAN release because I need to write new patch to clean up the XSUBs. I am intentionally breaking this up into different commits instead of me delivering 1 grand orange ball that standards taller than all the other balls on the beach, include the black red gold brick pretending to be a beach ball, for managability.

_Keeping myperl on the stack doesn't cost on normal API calls.

There is a cost for my_perl on the stack, since each func call requires a new copy of my_perl for each new C func frame. There is no concept of a const register or a const C auto on asm level on x86 ABI. For example need() has 20 call sites, on GCC 32 bit 4.6 -O2, with method1, need() gets my_perl in reg eax each time from its callers (non standard calling convention). At each caller edi or esi is copied to eax before call need instruction. Each need() on method1 requires 3 mov instructions. On method 2 each need() only required 2 mov instructions. Next is context_method1 .text size on GCC, look at "virtual size", ignore the other numbers. "size of raw data" is the image section aligned to next page boundary/disk sector.

C:\sources\Cpanel-JSON-XS>dumpbin /section:.text  "C:\sources\Cpanel-JSON-XS\bli
b\arch\auto\Cpanel\JSON\XS\xs.dll"
Microsoft (R) COFF/PE Dumper Version 7.10.6030
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file C:\sources\Cpanel-JSON-XS\blib\arch\auto\Cpanel\JSON\XS\xs.dll
u
File Type: DLL

SECTION HEADER #1
   .text name
    8E24 virtual size
    1000 virtual address (6AF41000 to 6AF49E23)
    9000 size of raw data
     400 file pointer to raw data (00000400 to 000093FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60500060 flags
         Code
         Initialized Data
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Execute Read

  Summary

        9000 .text

C:\sources\Cpanel-JSON-XS>

with context_method2

C:\sources\Cpanel-JSON-XS>dumpbin /section:.text  "C:\sources\Cpanel-JSON-XS\bli
b\arch\auto\Cpanel\JSON\XS\xs.dll"
Microsoft (R) COFF/PE Dumper Version 7.10.6030
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file C:\sources\Cpanel-JSON-XS\blib\arch\auto\Cpanel\JSON\XS\xs.dll

File Type: DLL

SECTION HEADER #1
   .text name
    8D34 virtual size
    1000 virtual address (6AF41000 to 6AF49D33)
    8E00 size of raw data
     400 file pointer to raw data (00000400 to 000091FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60500060 flags
         Code
         Initialized Data
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Execute Read

  Summary

        9000 .text

C:\sources\Cpanel-JSON-XS>

I suggest you try and benchmark both branches on your machines with a threaded perl, and good large json workload file of your day job, (cpanel/commercial customer).

I noticed the bench tool in eg. Changed it so count == 200 (I kept times at default which is 200), and a I give the script a 15 KB json file, method2 seems to be slightly faster, compare the decode column. And I assume the bench script gives the best/lowest/minimum time of all runs. encode column is unpredictable for method1 and method2.

method1, GCC 4.6 32 bit -02 threaded perl

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  52288.275 |   4716.994 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  55883.072 |   5041.837 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  65813.651 |   5148.786 |
--------------+------------+------------+
C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  23389.399 |   4851.542 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  22170.383 |   5239.998 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  34940.886 |   4435.366 |
--------------+------------+------------+

method2 GCC 4.6 32 bit -02 threaded perl

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS | 116476.090 |   4195.416 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  39936.244 |   4158.788 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  41142.812 |   4968.201 |
--------------+------------+------------+
C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  25281.360 |   4191.559 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  40469.934 |   4251.163 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  41892.769 |   5024.111 |
--------------+------------+------------+

C:\sources\Cpanel-JSON-XS\eg>perl bench < t.json
module        |     encode |     decode |
--------------|------------|------------|
Cpanel::JSON::XS |  16952.162 |   4347.262 |
--------------+------------+------------+
rurban commented 10 years ago

I tried both and don't really like method2 just for maintenance reasons. Your benchmark number look a bit too crazy to me so far. But if it's really worth on our own json benchmarks I'll reconsider it. We test with several workloads: small, medium, big, and usually against Data::MessagePack and Sereal.

bulk88 commented 10 years ago

rebased onto cjx 3 https://github.com/bulk88/Cpanel-JSON-XS/commits/contextmethod2_on_CJX3 https://github.com/bulk88/Cpanel-JSON-XS/commits/contextmethod1_on_CJX3

rurban commented 10 years ago

Merged contextmethod1_on_CJX3 with commit 585a5940e5f30d458bdc5c425ca1965b2cdefe6c Author: bulk88 bulk88@hotmail.com Date: Wed Apr 16 17:12:48 2014 -0400

See the benchmark at https://github.com/rurban/Cpanel-JSON-XS/commit/585a5940e5f30d458bdc5c425ca1965b2cdefe6c#commitcomment-6047219 (method1 was 2x faster than method2)