Skip to content

Commit 8ae1212

Browse files
authored
Merge pull request #622 from danmayer/perf-file-list-first-seen-at-3731001549367096294
⚡ Optimize FileList#first_seen_at to eliminate allocations
2 parents 24535fc + 525aa7f commit 8ae1212

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

lib/coverband/utils/file_list.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,13 @@ def covered_strength
7474
end
7575

7676
def first_seen_at
77-
filter_map { |f|
77+
min = nil
78+
each do |f|
7879
val = f.first_updated_at
79-
val unless val.is_a?(String)
80-
}.min
80+
next if val.is_a?(String)
81+
min = val if min.nil? || val < min
82+
end
83+
min
8184
end
8285
end
8386
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# frozen_string_literal: true
2+
3+
require "benchmark/ips"
4+
require "memory_profiler"
5+
6+
# Mock SourceFile
7+
class MockSourceFile
8+
attr_reader :first_updated_at
9+
10+
def initialize(first_updated_at)
11+
@first_updated_at = first_updated_at
12+
end
13+
end
14+
15+
class FileList < Array
16+
def first_seen_at_current
17+
filter_map { |f|
18+
val = f.first_updated_at
19+
val unless val.is_a?(String)
20+
}.min
21+
end
22+
23+
def first_seen_at_original
24+
map(&:first_updated_at).reject { |el| el.is_a?(String) }.min
25+
end
26+
27+
def first_seen_at_each
28+
min = nil
29+
each do |f|
30+
val = f.first_updated_at
31+
next if val.is_a?(String)
32+
min = val if min.nil? || val < min
33+
end
34+
min
35+
end
36+
end
37+
38+
# Generate data: 10,000 files
39+
files_mixed = Array.new(10000) { |i|
40+
val = (i % 5 == 0) ? "not available" : (Time.now - i)
41+
MockSourceFile.new(val)
42+
}
43+
list_mixed = FileList.new(files_mixed)
44+
45+
puts "---------------------------------------------------"
46+
puts "Memory Profiling: FileList#first_seen_at"
47+
48+
puts "\nOriginal (map+reject):"
49+
report = MemoryProfiler.report { list_mixed.first_seen_at_original }
50+
puts " Total allocated: #{report.total_allocated_memsize} bytes (#{report.total_allocated} objects)"
51+
52+
puts "\nCurrent (filter_map):"
53+
report = MemoryProfiler.report { list_mixed.first_seen_at_current }
54+
puts " Total allocated: #{report.total_allocated_memsize} bytes (#{report.total_allocated} objects)"
55+
56+
puts "\nOptimized (each):"
57+
report = MemoryProfiler.report { list_mixed.first_seen_at_each }
58+
puts " Total allocated: #{report.total_allocated_memsize} bytes (#{report.total_allocated} objects)"

0 commit comments

Comments
 (0)