From a93eac02689488d73996a03f3432017df202c342 Mon Sep 17 00:00:00 2001 From: Jerry Liu Date: Tue, 17 Jan 2017 15:37:16 -0500 Subject: [PATCH] Introduce new benchmarking methods to liquid to use on rubybench --- performance/benchmark.rb | 5 +- performance/theme_runner.rb | 99 +++++++++++++++++++++++++++---------- 2 files changed, 76 insertions(+), 28 deletions(-) diff --git a/performance/benchmark.rb b/performance/benchmark.rb index a6f8185..68c568c 100644 --- a/performance/benchmark.rb +++ b/performance/benchmark.rb @@ -5,7 +5,7 @@ Liquid::Template.error_mode = ARGV.first.to_sym if ARGV.first profiler = ThemeRunner.new Benchmark.ips do |x| - x.time = 60 + x.time = 10 x.warmup = 5 puts @@ -13,5 +13,6 @@ Benchmark.ips do |x| puts x.report("parse:") { profiler.compile } - x.report("parse & run:") { profiler.run } + x.report("render:") { profiler.render } + x.report("parse & render:") { profiler.run } end diff --git a/performance/theme_runner.rb b/performance/theme_runner.rb index 6ac7917..9f6a1fc 100644 --- a/performance/theme_runner.rb +++ b/performance/theme_runner.rb @@ -21,53 +21,100 @@ class ThemeRunner end end - # Load all templates into memory, do this now so that - # we don't profile IO. + # Initialize a new liquid ThemeRunner instance + # Will load all templates into memory, do this now so that we don't profile IO. def initialize @tests = Dir[__dir__ + '/tests/**/*.liquid'].collect do |test| next if File.basename(test) == 'theme.liquid' theme_path = File.dirname(test) + '/theme.liquid' - - [File.read(test), (File.file?(theme_path) ? File.read(theme_path) : nil), test] + { + liquid: File.read(test), + layout: (File.file?(theme_path) ? File.read(theme_path) : nil), + template_name: test + } end.compact + + compile_all_tests end + # `compile` will test just the compilation portion of liquid without any templates def compile - # Dup assigns because will make some changes to them - - @tests.each do |liquid, layout, template_name| - tmpl = Liquid::Template.new - tmpl.parse(liquid) - tmpl = Liquid::Template.new - tmpl.parse(layout) + @tests.each do |test_hash| + Liquid::Template.new.parse(test_hash[:liquid]) + Liquid::Template.new.parse(test_hash[:layout]) end end + # `run` is called to benchmark rendering and compiling at the same time def run - # Dup assigns because will make some changes to them - assigns = Database.tables.dup - - @tests.each do |liquid, layout, template_name| - # Compute page_tempalte outside of profiler run, uninteresting to profiler - page_template = File.basename(template_name, File.extname(template_name)) + each_test do |liquid, layout, assigns, page_template, template_name| compile_and_render(liquid, layout, assigns, page_template, template_name) end end + # `render` is called to benchmark just the render portion of liquid + def render + @compiled_tests.each do |test| + tmpl = test[:tmpl] + assigns = test[:assigns] + layout = test[:layout] + + if layout + assigns['content_for_layout'] = tmpl.render!(assigns) + layout.render!(assigns) + else + tmpl.render!(assigns) + end + end + end + + private + def compile_and_render(template, layout, assigns, page_template, template_file) + compiled_test = compile_test(template, layout, assigns, page_template, template_file) + assigns['content_for_layout'] = compiled_test[:tmpl].render!(assigns) + compiled_test[:layout].render!(assigns) if layout + end + + def compile_all_tests + @compiled_tests = [] + each_test do |liquid, layout, assigns, page_template, template_name| + @compiled_tests << compile_test(liquid, layout, assigns, page_template, template_name) + end + @compiled_tests + end + + def compile_test(template, layout, assigns, page_template, template_file) + tmpl = init_template(page_template, template_file) + parsed_template = tmpl.parse(template).dup + + if layout + parsed_layout = tmpl.parse(layout) + { tmpl: parsed_template, assigns: assigns, layout: parsed_layout } + else + { tmpl: parsed_template, assigns: assigns } + end + end + + # utility method with similar functionality needed in `compile_all_tests` and `run` + def each_test + # Dup assigns because will make some changes to them + assigns = Database.tables.dup + + @tests.each do |test_hash| + # Compute page_template outside of profiler run, uninteresting to profiler + page_template = File.basename(test_hash[:template_name], File.extname(test_hash[:template_name])) + yield(test_hash[:liquid], test_hash[:layout], assigns, page_template, test_hash[:template_name]) + end + end + + # set up a new Liquid::Template object for use in `compile_and_render` and `compile_test` + def init_template(page_template, template_file) tmpl = Liquid::Template.new tmpl.assigns['page_title'] = 'Page title' tmpl.assigns['template'] = page_template tmpl.registers[:file_system] = ThemeRunner::FileSystem.new(File.dirname(template_file)) - - content_for_layout = tmpl.parse(template).render!(assigns) - - if layout - assigns['content_for_layout'] = content_for_layout - tmpl.parse(layout).render!(assigns) - else - content_for_layout - end + tmpl end end