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