yeptris 0.1.13.1 → 0.1.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17b1311c9327a9986b7bb89f3731fd40ca040c49336fdb97596951fbf87ed1c0
4
- data.tar.gz: 6c1b2f707d15d469963ffc0ee030fc90287a5e01954d7431996f24765bddf9e3
3
+ metadata.gz: 288c8f3951e7cd252310e271ed666996442d66d90f04fbdefc8fde57fc122826
4
+ data.tar.gz: d52fb5127d673914f553b47449dbf2b57b2d1b581c5e0636c40c5faf99141222
5
5
  SHA512:
6
- metadata.gz: b04ca9a9d899c00207d8cf09ab1d1aa071c1cc63f2adab17cf87453d0a0646fc84c9df9f3e80f245bbc977a32e67feb7f25e2b562293a59adc102764b80507dc
7
- data.tar.gz: 25c9033573e619dc69924f4ae15c102b650efdbf7d39c1dcc4d3d73243d1d0ac3037750c7b28b5e6d28562175296fd4b125e39253f4ab9c9ed799529d7fcb4ee
6
+ metadata.gz: fc3a2f57041c9f28ec5133a98cf8573cfd820f9451d321ae6d333e507b1f2b9d7ce51814a0380eadee799904e056d013eea70142ebb6031d9c7480762f91634c
7
+ data.tar.gz: a6f0f5990a19597c1ac060e0dbb5abe2c921cdbdc2e49ec1fe70d04bfa91609c36c7b114e0d4e294e1175613a710fab722b1e524f6a1e5cd73f0340fbc2ead31
data/README.adoc CHANGED
@@ -72,9 +72,9 @@ fastest first:
72
72
  +
73
73
  ....
74
74
  CI referee (gated at 1.05 on both platforms, order-alternating
75
- interleave, N=200):
76
- ubuntu (x86_64, gc=disable) mean 0.961x vs JSON.parse
77
- macos (arm64, gc=none) mean 0.718x (head-to-head 173/200)
75
+ interleave, N=200; prefix-hashed token cache):
76
+ ubuntu (x86_64) mean 0.745x vs JSON.parse, 200/200 head-to-head
77
+ macos (arm64) mean 0.759x vs JSON.parse, 169/200 head-to-head
78
78
  ....
79
79
 
80
80
  The parse-window GC strategy is per-arch and runtime-switchable:
@@ -5,6 +5,7 @@
5
5
  #include <stdlib.h>
6
6
  #include <string.h>
7
7
  #include "parse/scalars.h"
8
+ #include <yeptris/visit.h>
8
9
  #include "scan/json.h"
9
10
 
10
11
  #define YEP_JR_MAX 1000
@@ -38,15 +39,26 @@ static void jr_ws(jr* j) {
38
39
  }
39
40
  }
40
41
 
42
+ /* Token-cache knob (TODO.restructure/37): off = fresh strings
43
+ * everywhere (JSON.parse's shape: every key pays its own aset
44
+ * hashing); on = interned keys/tokens (shared frozen VALUEs
45
+ * memoize their hash). The CI referee A/Bs the net sign per arch. */
46
+ enum { YEP_CACHE_ON = 0, YEP_CACHE_OFF = 1 };
47
+ static int yep_cache_mode = YEP_CACHE_ON;
48
+
41
49
  static uint64_t jr_hash(const char* sp, long sl) {
42
- /* FNV-1a 64 cheap, good enough for short keys */
43
- uint64_t h = 14695981039346656037ull;
44
- for (long i = 0; i < sl; i++) {
45
- h ^= (unsigned char)sp[i];
46
- h *= 1099511628211ull;
47
- }
48
- h ^= (uint64_t)sl;
49
- return h;
50
+ /* 8-byte-prefix key (the leptris nametab trick): one safe load
51
+ * of min(8, len) bytes + a multiply mix. Replaced byte-wise FNV
52
+ * (~15-20ns per token on the cached path, ~15k tokens per
53
+ * reference-corpus parse - the x86 materialization cost the
54
+ * decomposition isolated, TODO.restructure/37/38). */
55
+ uint64_t k = 0;
56
+ uint64_t take = (uint64_t)sl < 8 ? (uint64_t)sl : 8;
57
+ memcpy(&k, sp, (size_t)take);
58
+ k ^= (uint64_t)sl * 0x9E3779B97F4A7C15ull;
59
+ k *= 0xC2B2AE3D27D4EB4Full;
60
+ k ^= k >> 29;
61
+ return k;
50
62
  }
51
63
 
52
64
  static VALUE jr_cached(jr* j, const char* sp, long sl) {
@@ -86,7 +98,7 @@ static VALUE jr_str(jr* j, int as_key) {
86
98
  sp = j->p + start + 1;
87
99
  sl = (long)(close - start - 1);
88
100
  }
89
- if (as_key || sl <= 24) return jr_cached(j, sp, sl);
101
+ if (yep_cache_mode == YEP_CACHE_ON && (as_key || sl <= 24)) return jr_cached(j, sp, sl);
90
102
  return rb_enc_str_new(sp, sl, j->enc);
91
103
  }
92
104
 
@@ -244,6 +256,10 @@ static int yep_gc_mode = YEP_GC_DEFAULT;
244
256
 
245
257
  int yep_rb_gc_mode(void) { return yep_gc_mode; }
246
258
  int yep_rb_ins_mode(void) { return yep_ins_mode; }
259
+ int yep_rb_cache_mode(void) { return yep_cache_mode; }
260
+ void yep_rb_set_cache_mode(int mode) {
261
+ if (mode == YEP_CACHE_ON || mode == YEP_CACHE_OFF) yep_cache_mode = mode;
262
+ }
247
263
  void yep_rb_set_ins_mode(int mode) {
248
264
  if (mode == YEP_INS_BULK || mode == YEP_INS_ASET) yep_ins_mode = mode;
249
265
  }
@@ -253,6 +269,21 @@ void yep_rb_set_gc_mode(int mode) {
253
269
  }
254
270
  }
255
271
 
272
+ /* Pure grammar walk, no materialization (TODO.restructure/37): the
273
+ * same scan kernels through the null vtable. Decomposes scan vs
274
+ * materialize cost. Returns seconds for n iterations. */
275
+ #include <time.h>
276
+ double yep_rb_scan_time(const char* p, size_t len, int n) {
277
+ static const YeptrisVisitVTable none = {0};
278
+ struct timespec t0, t1;
279
+ clock_gettime(CLOCK_MONOTONIC, &t0);
280
+ for (int i = 0; i < n; i++) {
281
+ (void)yeptris_visit_json(p, len, &none, NULL);
282
+ }
283
+ clock_gettime(CLOCK_MONOTONIC, &t1);
284
+ return (double)(t1.tv_sec - t0.tv_sec) + (double)(t1.tv_nsec - t0.tv_nsec) / 1e9;
285
+ }
286
+
256
287
  VALUE yep_rb_parse_json(const char* p, size_t len) {
257
288
  jr j;
258
289
  memset(&j, 0, sizeof(j));
@@ -329,6 +329,9 @@ extern int yep_rb_gc_mode(void);
329
329
  extern void yep_rb_set_gc_mode(int mode);
330
330
  extern int yep_rb_ins_mode(void);
331
331
  extern void yep_rb_set_ins_mode(int mode);
332
+ extern int yep_rb_cache_mode(void);
333
+ extern void yep_rb_set_cache_mode(int mode);
334
+ extern double yep_rb_scan_time(const char* p, size_t len, int n);
332
335
 
333
336
  static VALUE native_gc_mode(VALUE self) {
334
337
  (void)self;
@@ -354,6 +357,29 @@ static VALUE native_ins_mode_set(VALUE self, VALUE mode) {
354
357
  return mode;
355
358
  }
356
359
 
360
+ static VALUE native_cache_mode(VALUE self) {
361
+ (void)self;
362
+ return yep_rb_cache_mode() == 1 ? ID2SYM(rb_intern("off")) : ID2SYM(rb_intern("on"));
363
+ }
364
+
365
+ static VALUE native_cache_mode_set(VALUE self, VALUE mode) {
366
+ (void)self;
367
+ Check_Type(mode, T_SYMBOL);
368
+ ID id = rb_sym2id(mode);
369
+ if (id == rb_intern("on")) yep_rb_set_cache_mode(0);
370
+ else if (id == rb_intern("off")) yep_rb_set_cache_mode(1);
371
+ else rb_raise(rb_eArgError, "cache_mode must be :on or :off");
372
+ return mode;
373
+ }
374
+
375
+ static VALUE native_scan_time(VALUE self, VALUE input, VALUE count) {
376
+ (void)self;
377
+ StringValue(input);
378
+ int n = NUM2INT(count);
379
+ double secs = yep_rb_scan_time(RSTRING_PTR(input), (size_t)RSTRING_LEN(input), n);
380
+ return DBL2NUM(secs / (double)n);
381
+ }
382
+
357
383
  static VALUE native_gc_mode_set(VALUE self, VALUE mode) {
358
384
  (void)self;
359
385
  Check_Type(mode, T_SYMBOL);
@@ -376,6 +402,9 @@ RUBY_FUNC_EXPORTED void Init_native(void) {
376
402
  rb_define_singleton_method(mNat, "gc_mode=", native_gc_mode_set, 1);
377
403
  rb_define_singleton_method(mNat, "ins_mode", native_ins_mode, 0);
378
404
  rb_define_singleton_method(mNat, "ins_mode=", native_ins_mode_set, 1);
405
+ rb_define_singleton_method(mNat, "cache_mode", native_cache_mode, 0);
406
+ rb_define_singleton_method(mNat, "cache_mode=", native_cache_mode_set, 1);
407
+ rb_define_singleton_method(mNat, "scan_time", native_scan_time, 2);
379
408
  rb_define_const(mNat, "AVAILABLE", Qtrue);
380
409
  const char* env = getenv("YEPTRIS_NATIVE_GC");
381
410
  if (env != NULL && strcmp(env, "none") == 0) yep_rb_set_gc_mode(1);
@@ -383,4 +412,6 @@ RUBY_FUNC_EXPORTED void Init_native(void) {
383
412
  else if (env != NULL && strcmp(env, "disable") == 0) yep_rb_set_gc_mode(0);
384
413
  const char* ins = getenv("YEPTRIS_NATIVE_INSERT");
385
414
  if (ins != NULL && strcmp(ins, "aset") == 0) yep_rb_set_ins_mode(1);
415
+ const char* cache = getenv("YEPTRIS_NATIVE_CACHE");
416
+ if (cache != NULL && strcmp(cache, "off") == 0) yep_rb_set_cache_mode(1);
386
417
  }
data/lib/yeptris.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Yeptris
4
4
  # The gem's version lives in the parent namespace's file — the last
5
5
  # internal require (yeptris/version) retired with it.
6
- VERSION = "0.1.13.1".freeze
6
+ VERSION = "0.1.13.2".freeze
7
7
  # The error hierarchy lives in THIS file (the parent namespace's
8
8
  # own file): nested constants do not trigger a parent-constant
9
9
  # autoload, and the law forbids internal requires — defining the
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yeptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13.1
4
+ version: 0.1.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.