groonga-query-log 1.4.4 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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