[Groonga-commit] groonga/groonga [master] [query-log][analyzer] reduce memory usage.

アーカイブの一覧に戻る

null+****@clear***** null+****@clear*****
2011年 6月 10日 (金) 10:55:19 JST


Kouhei Sutou	2011-06-10 01:55:19 +0000 (Fri, 10 Jun 2011)

  New Revision: 00cad33851156daf9ba83d21d7e45123bb753405

  Log:
    [query-log][analyzer] reduce memory usage.

  Modified files:
    tools/groonga-query-log-analyzer.rb

  Modified: tools/groonga-query-log-analyzer.rb (+92 -42)
===================================================================
--- tools/groonga-query-log-analyzer.rb    2011-06-10 01:08:10 +0000 (0e44835)
+++ tools/groonga-query-log-analyzer.rb    2011-06-10 01:55:19 +0000 (d3d7b3e)
@@ -52,8 +52,8 @@ class GroongaQueryLogAnaylzer
     @options[:order] = "-elapsed"
     @options[:color] = :auto
     @options[:output] = "-"
-    @options[:slow_operation_threshold] = 0.05
-    @options[:slow_response_threshold] = 0.1
+    @options[:slow_operation_threshold] = 0.1
+    @options[:slow_response_threshold] = 0.2
     @options[:reporter] = "console"
     @options[:dynamic_sort] = true
     @options[:stream] = false
@@ -361,20 +361,80 @@ class GroongaQueryLogAnaylzer
     end
   end
 
+  class SizedGroupedOperations < Array
+    def initialize
+      @max_size = 10
+      @sorter = create_sorter
+    end
+
+    def apply_options(options)
+      @max_size = options[:n_entries]
+    end
+
+    def each
+      i = 0
+      super do |grouped_operation|
+        break if i >= @max_size
+        i += 1
+        yield(grouped_operation)
+      end
+    end
+
+    def <<(operation)
+      each do |grouped_operation|
+        if grouped_operation[:name] == operation[:name] and
+            grouped_operation[:context] == operation[:context]
+          elapsed = operation[:relative_elapsed_in_seconds]
+          grouped_operation[:total_elapsed] += elapsed
+          grouped_operation[:n_operations] += 1
+          return self
+        end
+      end
+
+      grouped_operation = {
+        :name => operation[:name],
+        :context => operation[:context],
+        :n_operations => 1,
+        :total_elapsed => operation[:relative_elapsed_in_seconds],
+      }
+      buffer_size = @max_size * 100
+      if size < buffer_size
+        super(grouped_operation)
+        sort_by!(&@sorter)
+      else
+        if****@sorte*****(grouped_operation) < @sorter.call(last)
+          super(grouped_operation)
+          sort_by!(&@sorter)
+          pop
+        end
+      end
+      self
+    end
+
+    private
+    def create_sorter
+      lambda do |grouped_operation|
+        -grouped_operation[:total_elapsed]
+      end
+    end
+  end
+
   class SizedStatistics < Array
-    attr_reader :n_responses, :slow_operations, :slow_responses, :total_elapsed
+    attr_reader :n_responses, :n_slow_responses, :n_slow_operations
+    attr_reader :slow_operations, :total_elapsed
     attr_reader :start_time, :last_time
     attr_accessor :slow_operation_threshold, :slow_response_threshold
     def initialize
       @max_size = 10
       self.order = "-elapsed"
-      @slow_operation_threshold = 0.05
-      @slow_response_threshold = 0.1
+      @slow_operation_threshold = 0.1
+      @slow_response_threshold = 0.2
       @start_time = nil
       @last_time = nil
       @n_responses = 0
-      @slow_operations = []
-      @slow_responses = []
+      @n_slow_responses = 0
+      @n_slow_operations = 0
+      @slow_operations = SizedGroupedOperations.new
       @total_elapsed = 0
       @collect_slow_statistics = true
     end
@@ -390,13 +450,12 @@ class GroongaQueryLogAnaylzer
       @slow_operation_threshold = options[:slow_operation_threshold]
       @slow_response_threshold = options[:slow_response_threshold]
       @collect_slow_statistics = options[:report_summary]
+      @slow_operations.apply_options(options)
     end
 
     def <<(statistic)
       update_statistic(statistic)
-      if size < @max_size - 1
-        super(statistic)
-      elsif size == @max_size - 1
+      if size < @max_size
         super(statistic)
         sort_by!(&@sorter)
       else
@@ -425,7 +484,7 @@ class GroongaQueryLogAnaylzer
     end
 
     def slow_response_ratio
-      (@slow_responses.size.to_f / @n_responses) * 100
+      (@n_slow_responses.to_f / @n_responses) * 100
     end
 
     def period
@@ -467,12 +526,13 @@ class GroongaQueryLogAnaylzer
       @total_elapsed += statistic.elapsed_in_seconds
       return unless @collect_slow_statistics
       if slow?(statistic)
-        @slow_responses << statistic
+        @n_slow_responses += 1
         if statistic.select_command?
           statistic.each_operation do |operation|
-            if operation[:relative_elapsed_in_seconds] >= @slow_operation_threshold
-              @slow_operations << operation
-            end
+            relative_elapsed_in_seconds = operation[:relative_elapsed_in_seconds]
+            next unless relative_elapsed_in_seconds >= @slow_operation_threshold
+            @n_slow_operations += 1
+            @slow_operations << operation
           end
         end
       end
@@ -766,7 +826,7 @@ class GroongaQueryLogAnaylzer
     def report_summary
       @output.puts("Summary:")
       @output.puts("  # of responses      : #{@statistics.n_responses}")
-      @output.puts("  # of slow responses : #{@statistics.slow_responses.size}")
+      @output.puts("  # of slow responses : #{@statistics.n_slow_responses}")
       @output.puts("  responses/sec       : #{@statistics.responses_per_second}")
       @output.puts("  start time          : #{@statistics.start_time.iso8601}")
       @output.puts("  last time           : #{@statistics.last_time.iso8601}")
@@ -779,34 +839,24 @@ class GroongaQueryLogAnaylzer
 
     def report_slow_operations
       @output.puts("  Slow Operations:")
-      grouped_operations =****@stati*****_operations.group_by do |operation|
-        operation[:context]
-      end
-      operation_statistics = grouped_operations.collect do |context, operations|
-        total_elapsed = operations.inject(0) do |previous, operation|
-          previous + operation[:relative_elapsed_in_seconds]
-        end
-        {
-          :total_elapsed => total_elapsed,
-          :n_operations => operations.size,
-          :represent_operation => operations.first
-        }
-      end
-      sorted_operation_statistics = operation_statistics.sort_by do |operation_statistic|
-        -operation_statistic[:total_elapsed]
-      end
-
-      sorted_operation_statistics.each do |operation_statistics|
-        total_elapsed = operation_statistics[:total_elapsed]
-        n_operations = operation_statistics[:n_operations]
-        operation = operation_statistics[:represent_operation]
-        parameters = [total_elapsed,
+      total_elapsed_digit = nil
+      total_elapsed_decimal_digit = 6
+      n_operations_digit = nil
+      @statistics.slow_operations.each do |grouped_operation|
+        total_elapsed = grouped_operation[:total_elapsed]
+        total_elapsed_digit ||= Math.log10(total_elapsed).truncate + 1
+        n_operations = grouped_operation[:n_operations]
+        n_operations_digit ||= Math.log10(n_operations).truncate + 1
+        parameters = [total_elapsed_digit + 1 + total_elapsed_decimal_digit,
+                      total_elapsed_decimal_digit,
+                      total_elapsed,
                       total_elapsed / @statistics.total_elapsed * 100,
+                      n_operations_digit,
                       n_operations,
-                      n_operations / @statistics.slow_operations.size.to_f * 100,
-                      operation[:name],
-                      operation[:context]]
-        @output.puts("    [%10.6f](%5.2f%%) [%3d](%5.2f%%) %9s: %s" % parameters)
+                      n_operations / @statistics.n_slow_operations.to_f * 100,
+                      grouped_operation[:name],
+                      grouped_operation[:context]]
+        @output.puts("    [%*.*f](%5.2f%%) [%*d](%5.2f%%) %9s: %s" % parameters)
       end
     end
 




Groonga-commit メーリングリストの案内
アーカイブの一覧に戻る