157 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| return unless ENV.key?('BENCHMARK')
 | |
| 
 | |
| require 'spec_helper'
 | |
| require 'erb'
 | |
| require 'benchmark/ips'
 | |
| 
 | |
| # This benchmarks some of the Banzai pipelines and filters.
 | |
| # They are not definitive, but can be used by a developer to
 | |
| # get a rough idea how the changing or addition of a new filter
 | |
| # will effect performance.
 | |
| #
 | |
| # Run by:
 | |
| #   BENCHMARK=1 rspec spec/benchmarks/banzai_benchmark.rb
 | |
| # or
 | |
| #   rake benchmark:banzai
 | |
| #
 | |
| # A specific filter can also be benchmarked by using the `FILTER`
 | |
| # environment variable.
 | |
| #
 | |
| #   BENCHMARK=1 FILTER=MathFilter rspec spec/benchmarks/banzai_benchmark.rb --tag specific_filter
 | |
| # or
 | |
| #   FILTER=MathFilter rake benchmark:banzai
 | |
| #
 | |
| # rubocop: disable RSpec/TopLevelDescribePath
 | |
| RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures, feature_category: :team_planning do
 | |
|   include MarkupHelper
 | |
| 
 | |
|   let_it_be(:feature)       { MarkdownFeature.new }
 | |
|   let_it_be(:project)       { feature.project }
 | |
|   let_it_be(:group)         { feature.group }
 | |
|   let_it_be(:wiki)          { feature.wiki }
 | |
|   let_it_be(:wiki_page)     { feature.wiki_page }
 | |
|   let_it_be(:markdown_text) { feature.raw_markdown }
 | |
|   let_it_be(:grafana_integration) { create(:grafana_integration, project: project) }
 | |
|   let_it_be(:default_context) do
 | |
|     {
 | |
|       project: project,
 | |
|       current_user: current_user,
 | |
|       suggestions_filter_enabled: true
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   let(:context) do
 | |
|     Banzai::Filter::AssetProxyFilter.transform_context(default_context)
 | |
|   end
 | |
| 
 | |
|   let!(:render_context) { Banzai::RenderContext.new(project, current_user) }
 | |
| 
 | |
|   before do
 | |
|     stub_application_setting(asset_proxy_enabled: true)
 | |
|     stub_application_setting(asset_proxy_secret_key: 'shared-secret')
 | |
|     stub_application_setting(asset_proxy_url: 'https://assets.example.com')
 | |
|     stub_application_setting(asset_proxy_whitelist: %w[gitlab.com *.mydomain.com])
 | |
|     stub_application_setting(plantuml_enabled: true, plantuml_url: 'http://localhost:8080')
 | |
|     stub_application_setting(kroki_enabled: true, kroki_url: 'http://localhost:8000')
 | |
| 
 | |
|     Banzai::Filter::AssetProxyFilter.initialize_settings
 | |
|   end
 | |
| 
 | |
|   context 'pipelines' do
 | |
|     it 'benchmarks several pipelines' do
 | |
|       name = 'example.jpg'
 | |
|       path = "images/#{name}"
 | |
|       blob = double(name: name, path: path, mime_type: 'image/jpeg', data: nil)
 | |
|       allow(wiki).to receive(:find_file).with(path, load_content: false).and_return(Gitlab::Git::WikiFile.new(blob))
 | |
|       allow(wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
 | |
| 
 | |
|       puts "\n--> Benchmarking Full, Wiki, and Plain pipelines\n"
 | |
| 
 | |
|       Benchmark.ips do |x|
 | |
|         x.config(time: 10, warmup: 2)
 | |
| 
 | |
|         x.report('Full pipeline') { Banzai::Pipeline::FullPipeline.call(markdown_text, context) }
 | |
|         x.report('Wiki pipeline') { Banzai::Pipeline::WikiPipeline.call(markdown_text, context.merge(wiki: wiki, page_slug: wiki_page.slug)) }
 | |
|         x.report('Plain pipeline') { Banzai::Pipeline::PlainMarkdownPipeline.call(markdown_text, context) }
 | |
| 
 | |
|         x.compare!
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   context 'filters' do
 | |
|     it 'benchmarks all filters in the FullPipeline' do
 | |
|       benchmark_pipeline_filters(:full)
 | |
|     end
 | |
| 
 | |
|     it 'benchmarks all filters in the PlainMarkdownPipeline' do
 | |
|       benchmark_pipeline_filters(:plain_markdown)
 | |
|     end
 | |
| 
 | |
|     it 'benchmarks specified filters in the FullPipeline', :specific_filter do
 | |
|       begin
 | |
|         filter = ENV['FILTER'] || 'MarkdownFilter'
 | |
|         filter_klass = "Banzai::Filter::#{filter}".constantize
 | |
|       rescue NameError
 | |
|         raise 'Incorrect filter specified. Correct example: FILTER=MathFilter'
 | |
|       end
 | |
| 
 | |
|       benchmark_pipeline_filters(:full, [filter_klass])
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # build up the source text for each filter
 | |
|   def build_filter_text(pipeline, initial_text)
 | |
|     filter_source = {}
 | |
|     input_text    = initial_text
 | |
|     result        = nil
 | |
| 
 | |
|     pipeline.filters.each do |filter_klass|
 | |
|       # store inputs for current filter_klass
 | |
|       filter_source[filter_klass] = { input_text: input_text, input_result: result }
 | |
| 
 | |
|       filter = filter_klass.new(input_text, context, result)
 | |
|       output = filter.call
 | |
| 
 | |
|       # save these for the next filter_klass
 | |
|       input_text = output
 | |
|       result = filter.result
 | |
|     end
 | |
| 
 | |
|     filter_source
 | |
|   end
 | |
| 
 | |
|   def benchmark_pipeline_filters(pipeline_type, filter_klass_list = nil)
 | |
|     pipeline      = Banzai::Pipeline[pipeline_type]
 | |
|     filter_source = build_filter_text(pipeline, markdown_text)
 | |
| 
 | |
|     filter_msg = filter_klass_list ? filter_klass_list.first.name.demodulize : 'all filters'
 | |
|     puts "\n--> Benchmarking #{filter_msg} for #{pipeline.name.demodulize}\n"
 | |
| 
 | |
|     Benchmark.ips do |x|
 | |
|       x.config(time: 10, warmup: 2)
 | |
| 
 | |
|       filters = filter_klass_list || pipeline.filters
 | |
|       filters.each do |filter_klass|
 | |
|         label = filter_klass.name.demodulize.delete_suffix('Filter').truncate(20)
 | |
| 
 | |
|         x.report(label) do
 | |
|           filter = filter_klass.new(filter_source[filter_klass][:input_text],
 | |
|                                     context,
 | |
|                                     filter_source[filter_klass][:input_result])
 | |
|           filter.call
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       x.compare!
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Fake a `current_user` helper
 | |
|   def current_user
 | |
|     feature.user
 | |
|   end
 | |
| end
 |