Shopify / liquid-c

Liquid performance extension in C.
MIT License
119 stars 24 forks source link

store constant index in instruction #155

Closed ggmichaelgo closed 2 years ago

ggmichaelgo commented 3 years ago

What are you trying to accomplish?

Main issue: https://github.com/Shopify/liquid-c/issues/84

In order for us to implement If tag and For tag in Liquid-C, we need to be able to freely travel the instruction pointer. Currently, Liquid-C uses an instruction pointer and a constants pointer, and this PR will remove the constants pointer.

What approach did you choose and why?

Currently, the instruction row is structured like this: image

With this refactor, we will be storing the constant's index value in the instruction: image

** We need to keep our instruction to be or below 24 bit in order to store compiled Liquid template in storage services.

Performance Improvement on simple rendering

With this refactor, we are seeing a no-speed improvement with simple benchmark testing. (gist link)

main branch

Warming up --------------------------------------
       render_liquid   289.000  i/100ms
   render_liquid_pre   332.000  i/100ms
Calculating -------------------------------------
       render_liquid      2.924k (± 0.5%) i/s -     14.739k in   5.039984s
   render_liquid_pre      3.276k (± 0.7%) i/s -     16.600k in   5.067964s

PR branch

Warming up --------------------------------------
       render_liquid   297.000  i/100ms
   render_liquid_pre   334.000  i/100ms
Calculating -------------------------------------
       render_liquid      2.959k (± 0.3%) i/s -     14.850k in   5.018144s
   render_liquid_pre      3.305k (± 0.7%) i/s -     16.700k in   5.053282s

Affect on Performance

While parsing, we will be storing the constant's index value into constants_table, therefore we won't be storing duplicate values in the constants array. With this change, we are looking up and inserting value to a hashtable while vm_assembler_write_ruby_constant.

This will slightly affect our parsing time:

Before:

/home/michael/.rvm/rubies/ruby-3.0.2/bin/ruby ./performance.rb c benchmark lax

Running benchmark for 10 seconds (with 5 seconds warmup).

Warming up --------------------------------------
              parse:    10.000  i/100ms
             render:    17.000  i/100ms
     parse & render:     5.000  i/100ms
Calculating -------------------------------------
              parse:     92.906  (± 1.1%) i/s -    930.000  in  10.010951s
             render:    172.139  (± 1.2%) i/s -      1.734k in  10.074941s
     parse & render:     56.965  (± 0.0%) i/s -    570.000  in  10.006306s

Performance side-effect:

/home/michael/.rvm/rubies/ruby-3.0.2/bin/ruby ./performance.rb c benchmark lax

Running benchmark for 10 seconds (with 5 seconds warmup).

Warming up --------------------------------------
              parse:     9.000  i/100ms
             render:    17.000  i/100ms
     parse & render:     5.000  i/100ms
Calculating -------------------------------------
              parse:     87.346  (± 1.1%) i/s -    882.000  in  10.098912s
             render:    170.742  (± 1.2%) i/s -      1.717k in  10.057790s
     parse & render:     54.575  (± 0.0%) i/s -    550.000  in  10.078152s

Notes: Ops to update to use constant index over constant pointer:

TODO:

dylanahsmith commented 2 years ago

I've added @peterzhu2118 as a reviewer, since this work would ideally fit in nicely with his unmerged work on supporting serializing compiled templates. Similarly, I've added you as a reviewer for his first unmerged PR in that chain of work.