BigW Consortium Gitlab

Improve performance of SyntaxHighlightFilter

By using Rouge::Lexer.find instead of find_fancy() and memoizing the HTML formatter we can speed up the highlighting process by between 1.7 and 1.8 times (at least when measured using synthetic benchmarks). To measure this I used the following benchmark: require 'benchmark/ips' input = '' Dir['./app/controllers/**/*.rb'].each do |controller| input << <<-EOF <pre><code class="ruby">#{File.read(controller).strip}</code></pre> EOF end document = Nokogiri::HTML.fragment(input) filter = Banzai::Filter::SyntaxHighlightFilter.new(document) puts "Input size: #{(input.bytesize.to_f / 1024).round(2)} KB" Benchmark.ips do |bench| bench.report 'call' do filter.call end end This benchmark produces 250 KB of input. Before these changes the timing output would be as follows: Calculating ------------------------------------- call 1.000 i/100ms ------------------------------------------------- call 22.439 (±35.7%) i/s - 93.000 After these changes the output instead is as follows: Calculating ------------------------------------- call 1.000 i/100ms ------------------------------------------------- call 41.283 (±38.8%) i/s - 148.000 Note that due to the fairly high standard deviation and this being a synthetic benchmark it's entirely possible the real-world improvements are smaller.
parent 73772eca
...@@ -15,6 +15,7 @@ v 8.11.0 (unreleased) ...@@ -15,6 +15,7 @@ v 8.11.0 (unreleased)
- Limit git rev-list output count to one in forced push check - Limit git rev-list output count to one in forced push check
- Clean up unused routes (Josef Strzibny) - Clean up unused routes (Josef Strzibny)
- Add green outline to New Branch button. !5447 (winniehell) - Add green outline to New Branch button. !5447 (winniehell)
- Improve performance of syntax highlighting Markdown code blocks
- Update to gitlab_git 10.4.1 and take advantage of preserved Ref objects - Update to gitlab_git 10.4.1 and take advantage of preserved Ref objects
- Retrieve rendered HTML from cache in one request - Retrieve rendered HTML from cache in one request
- Fix renaming repository when name contains invalid chararacters under project settings - Fix renaming repository when name contains invalid chararacters under project settings
......
...@@ -18,14 +18,11 @@ module Banzai ...@@ -18,14 +18,11 @@ module Banzai
def highlight_node(node) def highlight_node(node)
language = node.attr('class') language = node.attr('class')
code = node.text code = node.text
css_classes = "code highlight" css_classes = "code highlight"
lexer = lexer_for(language)
lexer = Rouge::Lexer.find_fancy(language) || Rouge::Lexers::PlainText
formatter = Rouge::Formatters::HTML.new
begin begin
code = formatter.format(lexer.lex(code)) code = format(lex(lexer, code))
css_classes << " js-syntax-highlight #{lexer.tag}" css_classes << " js-syntax-highlight #{lexer.tag}"
rescue rescue
...@@ -41,14 +38,27 @@ module Banzai ...@@ -41,14 +38,27 @@ module Banzai
private private
# Separate method so it can be instrumented.
def lex(lexer, code)
lexer.lex(code)
end
def format(tokens)
rouge_formatter.format(tokens)
end
def lexer_for(language)
(Rouge::Lexer.find(language) || Rouge::Lexers::PlainText).new
end
def replace_parent_pre_element(node, highlighted) def replace_parent_pre_element(node, highlighted)
# Replace the parent `pre` element with the entire highlighted block # Replace the parent `pre` element with the entire highlighted block
node.parent.replace(highlighted) node.parent.replace(highlighted)
end end
# Override Rouge::Plugins::Redcarpet#rouge_formatter # Override Rouge::Plugins::Redcarpet#rouge_formatter
def rouge_formatter(lexer) def rouge_formatter(lexer = nil)
Rouge::Formatters::HTML.new @rouge_formatter ||= Rouge::Formatters::HTML.new
end end
end end
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment