[Groonga-commit] groonga/groonga-query-log at 7ff1d80 [master] Add memory leak detector

Back to archive index

Kouhei Sutou null+****@clear*****
Fri Sep 20 11:32:45 JST 2013


Kouhei Sutou	2013-09-20 11:32:45 +0900 (Fri, 20 Sep 2013)

  New Revision: 7ff1d8067b426341c2a73be08d3a8f62f26898f3
  https://github.com/groonga/groonga-query-log/commit/7ff1d8067b426341c2a73be08d3a8f62f26898f3

  Message:
    Add memory leak detector
    
    It isn't ran yet!

  Added files:
    bin/groonga-query-log-detect-memory-leak
    lib/groonga/query-log/command/detect-memory-leak.rb
    lib/groonga/query-log/memory-leak-detector.rb

  Added: bin/groonga-query-log-detect-memory-leak (+23 -0) 100755
===================================================================
--- /dev/null
+++ bin/groonga-query-log-detect-memory-leak    2013-09-20 11:32:45 +0900 (ab0a158)
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013  Kouhei Sutou <kou �� clear-code.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+require "groonga/query-log/command/detect-memory-leak"
+
+detect_memory_leak_command = Groonga::QueryLog::Command::DetectMemoryLeak.new
+detect_memory_leak_command.run(*ARGF)

  Added: lib/groonga/query-log/command/detect-memory-leak.rb (+84 -0) 100644
===================================================================
--- /dev/null
+++ lib/groonga/query-log/command/detect-memory-leak.rb    2013-09-20 11:32:45 +0900 (6906acd)
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013  Kouhei Sutou <kou �� clear-code.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+require "optparse"
+
+require "groonga/query-log/memory-leak-detector"
+
+module Groonga
+  module QueryLog
+    module Command
+      class DetectMemoryLeak
+        def initialize
+          @options = MemoryLeakDetector::Options.new
+        end
+
+        def run(*command_line)
+          input_paths = create_parser.parse(*command_line)
+          detector = MemoryLeakDetector.new(@options)
+          input_paths.each do |input_path|
+            File.open(input_path) do |input|
+              detector.detect(input)
+            end
+          end
+        end
+
+        private
+        def create_parser
+          parser = OptionParser.new
+          parser.banner += " QUERY_LOG"
+
+          parser.separator("")
+          parser.separator("Options:")
+
+          parser.on("--host=HOST",
+                    "Host name or IP address of groonga server",
+                    "[#{@options.host}]") do |host|
+            @options.host = host
+          end
+
+          parser.on("--port=PORT", Integer,
+                    "Port number of groonga server",
+                    "[#{@options.port}]") do |port|
+            @options.port = port
+          end
+
+          available_protocols = [:gqtp, :http]
+          available_protocols_label = "[#{available_protocols.join(', ')}]"
+          parser.on("--protocol=PROTOCOL", available_protocols,
+                    "Protocol of groonga server",
+                    available_protocols_label) do |protocol|
+            @options.protocol = protocol
+          end
+
+          parser.on("--pid=PID",
+                    "The PID of groonga server",
+                    "[#{@options.pid}]") do |pid|
+            @options.pid = pid
+          end
+
+          parser.on("--n-tries=N", Integer,
+                    "The number of the same request tries",
+                    "[#{@options.n_tries}]") do |n|
+            @options.n_tries = n
+          end
+        end
+      end
+    end
+  end
+end

  Added: lib/groonga/query-log/memory-leak-detector.rb (+107 -0) 100644
===================================================================
--- /dev/null
+++ lib/groonga/query-log/memory-leak-detector.rb    2013-09-20 11:32:45 +0900 (f553a40)
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013  Kouhei Sutou <kou �� clear-code.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+require "groonga/client"
+
+require "groonga/query-log/parser"
+
+module Groonga
+  module QueryLog
+    class MemoryLeakDetector
+      def initialize(options)
+        @options = options
+      end
+
+      def detect(input)
+        each_command(input) do |command|
+          @options.create_client do |client|
+            previous_memory_usage = nil
+            @options.n_tries.times do |i|
+              client.execute(command)
+              previous_memory_usage = current_memory_usage
+              current_memory_usage = memory_usage
+              next if previous_memory_usage.nil?
+              if previous_memory_usage != current_memory_usage
+                max_n_digits = [
+                  compute_n_digits(previous_memory_usage),
+                  compute_n_digits(current_memory_usage),
+                ].max
+                puts("detect a memory leak:")
+                puts("Nth try: #{i}")
+                puts("previous: %*d" % [max_n_digits, previous_memory_usage])
+                puts(" current: %*d" % [max_n_digits, current_memory_usage])
+                puts(command.original_source)
+              end
+            end
+          rescue Groonga::Client::Connection::Error
+            # TODO: add error log mechanism
+            $stderr.puts(Time.now.iso8601)
+            $stderr.puts(statistic.command.original_source)
+            $stderr.puts($!.raw_error.message)
+            $stderr.puts($!.raw_error.backtrace)
+          end
+        end
+      end
+
+      private
+      def each_command(input)
+        parser = Parser.new
+        parser.parse(input) do |statistic|
+          yield(statistic.command)
+        end
+      end
+
+      def memory_usage
+        `ps -o rss --no-header --pid #{@options.pid}`.to_i
+      end
+
+      class Options
+        attr_accessor :host
+        attr_accessor :port
+        attr_accessor :protocol
+        attr_accessor :pid
+        attr_accessor :n_tries
+        def initialize
+          @host = "127.0.0.1"
+          @port = 10041
+          @protocol = :gqtp
+          @pid = guess_groonga_server_pid
+          @n_tries = 10
+        end
+
+        def create_client(&block)
+          Groonga::Client.open(:host     => @host,
+                               :port     => @port,
+                               :protocol => @protocol,
+                               &block)
+        end
+
+        private
+        def guess_groonga_server_pid
+          # This command line works only for ps by procps.
+          pid = `ps -o pid --no-header -C groonga`.strip
+          if pid.empty?
+            nil
+          else
+            pid.to_i
+          end
+        end
+      end
+    end
+  end
+end
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index