diff options
author | Robert Speicher <robert@gitlab.com> | 2017-06-12 19:23:49 +0000 |
---|---|---|
committer | Robert Speicher <robert@gitlab.com> | 2017-06-12 19:23:49 +0000 |
commit | 5a66e6d968fb9b1bd1159b9156a88bd06208e363 (patch) | |
tree | 99bd4cdca441db24dd538c6811f9d76c12d2de58 /lib | |
parent | 8d7951d879d13894dcc1fd5d845c8d844bee321a (diff) | |
parent | be0a949a004a34015977bdbcfe24e3173cd3aba9 (diff) | |
download | gitlab-ce-5a66e6d968fb9b1bd1159b9156a88bd06208e363.tar.gz |
Merge branch '29010-perf-bar' into 'master'
Add an optional performance bar to view performance metrics for the current page
Closes #29010
See merge request !11439
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gitlab/performance_bar.rb | 7 | ||||
-rw-r--r-- | lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb | 22 | ||||
-rw-r--r-- | lib/gitlab/performance_bar/peek_query_tracker.rb | 39 | ||||
-rw-r--r-- | lib/peek/rblineprof/custom_controller_helpers.rb | 96 |
4 files changed, 164 insertions, 0 deletions
diff --git a/lib/gitlab/performance_bar.rb b/lib/gitlab/performance_bar.rb new file mode 100644 index 00000000000..163a40ad306 --- /dev/null +++ b/lib/gitlab/performance_bar.rb @@ -0,0 +1,7 @@ +module Gitlab + module PerformanceBar + def self.enabled? + Feature.enabled?('gitlab_performance_bar') + end + end +end diff --git a/lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb b/lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb new file mode 100644 index 00000000000..d939a6ea18d --- /dev/null +++ b/lib/gitlab/performance_bar/peek_performance_bar_with_rack_body.rb @@ -0,0 +1,22 @@ +# This solves a bug with a X-Senfile header that wouldn't be set properly, see +# https://github.com/peek/peek-performance_bar/pull/27 +module Gitlab + module PerformanceBar + module PeekPerformanceBarWithRackBody + def call(env) + @env = env + reset_stats + + @total_requests += 1 + first_request if @total_requests == 1 + + env['process.request_start'] = @start.to_f + env['process.total_requests'] = total_requests + + status, headers, body = @app.call(env) + body = Rack::BodyProxy.new(body) { record_request } + [status, headers, body] + end + end + end +end diff --git a/lib/gitlab/performance_bar/peek_query_tracker.rb b/lib/gitlab/performance_bar/peek_query_tracker.rb new file mode 100644 index 00000000000..7ab80f5ee0f --- /dev/null +++ b/lib/gitlab/performance_bar/peek_query_tracker.rb @@ -0,0 +1,39 @@ +# Inspired by https://github.com/peek/peek-pg/blob/master/lib/peek/views/pg.rb +module Gitlab + module PerformanceBar + module PeekQueryTracker + def sorted_queries + PEEK_DB_CLIENT.query_details. + sort { |a, b| b[:duration] <=> a[:duration] } + end + + def results + super.merge(queries: sorted_queries) + end + + private + + def setup_subscribers + super + + # Reset each counter when a new request starts + before_request do + PEEK_DB_CLIENT.query_details = [] + end + + subscribe('sql.active_record') do |_, start, finish, _, data| + if RequestStore.active? && RequestStore.store[:peek_enabled] + track_query(data[:sql].strip, data[:binds], start, finish) + end + end + end + + def track_query(raw_query, bindings, start, finish) + query = Gitlab::Sherlock::Query.new(raw_query, start, finish) + query_info = { duration: '%.3f' % query.duration, sql: query.formatted_query } + + PEEK_DB_CLIENT.query_details << query_info + end + end + end +end diff --git a/lib/peek/rblineprof/custom_controller_helpers.rb b/lib/peek/rblineprof/custom_controller_helpers.rb new file mode 100644 index 00000000000..99f9c2c9b04 --- /dev/null +++ b/lib/peek/rblineprof/custom_controller_helpers.rb @@ -0,0 +1,96 @@ +module Peek + module Rblineprof + module CustomControllerHelpers + extend ActiveSupport::Concern + + # This will become useless once https://github.com/peek/peek-rblineprof/pull/5 + # is merged + def pygmentize(file_name, code, lexer = nil) + if lexer.present? + Gitlab::Highlight.highlight(file_name, code) + else + "<pre>#{Rack::Utils.escape_html(code)}</pre>" + end + end + + # rubocop:disable all + def inject_rblineprof + ret = nil + profile = lineprof(rblineprof_profiler_regex) do + ret = yield + end + + if response.content_type =~ %r|text/html| + sort = params[:lineprofiler_sort] + mode = params[:lineprofiler_mode] || 'cpu' + min = (params[:lineprofiler_min] || 5).to_i * 1000 + summary = params[:lineprofiler_summary] + + # Sort each file by the longest calculated time + per_file = profile.map do |file, lines| + total, child, excl, total_cpu, child_cpu, excl_cpu = lines[0] + + wall = summary == 'exclusive' ? excl : total + cpu = summary == 'exclusive' ? excl_cpu : total_cpu + idle = summary == 'exclusive' ? (excl - excl_cpu) : (total - total_cpu) + + [ + file, lines, + wall, cpu, idle, + sort == 'idle' ? idle : sort == 'cpu' ? cpu : wall + ] + end.sort_by{ |a,b,c,d,e,f| -f } + + output = '' + per_file.each do |file_name, lines, file_wall, file_cpu, file_idle, file_sort| + + output << "<div class='peek-rblineprof-file'><div class='heading'>" + + show_src = file_sort > min + tmpl = show_src ? "<a href='#' class='js-lineprof-file'>%s</a>" : "%s" + + if mode == 'cpu' + output << sprintf("<span class='duration'>% 8.1fms + % 8.1fms</span> #{tmpl}", file_cpu / 1000.0, file_idle / 1000.0, file_name.sub(Rails.root.to_s + '/', '')) + else + output << sprintf("<span class='duration'>% 8.1fms</span> #{tmpl}", file_wall/1000.0, file_name.sub(Rails.root.to_s + '/', '')) + end + + output << "</div>" # .heading + + next unless show_src + + output << "<div class='data'>" + code = [] + times = [] + File.readlines(file_name).each_with_index do |line, i| + code << line + wall, cpu, calls = lines[i + 1] + + if calls && calls > 0 + if mode == 'cpu' + idle = wall - cpu + times << sprintf("% 8.1fms + % 8.1fms (% 5d)", cpu / 1000.0, idle / 1000.0, calls) + else + times << sprintf("% 8.1fms (% 5d)", wall / 1000.0, calls) + end + else + times << ' ' + end + end + output << "<pre class='duration'>#{times.join("\n")}</pre>" + # The following line was changed from + # https://github.com/peek/peek-rblineprof/blob/8d3b7a283a27de2f40abda45974516693d882258/lib/peek/rblineprof/controller_helpers.rb#L125 + # This will become useless once https://github.com/peek/peek-rblineprof/pull/16 + # is merged and is implemented. + output << "<pre class='code highlight white'>#{pygmentize(file_name, code.join, 'ruby')}</pre>" + output << "</div></div>" # .data then .peek-rblineprof-file + end + + response.body += "<div class='peek-rblineprof-modal' id='line-profile'>#{output}</div>".html_safe + end + + ret + end + end + end +end |