This is an automated email from the ASF dual-hosted git repository.

nickva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb-jiffy.git

commit c77f342ab89182c06a4bfe064fa3d365d7d26bd5
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Wed Apr 15 23:12:57 2026 -0400

    Use branch predictors for encoding
    
    Branch predictors are compiler hints to structure the code such that some 
code
    is more/less likely to be speculatively executed. This is a technique I 
noticed
    in QuickJS code and figured it's worth trying here. This turns out to help 
in
    encoding more than decoding. I guess encoding is more "branchy".
    
    The improvements are not huge, just a few percentage points, but they are
    consistent for the majority of encoding benchmarks and with both GCC 
(Debian)
    and Clang (MacOS) compilers:
    
    Sample of results from Debian 13/GCC
    
    ```
    ===== With input Encode Pokedex =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        1.87 K      535.83 us    +/-10.10%      
541.35 us      674.64 us
    jiffy (master)                  1.70 K      589.32 us    +/-11.87%      
579.90 us      783.70 us
    Comparison:
    jiffy (branch-predictor)        1.87 K
    jiffy (master)                  1.70 K - 1.10x slower +53.49 us
    ===== With input Encode Semanticscholar Corpus =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (master)                   20.13       49.68 ms     +/-4.94%       
49.70 ms       58.81 ms
    jiffy (branch-predictor)         19.37       51.64 ms    +/-11.48%       
50.40 ms       62.91 ms
    Comparison:
    jiffy (master)                   20.13
    jiffy (branch-predictor)         19.37 - 1.04x slower +1.95 ms
    ===== With input Encode Twitter =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        272.86        3.66 ms    +/-14.99%        
3.55 ms        5.15 ms
    jiffy (master)                  252.14        3.97 ms    +/-14.50%        
3.83 ms        5.18 ms
    Comparison:
    jiffy (branch-predictor)        272.86
    jiffy (master)                  252.14 - 1.08x slower +0.30 ms
    ===== With input Encode UTF-8 escaped =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        8.88 K      112.59 us     +/-0.76%      
112.45 us      115.26 us
    jiffy (master)                  8.44 K      118.48 us     +/-1.41%      
118.07 us      124.21 us
    Comparison:
    jiffy (branch-predictor)        8.88 K
    jiffy (master)                  8.44 K - 1.05x slower +5.89 us
    ===== With input Encode UTF-8 unescaped =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        8.87 K      112.73 us     +/-0.72%      
112.58 us      115.29 us
    jiffy (master)                  8.48 K      117.87 us     +/-0.67%      
117.84 us      120.02 us
    Comparison:
    jiffy (branch-predictor)        8.87 K
    jiffy (master)                  8.48 K - 1.05x slower +5.14 us
    ```
    
    Sample of results from MacOS (Clang)
    
    ```
    ===== With input Encode Pokedex =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        1.81 K      551.89 us    +/-11.53%      
545.92 us      734.93 us
    jiffy (master)                  1.70 K      587.50 us    +/-11.49%      
580.93 us      779.05 us
    Comparison:
    jiffy (branch-predictor)        1.81 K
    jiffy (master)                  1.70 K - 1.06x slower +35.61 us
    ===== With input Encode Semanticscholar Corpus =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (master)                   19.34       51.70 ms     +/-9.42%       
50.46 ms       64.43 ms
    jiffy (branch-predictor)         19.33       51.73 ms    +/-12.60%       
50.31 ms       71.43 ms
    Comparison:
    jiffy (master)                   19.34
    jiffy (branch-predictor)         19.33 - 1.00x slower +0.0301 ms
    ===== With input Encode Twitter =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        274.06        3.65 ms    +/-14.39%        
3.52 ms        4.81 ms
    jiffy (master)                  256.28        3.90 ms    +/-14.25%        
3.78 ms        5.11 ms
    Comparison:
    jiffy (branch-predictor)        274.06
    jiffy (master)                  256.28 - 1.07x slower +0.25 ms
    ===== With input Encode UTF-8 escaped =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        8.89 K      112.47 us     +/-0.77%      
112.32 us      115.13 us
    jiffy (master)                  8.47 K      118.05 us     +/-0.79%      
118.02 us      120.57 us
    Comparison:
    jiffy (branch-predictor)        8.89 K
    jiffy (master)                  8.47 K - 1.05x slower +5.58 us
    ===== With input Encode UTF-8 unescaped =====
    Name                               ips        average  deviation         
median         99th %
    jiffy (branch-predictor)        8.86 K      112.90 us     +/-0.90%      
112.67 us      116.13 us
    jiffy (master)                  8.48 K      117.95 us     +/-0.72%      
117.92 us      120.21 us
    Comparison:
    jiffy (branch-predictor)        8.86 K
    jiffy (master)                  8.48 K - 1.04x slower +5.05 us
    ```
---
 c_src/encoder.c | 16 ++++++++--------
 c_src/jiffy.h   |  9 +++++++++
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/c_src/encoder.c b/c_src/encoder.c
index 310ebe2..a2a0108 100644
--- a/c_src/encoder.c
+++ b/c_src/encoder.c
@@ -261,12 +261,12 @@ enc_ensure(Encoder* e, size_t req)
 {
     size_t new_size = BIN_INC_SIZE;
 
-    if(e->have_buffer) {
-        if(req < (e->buffer.size - e->i)) {
+    if(JIFFY_LIKELY(e->have_buffer)) {
+        if(JIFFY_LIKELY(req < (e->buffer.size - e->i))) {
             return 1;
         }
 
-        if(!enc_flush(e)) {
+        if(JIFFY_UNLIKELY(!enc_flush(e))) {
             return 0;
         }
 
@@ -390,9 +390,9 @@ enc_atom(Encoder* e, ERL_NIF_TERM val)
             return 0;
         }
 
-        if(enc_special_character(e, data[i])) {
+        if(JIFFY_UNLIKELY(enc_special_character(e, data[i]))) {
             i++;
-        } else if(data[i] < 0x80) {
+        } else if(JIFFY_LIKELY(data[i] < 0x80)) {
             // Scan ahead for plain ASCII chars which don't need escaping.
             // Since optionally users could escape forward slashes, too, we
             // stop on them as well
@@ -511,12 +511,12 @@ enc_string(Encoder* e, ERL_NIF_TERM val)
             }
             memcpy(&(e->p[e->i]), &data[start], run);
             e->i += run;
-        } else if(data[i] >= 0x80) {
+        } else if(JIFFY_UNLIKELY(data[i] >= 0x80)) {
             ulen = utf8_validate(&(data[i]), size - i);
 
-            if (ulen == 0) {
+            if (JIFFY_UNLIKELY(ulen == 0)) {
                 return 0;
-            } else if (e->uescape) {
+            } else if (JIFFY_UNLIKELY(e->uescape)) {
                 uval = utf8_to_unicode(&(data[i]), size-i);
                 if(uval < 0) {
                     return 0;
diff --git a/c_src/jiffy.h b/c_src/jiffy.h
index 252d2fc..082b62c 100644
--- a/c_src/jiffy.h
+++ b/c_src/jiffy.h
@@ -23,6 +23,15 @@
   #define inline __inline
 #endif
 
+// These are to help the branch predictor
+#if defined(__GNUC__) || defined(__clang__)
+  #define JIFFY_LIKELY(x)   __builtin_expect(!!(x), 1)
+  #define JIFFY_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+  #define JIFFY_LIKELY(x)   (x)
+  #define JIFFY_UNLIKELY(x) (x)
+#endif
+
 typedef struct {
     ERL_NIF_TERM    atom_ok;
     ERL_NIF_TERM    atom_error;

Reply via email to