diff options
author | Jean Boussier <[email protected]> | 2024-10-29 11:00:16 +0100 |
---|---|---|
committer | Hiroshi SHIBATA <[email protected]> | 2024-11-01 13:04:24 +0900 |
commit | 59eebeca02325861dd16452c9b85f4920bccd84f () | |
tree | dcc4bd7fde4a87782599354843ea788870285296 /ext/json/fbuffer | |
parent | d329896fb590de96832d522b475404cae1279767 (diff) |
[ruby/json] Allocate the initial generator buffer on the stack
Ref: https://.com/ruby/json/issues/655 Followup: https://.com/ruby/json/issues/657 Assuming the generator might be used for fairly small documents we can start with a reasonable buffer size of the stack, and if we outgrow it, we can spill on the heap. In a way this is optimizing for micro-benchmarks, but there are valid use case for fiarly small JSON document in actual real world scenarios, so trashing the GC less in such case make sense. Before: ``` ruby 3.3.4 (2024-07-09 revision https://.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- Oj 518.700k i/100ms JSON reuse 483.370k i/100ms Calculating ------------------------------------- Oj 5.722M (± 1.8%) i/s (174.76 ns/i) - 29.047M in 5.077823s JSON reuse 5.278M (± 1.5%) i/s (189.46 ns/i) - 26.585M in 5.038172s Comparison: Oj: 5722283.8 i/s JSON reuse: 5278061.7 i/s - 1.08x slower ``` After: ``` ruby 3.3.4 (2024-07-09 revision https://.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- Oj 517.837k i/100ms JSON reuse 548.871k i/100ms Calculating ------------------------------------- Oj 5.693M (± 1.6%) i/s (175.65 ns/i) - 28.481M in 5.004056s JSON reuse 5.855M (± 1.2%) i/s (170.80 ns/i) - 29.639M in 5.063004s Comparison: Oj: 5692985.6 i/s JSON reuse: 5854857.9 i/s - 1.03x faster ``` https://.com/ruby/json/commit/fe607f4806
-rw-r--r-- | ext/json/fbuffer/fbuffer.h | 29 |
1 files changed, 25 insertions, 4 deletions
@@ -4,13 +4,20 @@ #include "ruby.h" #include "ruby/encoding.h" typedef struct FBufferStruct { unsigned long initial_length; - char *ptr; unsigned long len; unsigned long capa; } FBuffer; #define FBUFFER_INITIAL_LENGTH_DEFAULT 1024 #define FBUFFER_PTR(fb) ((fb)->ptr) @@ -35,14 +42,21 @@ static VALUE fbuffer_to_s(FBuffer *fb); #define RB_UNLIKELY(expr) expr #endif -static void fbuffer_init(FBuffer *fb, unsigned long initial_length) { fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT; } static void fbuffer_free(FBuffer *fb) { - if (fb->ptr) ruby_xfree(fb->ptr); } #ifndef JSON_GENERATOR @@ -65,7 +79,14 @@ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested) for (required = fb->capa; requested > required - fb->len; required <<= 1); if (required > fb->capa) { - REALLOC_N(fb->ptr, char, required); fb->capa = required; } } |