groonga-query-log 1.4.4 → 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: faeaa6fd86742d02ee7dd26056139a4cc4d267d10e5d18ae70bfb343ab946439
4
- data.tar.gz: 4288f0e864a772a278d01bfd0d818d8d7f342234c883e2945025e4a8c881935f
3
+ metadata.gz: 4bc397a48e26c377cab3315458cc8da30cb80cd7efd00bdea36595d7f6cb8bd7
4
+ data.tar.gz: 142b467fd6d1b809e4ca2c8b06c826084488dc6cf48aabc387e2dbe22edf0688
5
5
  SHA512:
6
- metadata.gz: de6b0181aa230461a7cfc90aa611587d5458aef929c8c6b85dfacb176f9052ac3ae62525ae86797338f629e330998c60712b6e7f604765cfaddeb2a0c321c648
7
- data.tar.gz: 6cdb79c3619951d64ede9dabbce9c136a19bc4b6e7bc23ecfe07c92696be633217478ee7e7dac2c3fc9fd99ab496f6001c085dc956921508fe49a98a63fc6ac3
6
+ metadata.gz: 49862f644474605b03c770c8bd88ca4469a1d234f6b13fc707147ea6ff3c1d82b3f8aa883b35e9fefc09e6c4f58b12c66e9f899a1daf96f4342cc03ffa4969fd
7
+ data.tar.gz: cd8283475cab0a4cfdd4f3d2ae6d8d5b42ecc9b09b8877185a07a660fd44819910a372cb472620e0e65444ac762ec729387c5d53dee299eba1f3dbade445b2d5
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (C) 2019 Kentaro hayashi <hayashi@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "groonga-query-log/command/check-performance-regression"
20
+
21
+ checker = GroongaQueryLog::Command::CheckPerformanceRegression.new
22
+ exit(checker.run(ARGV))
@@ -1,5 +1,19 @@
1
1
  # News
2
2
 
3
+ ## 1.4.5: 2019-08-15
4
+
5
+ ### Improvements
6
+
7
+ * `groonga-query-log-check-performance-regression`:
8
+
9
+ * Added feature for checking deterioration of performance.
10
+
11
+ ### Fixes
12
+
13
+ * `groonga-query-log-run-regression-test`:
14
+
15
+ * Fixed a bug that `--rewrite-and-not-operator` option doesn't work.
16
+
3
17
  ## 1.4.4: 2019-08-05
4
18
 
5
19
  ### Improvements
@@ -0,0 +1,447 @@
1
+ # Copyright (C) 2019 Kentaro Hayashi <hayashi@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "optparse"
18
+ require "json"
19
+
20
+ require "groonga-query-log"
21
+ require "groonga-query-log/command-line"
22
+
23
+ require "groonga-query-log/command/analyzer"
24
+ require "groonga-query-log/command/analyzer/sized-statistics"
25
+
26
+ module GroongaQueryLog
27
+ module Command
28
+ class CheckPerformanceRegression < CommandLine
29
+ NSEC_IN_SECONDS = (1000 * 1000 * 1000)
30
+ USEC_IN_SECONDS = (1000 * 1000)
31
+ MSEC_IN_SECONDS = 1000
32
+
33
+ def initialize(options={})
34
+ setup_options(options)
35
+ end
36
+
37
+ def run(arguments)
38
+ paths = []
39
+ begin
40
+ paths = @option_parser.parse!(arguments)
41
+ rescue OptionParser::InvalidOption => error
42
+ $stderr.puts(error)
43
+ return false
44
+ end
45
+
46
+ if paths.size != 2
47
+ $stderr.puts("old query log and new query log must be specified.")
48
+ return false
49
+ end
50
+
51
+ old_query_paths = resolve_path(paths[0])
52
+ return false if old_query_paths.nil?
53
+ new_query_paths = resolve_path(paths[1])
54
+ return false if new_query_paths.nil?
55
+
56
+ old_statistics = analyze(old_query_paths)
57
+ return false if old_statistics.nil?
58
+ new_statistics = analyze(new_query_paths)
59
+ return false if new_statistics.nil?
60
+
61
+ open_output do |output|
62
+ checker = Checker.new(old_statistics,
63
+ new_statistics,
64
+ output,
65
+ @threshold,
66
+ @target_queries)
67
+ checker.check
68
+ end
69
+ end
70
+
71
+ private
72
+ def resolve_path(path)
73
+ if File.directory?(path)
74
+ Dir.glob("#{path}/*.log")
75
+ elsif File.exist?(path)
76
+ [path]
77
+ else
78
+ $stderr.puts("query log path doesn't exist: <#{path}>")
79
+ nil
80
+ end
81
+ end
82
+
83
+ def open_output(&block)
84
+ case @output
85
+ when "-"
86
+ yield($stdout)
87
+ when String
88
+ File.open(@output, "w", &block)
89
+ else
90
+ yield(@output)
91
+ end
92
+ end
93
+
94
+ def setup_options(options)
95
+ @output = options[:output] || "-"
96
+ @n_entries = 1000
97
+ @threshold = Threshold.new
98
+ @target_queries = []
99
+
100
+ @option_parser = OptionParser.new do |parser|
101
+ parser.version = VERSION
102
+ parser.banner += " OLD_QUERY_LOG NEW_QUERY_LOG"
103
+
104
+ parser.on("-n", "--n-entries=N",
105
+ Integer,
106
+ "Analyze N query log entries",
107
+ "(#{@n_entries})") do |n|
108
+ @n_entries = n
109
+ end
110
+
111
+ if @output == "-"
112
+ default_output = "stdout"
113
+ else
114
+ default_output = @output
115
+ end
116
+ parser.on("--output=PATH",
117
+ "Output to PATH.",
118
+ "(#{default_output})") do |output|
119
+ @output = output
120
+ end
121
+
122
+ parser.on("--target-query-file=TARGET_QUERY_FILE",
123
+ "Analyze matched queries which are listed " +
124
+ "in specified TARGET_QUERY_FILE.") do |path|
125
+ if File.exist?(path)
126
+ @target_queries = File.readlines(path, chomp: true)
127
+ else
128
+ message = "target query file doesn't exist: <#{path}>"
129
+ raise OptionParser::InvalidOption.new(message)
130
+ end
131
+ end
132
+
133
+ parser.on("--slow-query-ratio=RATIO",
134
+ Float,
135
+ "Use RATIO as threshold to detect slow queries.",
136
+ "If MEAN_NEW_ELAPSED_TIME / MEAN_OLD_ELAPSED_TIME AVERAGE",
137
+ "is larger than RATIO, the query is slow.",
138
+ "(#{@threshold.query_ratio})") do |ratio|
139
+ @threshold.query_ratio = ratio
140
+ end
141
+
142
+ parser.on("--slow-query-second=SECOND",
143
+ Float,
144
+ "Use SECOND as threshold to detect slow queries.",
145
+ "If MEAN_NEW_ELAPSED_TIME - MEAN_OLD_ELAPSED_TIME AVERAGE",
146
+ "is larger than SECOND, the query is slow.",
147
+ "(#{@threshold.query_second})") do |second|
148
+ @threshold.query_second = second
149
+ end
150
+
151
+ parser.on("--slow-operation-ratio=RATIO",
152
+ Float,
153
+ "Use RATIO as threshold to detect slow operations.",
154
+ "If MEAN_NEW_ELAPSED_TIME / MEAN_OLD_ELAPSED_TIME AVERAGE",
155
+ "is larger than RATIO, the operation is slow.",
156
+ "(#{@threshold.operation_ratio})") do |ratio|
157
+ @threshold.operation_ratio = ratio
158
+ end
159
+
160
+ parser.on("--slow-operation-second=SECOND",
161
+ Float,
162
+ "Use SECOND as threshold to detect slow operations.",
163
+ "If MEAN_NEW_ELAPSED_TIME - MEAN_OLD_ELAPSED_TIME AVERAGE",
164
+ "is larger than SECOND, the operation is slow.",
165
+ "(#{@threshold.operation_second})") do |second|
166
+ @threshold.operation_second = second
167
+ end
168
+ end
169
+ end
170
+
171
+
172
+ def analyze(log_paths)
173
+ full_statistics = []
174
+ begin
175
+ n = 1
176
+ parser = Parser.new
177
+ parse_log(parser, log_paths) do |statistic|
178
+ next if n > @n_entries
179
+ full_statistics << statistic
180
+ n += 1
181
+ end
182
+ rescue Error
183
+ $stderr.puts($!.message)
184
+ return nil
185
+ end
186
+ full_statistics
187
+ end
188
+
189
+ class Threshold
190
+ attr_accessor :query_ratio
191
+ attr_accessor :query_second
192
+ attr_accessor :operation_ratio
193
+ attr_accessor :operation_second
194
+ def initialize
195
+ @query_ratio = 0
196
+ @query_second = 0.2
197
+ @operation_ratio = 0.1
198
+ @operation_second = 0.1
199
+ end
200
+
201
+ def slow_query?(diff_sec, diff_ratio)
202
+ return false if diff_sec.zero?
203
+ (diff_sec >= @query_second) and
204
+ (diff_ratio >= @query_ratio)
205
+ end
206
+
207
+ def slow_operation?(diff_sec, diff_ratio)
208
+ return false if diff_sec.zero?
209
+ (diff_sec >= @operation_second) and
210
+ (diff_ratio >= @operation_ratio)
211
+ end
212
+ end
213
+
214
+ class Statistic
215
+ def initialize(old, new, threshold)
216
+ @old = old
217
+ @new = new
218
+ @threshold = threshold
219
+ end
220
+
221
+ def old_elapsed_time
222
+ @old_elapsed_time ||= compute_mean(@old)
223
+ end
224
+
225
+ def new_elapsed_time
226
+ @new_elapsed_time ||= compute_mean(@new)
227
+ end
228
+
229
+ def diff_elapsed_time
230
+ new_elapsed_time - old_elapsed_time
231
+ end
232
+
233
+ def ratio
234
+ @ratio ||= compute_ratio
235
+ end
236
+
237
+ private
238
+ def compute_ratio
239
+ if old_elapsed_time.zero?
240
+ if new_elapsed_time.zero?
241
+ 0.0
242
+ else
243
+ Float::INIFINITY
244
+ end
245
+ else
246
+ new_elapsed_time / old_elapsed_time
247
+ end
248
+ end
249
+ end
250
+
251
+ class OperationStatistic < Statistic
252
+ attr_reader :index
253
+ def initialize(operation, index, old, new, threshold)
254
+ super(old, new, threshold)
255
+ @operation = operation
256
+ @index = index
257
+ end
258
+
259
+ def name
260
+ @operation[:name]
261
+ end
262
+
263
+ def context
264
+ @operation[:context]
265
+ end
266
+
267
+ def slow?
268
+ @threshold.slow_operation?(diff_elapsed_time, ratio)
269
+ end
270
+
271
+ private
272
+ def compute_mean(operations)
273
+ elapsed_times = operations.collect do |operation|
274
+ operation[:relative_elapsed] / 1000.0 / 1000.0 / 1000.0
275
+ end
276
+ elapsed_times.inject(:+) / elapsed_times.size
277
+ end
278
+ end
279
+
280
+ class QueryStatistic < Statistic
281
+ attr_reader :query
282
+ def initialize(query, old, new, threshold)
283
+ super(old, new, threshold)
284
+ @query = query
285
+ end
286
+
287
+ def slow?
288
+ @threshold.slow_query?(diff_elapsed_time, ratio)
289
+ end
290
+
291
+ def each_operation_statistic
292
+ @old.first.operations.each_with_index do |operation, i|
293
+ old_operations = @old.collect do |statistic|
294
+ statistic.operations[i]
295
+ end
296
+ # TODO: old and new may use different index
297
+ new_operations = @new.collect do |statistic|
298
+ statistic.operations[i]
299
+ end
300
+ operation_statistic = OperationStatistic.new(operation,
301
+ i,
302
+ old_operations,
303
+ new_operations,
304
+ @threshold)
305
+ yield(operation_statistic)
306
+ end
307
+ end
308
+
309
+ private
310
+ def compute_mean(statistics)
311
+ elapsed_times = statistics.collect do |statistic|
312
+ statistic.elapsed / 1000.0 / 1000.0 / 1000.0
313
+ end
314
+ elapsed_times.inject(:+) / elapsed_times.size
315
+ end
316
+ end
317
+
318
+ class Checker
319
+ def initialize(old_statistics,
320
+ new_statistics,
321
+ output,
322
+ threshold,
323
+ target_queries)
324
+ @old_statistics = old_statistics
325
+ @new_statistics = new_statistics
326
+ @output = output
327
+ @threshold = threshold
328
+ @target_queries = target_queries
329
+ end
330
+
331
+ def check
332
+ old_statistics = filter_statistics(@old_statistics)
333
+ new_statistics = filter_statistics(@new_statistics)
334
+ old_queries = old_statistics.group_by(&:raw_command)
335
+ new_queries = new_statistics.group_by(&:raw_command)
336
+
337
+ query_statistics = []
338
+ old_queries.each_key do |query|
339
+ query_statistic = QueryStatistic.new(query,
340
+ old_queries[query],
341
+ new_queries[query],
342
+ @threshold)
343
+ next unless query_statistic.slow?
344
+ query_statistics << query_statistic
345
+ end
346
+
347
+ n_slow_queries = 0
348
+ n_target_operations = 0
349
+ n_slow_operations = 0
350
+ query_statistics.sort_by(&:ratio).each do |query_statistic|
351
+ n_slow_queries += 1
352
+ @output.puts(<<-REPORT)
353
+ Query: #{query_statistic.query}
354
+ Mean (old): #{format_elapsed_time(query_statistic.old_elapsed_time)}
355
+ Mean (new): #{format_elapsed_time(query_statistic.new_elapsed_time)}
356
+ Diff: #{format_diff(query_statistic)}
357
+ Operations:
358
+ REPORT
359
+ query_statistic.each_operation_statistic do |operation_statistic|
360
+ n_target_operations += 1
361
+ next unless operation_statistic.slow?
362
+
363
+ n_slow_operations += 1
364
+ index = operation_statistic.index
365
+ name = operation_statistic.name
366
+ context = operation_statistic.context
367
+ label = [name, context].compact.join(" ")
368
+ old_elapsed_time = operation_statistic.old_elapsed_time
369
+ new_elapsed_time = operation_statistic.new_elapsed_time
370
+ @output.puts(<<-REPORT)
371
+ Operation[#{index}]: #{label}
372
+ Mean (old): #{format_elapsed_time(old_elapsed_time)}
373
+ Mean (new): #{format_elapsed_time(new_elapsed_time)}
374
+ Diff: #{format_diff(operation_statistic)}
375
+ REPORT
376
+ end
377
+ end
378
+
379
+ n_all_queries = @old_statistics.size
380
+ n_target_queries = old_queries.size
381
+ n_old_cached_queries = count_cached_queries(@old_statistics)
382
+ n_new_cached_queries = count_cached_queries(@new_statistics)
383
+ @output.puts(<<-REPORT)
384
+ Summary:
385
+ Slow queries: #{format_summary(n_slow_queries, n_target_queries)}
386
+ Slow operations: #{format_summary(n_slow_operations, n_target_operations)}
387
+ Caches (old): #{format_summary(n_old_cached_queries, n_all_queries)}
388
+ Caches (new): #{format_summary(n_new_cached_queries, n_all_queries)}
389
+ REPORT
390
+ true
391
+ end
392
+
393
+ private
394
+ def count_cached_queries(statistics)
395
+ n_cached_queries = 0
396
+ statistics.each do |statistic|
397
+ n_cached_queries += 1 if statistic.cache_used?
398
+ end
399
+ n_cached_queries
400
+ end
401
+
402
+ def filter_statistics(statistics)
403
+ statistics.find_all do |statistic|
404
+ target_statistic?(statistic)
405
+ end
406
+ end
407
+
408
+ def target_statistic?(statistic)
409
+ return false if statistic.cache_used?
410
+ return true if @target_queries.empty?
411
+ @target_queries.include?(statistic.raw_command)
412
+ end
413
+
414
+ def format_elapsed_time(elapsed_time)
415
+ if elapsed_time < (1 / 1000.0 / 1000.0)
416
+ "%.1fnsec" % (elapsed_time * 1000 * 1000)
417
+ elsif elapsed_time < (1 / 1000.0)
418
+ "%.1fusec" % (elapsed_time * 1000 * 1000)
419
+ elsif elapsed_time < 1
420
+ "%.1fmsec" % (elapsed_time * 1000)
421
+ elsif elapsed_time < 60
422
+ "%.1fsec" % elapsed_time
423
+ else
424
+ "%.1fmin" % (elapsed_time / 60)
425
+ end
426
+ end
427
+
428
+ def format_diff(statistic)
429
+ "%s%s/%+.2f" % [
430
+ statistic.diff_elapsed_time < 0 ? "-" : "+",
431
+ format_elapsed_time(statistic.diff_elapsed_time),
432
+ statistic.ratio,
433
+ ]
434
+ end
435
+
436
+ def format_summary(n_slows, total)
437
+ if total.zero?
438
+ percentage = 0.0
439
+ else
440
+ percentage = (n_slows / total.to_f) * 100
441
+ end
442
+ "%d/%d(%6.2f%%)" % [n_slows, total, percentage]
443
+ end
444
+ end
445
+ end
446
+ end
447
+ end
@@ -338,7 +338,7 @@ module GroongaQueryLog
338
338
  @nullable_reference_number_accessors,
339
339
  :rewrite_not_or_regular_expression =>
340
340
  @rewrite_not_or_regular_expression,
341
- :rewite_and_not_operator =>
341
+ :rewrite_and_not_operator =>
342
342
  @rewrite_and_not_operator,
343
343
  :target_command_names => @target_command_names,
344
344
  :read_timeout => @read_timeout,
@@ -61,6 +61,12 @@ module GroongaQueryLog
61
61
  elapsed_in_seconds >= @slow_response_threshold
62
62
  end
63
63
 
64
+ def cache_used?
65
+ each_operation.any? do |operation|
66
+ operation[:name] == "cache"
67
+ end
68
+ end
69
+
64
70
  def each_operation
65
71
  return to_enum(__method__) unless block_given?
66
72
 
@@ -15,5 +15,5 @@
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
  module GroongaQueryLog
18
- VERSION = "1.4.4"
18
+ VERSION = "1.4.5"
19
19
  end
@@ -0,0 +1,311 @@
1
+ # Copyright (C) 2019 Kentaro Hayashi <hayashi@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "groonga-query-log/command/check-performance-regression"
18
+
19
+ class CheckPerformanceRegressionCommandTest < Test::Unit::TestCase
20
+ include Helper::Path
21
+
22
+ def setup
23
+ @command = GroongaQueryLog::Command::CheckPerformanceRegression.new
24
+ end
25
+
26
+ def fixture_path(*components)
27
+ super("check-performance-regression", *components)
28
+ end
29
+
30
+ def run_command(*arguments)
31
+ output = StringIO.new
32
+ options = {:output => output}
33
+ command = GroongaQueryLog::Command::CheckPerformanceRegression.new(options)
34
+ command.run(arguments)
35
+ output.string
36
+ end
37
+
38
+ sub_test_case("options") do
39
+ MISSING_QUERY_LOG_ERROR = <<-OUTPUT
40
+ old query log and new query log must be specified.
41
+ OUTPUT
42
+
43
+ def run_command_with_stderr
44
+ begin
45
+ output = StringIO.new
46
+ $stderr = output
47
+ yield
48
+ output.string
49
+ ensure
50
+ $stderr = STDERR
51
+ end
52
+ end
53
+
54
+ def test_no_option
55
+ actual = run_command_with_stderr do
56
+ @command.run([])
57
+ end
58
+ assert_equal(MISSING_QUERY_LOG_ERROR, actual)
59
+ end
60
+
61
+ def test_too_few_query_logs
62
+ actual = run_command_with_stderr do
63
+ @command.run([
64
+ fixture_path("query1.log")
65
+ ])
66
+ end
67
+ assert_equal(MISSING_QUERY_LOG_ERROR, actual)
68
+ end
69
+
70
+ def test_too_many_query_logs
71
+ actual = run_command_with_stderr do
72
+ @command.run([
73
+ fixture_path("query1.log"),
74
+ fixture_path("query2.log"),
75
+ fixture_path("query1.log")
76
+ ])
77
+ end
78
+ assert_equal(MISSING_QUERY_LOG_ERROR, actual)
79
+ end
80
+
81
+ def test_nonexistent_input_old_query
82
+ actual = run_command_with_stderr do
83
+ @command.run([
84
+ fixture_path("nonexsistent.log"),
85
+ fixture_path("query2.log")
86
+ ])
87
+ end
88
+ assert_equal(<<-OUTPUT, actual)
89
+ query log path doesn't exist: <#{fixture_path("nonexsistent.log")}>
90
+ OUTPUT
91
+ end
92
+
93
+ def test_nonexistent_input_new_query
94
+ actual = run_command_with_stderr do
95
+ @command.run([
96
+ fixture_path("query1.log"),
97
+ fixture_path("nonexsistent.log")
98
+ ])
99
+ end
100
+ assert_equal(<<-OUTPUT, actual)
101
+ query log path doesn't exist: <#{fixture_path("nonexsistent.log")}>
102
+ OUTPUT
103
+ end
104
+
105
+ def test_output
106
+ Tempfile.open('test_output') do |output|
107
+ @command.run([
108
+ "--slow-query-ratio=0",
109
+ "--slow-query-second=0",
110
+ "--slow-operation-ratio=0",
111
+ "--slow-operation-second=0",
112
+ "--output=#{output.path}",
113
+ fixture_path("query1.log"),
114
+ fixture_path("query2.log")
115
+ ])
116
+ expected = <<-OUTPUT
117
+ Query: select --table Site --limit 0
118
+ Mean (old): 12.0msec
119
+ Mean (new): 14.0msec
120
+ Diff: +2.0msec/+1.17
121
+ Operations:
122
+ Operation[0]: select
123
+ Mean (old): 5.0msec
124
+ Mean (new): 6.0msec
125
+ Diff: +1.0msec/+1.20
126
+ Summary:
127
+ Slow queries: 1/1(100.00%)
128
+ Slow operations: 1/2( 50.00%)
129
+ Caches (old): 0/1( 0.00%)
130
+ Caches (new): 0/1( 0.00%)
131
+ OUTPUT
132
+ assert_equal(expected, output.read)
133
+ end
134
+ end
135
+
136
+ def test_n_query
137
+ actual = run_command("--n-entries=1",
138
+ "--slow-query-ratio=0",
139
+ "--slow-query-second=0",
140
+ "--slow-operation-ratio=0",
141
+ "--slow-operation-second=0",
142
+ fixture_path("nquery.log"),
143
+ fixture_path("nquery2.log"))
144
+ expected = <<-OUTPUT
145
+ Query: select --table Site --filter "_id >= 4 && _id <= 6"
146
+ Mean (old): 70.0msec
147
+ Mean (new): 90.0msec
148
+ Diff: +20.0msec/+1.29
149
+ Operations:
150
+ Operation[0]: filter #<accessor _id(Site)> greater_equal 4
151
+ Mean (old): 40.0msec
152
+ Mean (new): 80.0msec
153
+ Diff: +40.0msec/+2.00
154
+ Operation[1]: filter #<accessor _id(Site)> less_equal 6
155
+ Mean (old): 10.0msec
156
+ Mean (new): 20.0msec
157
+ Diff: +10.0msec/+2.00
158
+ Operation[2]: select
159
+ Mean (old): 10.0msec
160
+ Mean (new): 20.0msec
161
+ Diff: +10.0msec/+2.00
162
+ Operation[3]: output
163
+ Mean (old): 10.0msec
164
+ Mean (new): 20.0msec
165
+ Diff: +10.0msec/+2.00
166
+ Summary:
167
+ Slow queries: 1/1(100.00%)
168
+ Slow operations: 4/4(100.00%)
169
+ Caches (old): 0/1( 0.00%)
170
+ Caches (new): 0/1( 0.00%)
171
+ OUTPUT
172
+ assert_equal(expected, actual)
173
+ end
174
+ end
175
+
176
+ sub_test_case(".new") do
177
+ def test_output
178
+ actual = run_command("--slow-query-ratio=0.0",
179
+ "--slow-query-second=0.0",
180
+ "--slow-operation-ratio=0.0",
181
+ "--slow-operation-second=0.0",
182
+ fixture_path("query1.log"),
183
+ fixture_path("query2.log"))
184
+ expected = <<-OUTPUT
185
+ Query: select --table Site --limit 0
186
+ Mean (old): 12.0msec
187
+ Mean (new): 14.0msec
188
+ Diff: +2.0msec/+1.17
189
+ Operations:
190
+ Operation[0]: select
191
+ Mean (old): 5.0msec
192
+ Mean (new): 6.0msec
193
+ Diff: +1.0msec/+1.20
194
+ Summary:
195
+ Slow queries: 1/1(100.00%)
196
+ Slow operations: 1/2( 50.00%)
197
+ Caches (old): 0/1( 0.00%)
198
+ Caches (new): 0/1( 0.00%)
199
+ OUTPUT
200
+ assert_equal(expected, actual)
201
+ end
202
+ end
203
+
204
+ sub_test_case("query-ratio") do
205
+ def test_filtered
206
+ actual = run_command("--slow-query-ratio=2",
207
+ "--slow-query-second=0",
208
+ "--slow-operation-ratio=0",
209
+ "--slow-operation-second=0",
210
+ fixture_path("query1.log"),
211
+ fixture_path("query2.log"))
212
+ expected = <<-OUTPUT
213
+ Summary:
214
+ Slow queries: 0/1( 0.00%)
215
+ Slow operations: 0/0( 0.00%)
216
+ Caches (old): 0/1( 0.00%)
217
+ Caches (new): 0/1( 0.00%)
218
+ OUTPUT
219
+ assert_equal(expected, actual)
220
+ end
221
+ end
222
+
223
+ sub_test_case("operation-ratio") do
224
+ def test_filtered
225
+ actual = run_command("--slow-query-ratio=0",
226
+ "--slow-query-second=0",
227
+ "--slow-operation-ratio=2",
228
+ "--slow-operation-second=0",
229
+ fixture_path("query1.log"),
230
+ fixture_path("query2.log"))
231
+ expected = <<-OUTPUT
232
+ Query: select --table Site --limit 0
233
+ Mean (old): 12.0msec
234
+ Mean (new): 14.0msec
235
+ Diff: +2.0msec/+1.17
236
+ Operations:
237
+ Summary:
238
+ Slow queries: 1/1(100.00%)
239
+ Slow operations: 0/2( 0.00%)
240
+ Caches (old): 0/1( 0.00%)
241
+ Caches (new): 0/1( 0.00%)
242
+ OUTPUT
243
+ assert_equal(expected, actual)
244
+ end
245
+ end
246
+
247
+ sub_test_case("query-second") do
248
+ def test_filtered
249
+ actual = run_command("--slow-query-ratio=0",
250
+ "--slow-query-second=0.02",
251
+ "--slow-operation-ratio=0",
252
+ "--slow-operation-second=0",
253
+ fixture_path("query1.log"),
254
+ fixture_path("query2.log"))
255
+ expected = <<-OUTPUT
256
+ Summary:
257
+ Slow queries: 0/1( 0.00%)
258
+ Slow operations: 0/0( 0.00%)
259
+ Caches (old): 0/1( 0.00%)
260
+ Caches (new): 0/1( 0.00%)
261
+ OUTPUT
262
+ assert_equal(expected, actual)
263
+ end
264
+ end
265
+
266
+ sub_test_case("operation-second") do
267
+ def test_filtered
268
+ actual = run_command("--slow-query-ratio=0",
269
+ "--slow-query-second=0",
270
+ "--slow-operation-ratio=0",
271
+ "--slow-operation-second=0.001",
272
+ fixture_path("query1.log"),
273
+ fixture_path("query2.log"))
274
+ expected = <<-OUTPUT
275
+ Query: select --table Site --limit 0
276
+ Mean (old): 12.0msec
277
+ Mean (new): 14.0msec
278
+ Diff: +2.0msec/+1.17
279
+ Operations:
280
+ Operation[0]: select
281
+ Mean (old): 5.0msec
282
+ Mean (new): 6.0msec
283
+ Diff: +1.0msec/+1.20
284
+ Summary:
285
+ Slow queries: 1/1(100.00%)
286
+ Slow operations: 1/2( 50.00%)
287
+ Caches (old): 0/1( 0.00%)
288
+ Caches (new): 0/1( 0.00%)
289
+ OUTPUT
290
+ assert_equal(expected, actual)
291
+ end
292
+ end
293
+
294
+ sub_test_case("cache") do
295
+ def test_ignored_cache
296
+ actual = run_command("--slow-query-ratio=0",
297
+ "--slow-operation-ratio=0",
298
+ "--slow-query-second=0",
299
+ fixture_path("cache.log"),
300
+ fixture_path("cache.log"))
301
+ expected = <<-OUTPUT
302
+ Summary:
303
+ Slow queries: 0/0( 0.00%)
304
+ Slow operations: 0/0( 0.00%)
305
+ Caches (old): 1/1(100.00%)
306
+ Caches (new): 1/1(100.00%)
307
+ OUTPUT
308
+ assert_equal(expected, actual)
309
+ end
310
+ end
311
+ end
@@ -0,0 +1,3 @@
1
+ 2019-01-22 16:00:00.000000|0x7ffc70f60080|>select --table Site --limit 0
2
+ 2019-01-22 16:00:01.500000|0x7ffc70f60080|:000000006000000 cache(1)
3
+ 2019-01-22 16:00:03.000000|0x7ffc70f60080|<000000014000000 rc=0
@@ -0,0 +1,10 @@
1
+ 2019-01-24 08:18:33.921596|0x7ffd9e258a40|>select --table Site --filter "_id >= 4 && _id <= 6"
2
+ 2019-01-24 08:18:33.968258|0x7ffd9e258a40|:000000040000000 filter(6): #<accessor _id(Site)> greater_equal 4
3
+ 2019-01-24 08:18:33.968917|0x7ffd9e258a40|:000000050000000 filter(3): #<accessor _id(Site)> less_equal 6
4
+ 2019-01-24 08:18:33.968940|0x7ffd9e258a40|:000000060000000 select(3)
5
+ 2019-01-24 08:18:33.969085|0x7ffd9e258a40|:000000070000000 output(3)
6
+ 2019-01-24 08:18:33.969311|0x7ffd9e258a40|<000000070000000 rc=0
7
+ 2019-01-24 08:19:05.449799|0x7ffe40eafa50|>select --table Site
8
+ 2019-01-24 08:19:05.450416|0x7ffe40eafa50|:000000000600000 select(9)
9
+ 2019-01-24 08:19:05.450706|0x7ffe40eafa50|:000000000900000 output(9)
10
+ 2019-01-24 08:19:05.451271|0x7ffe40eafa50|<000000001400000 rc=0
@@ -0,0 +1,10 @@
1
+ 2019-01-24 08:18:33.921596|0x7ffd9e258a40|>select --table Site --filter "_id >= 4 && _id <= 6"
2
+ 2019-01-24 08:18:33.968258|0x7ffd9e258a40|:000000080000000 filter(6): #<accessor _id(Site)> greater_equal 4
3
+ 2019-01-24 08:18:33.968917|0x7ffd9e258a40|:000000100000000 filter(3): #<accessor _id(Site)> less_equal 6
4
+ 2019-01-24 08:18:33.968940|0x7ffd9e258a40|:000000120000000 select(3)
5
+ 2019-01-24 08:18:33.969085|0x7ffd9e258a40|:000000140000000 output(3)
6
+ 2019-01-24 08:18:33.969311|0x7ffd9e258a40|<000000090000000 rc=0
7
+ 2019-01-24 08:19:05.449799|0x7ffe40eafa50|>select --table Site
8
+ 2019-01-24 08:19:05.450416|0x7ffe40eafa50|:000000000600000 select(9)
9
+ 2019-01-24 08:19:05.450706|0x7ffe40eafa50|:000000000900000 output(9)
10
+ 2019-01-24 08:19:05.451271|0x7ffe40eafa50|<000000001400000 rc=0
@@ -0,0 +1,4 @@
1
+ 2019-01-22 15:00:57.466438|0x7ffc70f60080|>select --table Site --limit 0
2
+ 2019-01-22 15:00:57.472248|0x7ffc70f60080|:000000005000000 select(1)
3
+ 2019-01-22 15:00:57.475195|0x7ffc70f60080|:000000007000000 output(0)
4
+ 2019-01-22 15:00:57.475480|0x7ffc70f60080|<000000012000000 rc=0
@@ -0,0 +1,4 @@
1
+ 2019-01-22 16:00:00.000000|0x7ffc70f60080|>select --table Site --limit 0
2
+ 2019-01-22 16:00:01.500000|0x7ffc70f60080|:000000006000000 select(1)
3
+ 2019-01-22 16:00:02.000000|0x7ffc70f60080|:000000008000000 output(0)
4
+ 2019-01-22 16:00:03.000000|0x7ffc70f60080|<000000014000000 rc=0
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: groonga-query-log
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 1.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kouhei Sutou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-07 00:00:00.000000000 Z
11
+ date: 2019-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: groonga-command-parser
@@ -154,17 +154,18 @@ description: ''
154
154
  email:
155
155
  - kou@clear-code.com
156
156
  executables:
157
- - groonga-query-log-format-regression-test-logs
158
- - groonga-query-log-run-regression-test
157
+ - groonga-query-log-detect-memory-leak
158
+ - groonga-query-log-analyze
159
159
  - groonga-query-log-check-crash
160
160
  - groonga-query-log-replay
161
+ - groonga-query-log-extract
162
+ - groonga-query-log-show-running-queries
161
163
  - groonga-query-log-check-command-version-compatibility
164
+ - groonga-query-log-run-regression-test
162
165
  - groonga-query-log-verify-server
163
- - groonga-query-log-show-running-queries
164
- - groonga-query-log-analyze
165
- - groonga-query-log-extract
166
- - groonga-query-log-detect-memory-leak
167
166
  - groonga-query-log-analyze-load
167
+ - groonga-query-log-format-regression-test-logs
168
+ - groonga-query-log-check-performance-regression
168
169
  extensions: []
169
170
  extra_rdoc_files: []
170
171
  files:
@@ -176,6 +177,7 @@ files:
176
177
  - bin/groonga-query-log-analyze-load
177
178
  - bin/groonga-query-log-check-command-version-compatibility
178
179
  - bin/groonga-query-log-check-crash
180
+ - bin/groonga-query-log-check-performance-regression
179
181
  - bin/groonga-query-log-detect-memory-leak
180
182
  - bin/groonga-query-log-extract
181
183
  - bin/groonga-query-log-format-regression-test-logs
@@ -203,6 +205,7 @@ files:
203
205
  - lib/groonga-query-log/command/analyzer/streamer.rb
204
206
  - lib/groonga-query-log/command/check-command-version-compatibility.rb
205
207
  - lib/groonga-query-log/command/check-crash.rb
208
+ - lib/groonga-query-log/command/check-performance-regression.rb
206
209
  - lib/groonga-query-log/command/detect-memory-leak.rb
207
210
  - lib/groonga-query-log/command/extract.rb
208
211
  - lib/groonga-query-log/command/format-regression-test-logs.rb
@@ -230,9 +233,15 @@ files:
230
233
  - lib/groonga/query-log/command/show-running-queries.rb
231
234
  - lib/groonga/query-log/command/verify-server.rb
232
235
  - test/command/test-analyzer.rb
236
+ - test/command/test-check-performance-regression.rb
233
237
  - test/command/test-extract.rb
234
238
  - test/command/test-format-regression-test-logs.rb
235
239
  - test/command/test-run-regression-test.rb
240
+ - test/fixtures/check-performance-regression/cache.log
241
+ - test/fixtures/check-performance-regression/nquery.log
242
+ - test/fixtures/check-performance-regression/nquery2.log
243
+ - test/fixtures/check-performance-regression/query1.log
244
+ - test/fixtures/check-performance-regression/query2.log
236
245
  - test/fixtures/multi.expected
237
246
  - test/fixtures/n_entries.expected
238
247
  - test/fixtures/no-report-summary.expected
@@ -289,36 +298,42 @@ summary: Groonga-query-log is a collection of library and tools to process [Groo
289
298
  as a library. You can analyze your Groonga's queries and test with your Groonga's
290
299
  query log by using groonga-query-log as a tool.
291
300
  test_files:
292
- - test/fixtures/reporter/console.expected
293
- - test/fixtures/reporter/html.expected
294
- - test/fixtures/reporter/json-stream.expected
295
- - test/fixtures/reporter/json.expected
296
- - test/fixtures/order/start-time.expected
301
+ - test/run-test.rb
302
+ - test/fixtures/n_entries.expected
303
+ - test/fixtures/check-performance-regression/query1.log
304
+ - test/fixtures/check-performance-regression/cache.log
305
+ - test/fixtures/check-performance-regression/nquery2.log
306
+ - test/fixtures/check-performance-regression/nquery.log
307
+ - test/fixtures/check-performance-regression/query2.log
308
+ - test/fixtures/target-tables.expected
309
+ - test/fixtures/no-report-summary.expected
297
310
  - test/fixtures/order/-start-time.expected
298
311
  - test/fixtures/order/-elapsed.expected
312
+ - test/fixtures/order/start-time.expected
299
313
  - test/fixtures/order/elapsed.expected
300
- - test/fixtures/no-report-summary.expected
301
- - test/fixtures/target-commands.expected
302
- - test/fixtures/run-regression-test/data/data.grn
303
- - test/fixtures/run-regression-test/query-logs/query.log
304
- - test/fixtures/run-regression-test/indexes/indexes.grn
305
- - test/fixtures/run-regression-test/schema/schema.grn
306
- - test/fixtures/other-query.log
307
- - test/fixtures/query.log
308
- - test/fixtures/target-tables.expected
309
- - test/fixtures/n_entries.expected
310
- - test/fixtures/multi.expected
311
- - test/fixtures/regression-test-logs/command-format.log
312
314
  - test/fixtures/regression-test-logs/url-format.log
315
+ - test/fixtures/regression-test-logs/command-format.log
313
316
  - test/fixtures/regression-test-logs/error.log
317
+ - test/fixtures/multi.expected
318
+ - test/fixtures/query.log
319
+ - test/fixtures/other-query.log
320
+ - test/fixtures/reporter/json-stream.expected
321
+ - test/fixtures/reporter/console.expected
322
+ - test/fixtures/reporter/json.expected
323
+ - test/fixtures/reporter/html.expected
324
+ - test/fixtures/run-regression-test/schema/schema.grn
325
+ - test/fixtures/run-regression-test/data/data.grn
326
+ - test/fixtures/run-regression-test/indexes/indexes.grn
327
+ - test/fixtures/run-regression-test/query-logs/query.log
328
+ - test/fixtures/target-commands.expected
329
+ - test/test-parser.rb
330
+ - test/helper.rb
331
+ - test/test-replayer.rb
332
+ - test/test-response-comparer.rb
314
333
  - test/command/test-run-regression-test.rb
334
+ - test/command/test-check-performance-regression.rb
315
335
  - test/command/test-format-regression-test-logs.rb
316
336
  - test/command/test-analyzer.rb
317
337
  - test/command/test-extract.rb
318
- - test/test-response-comparer.rb
319
- - test/test-replayer.rb
320
338
  - test/test-incompatibility-detector.rb
321
339
  - test/test-filter-rewriter.rb
322
- - test/test-parser.rb
323
- - test/helper.rb
324
- - test/run-test.rb