summaryrefslogtreecommitdiff
path: root/lib/peek/rblineprof/custom_controller_helpers.rb
blob: 581cc6a37b43c57041b2b0ad37fab94fa3373136 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# frozen_string_literal: true

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 = ["<div class='modal-dialog modal-xl'><div class='modal-content'>"]
          output << "<div class='modal-header'>"
          output << "<h4>Line profiling: #{human_description(params[:lineprofiler])}</h4>"
          output << "<button class='close' type='button' data-dismiss='modal' aria-label='close'><span aria-hidden='true'>&times;</span></button>"
          output << "</div>"
          output << "<div class='modal-body'>"

          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

          output << "</div></div></div>"

          response.body += "<div class='modal' id='modal-peek-line-profile' tabindex=-1>#{output.join}</div>".html_safe
        end

        ret
      end

      private

      def human_description(lineprofiler_param)
        case lineprofiler_param
        when 'app'
          'app/ & lib/'
        when 'views'
          'app/view/'
        when 'gems'
          'vendor/gems'
        when 'all'
          'everything in Rails.root'
        when 'stdlib'
          'everything in the Ruby standard library'
        else
          'app/, config/, lib/, vendor/ & plugin/'
        end
      end
    end
  end
end