Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions harness/harness-common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ def get_rss
# First, grab a line like "62796 kB". Checking the Linux kernel source, Rss will always be in kB.
rss_desc = File.read(mem_rollup_file).lines.detect { |line| line.start_with?("Rss") }.split(":", 2)[1][/(\d+)/, 1]
1024 * Integer(rss_desc)
elsif is_windows
get_windows_memory_counters&.fetch(:working_set) || 0
else
# Collect our own peak mem usage as soon as reasonable after finishing the last iteration.
# This method is only accurate to kilobytes, but is nicely portable and doesn't require
Expand Down Expand Up @@ -176,6 +178,46 @@ def self.function(name, args, ret)
end
end

# Memoized like ProcPidRusage, since load_fiddle alone takes about 0.1 ms on Windows.
module WindowsMemoryCounters
@resolved = false

def self.fn
return @fn if @resolved

@resolved = true
@fn = begin
load_fiddle
process = WindowsKernel32.function('GetCurrentProcess', [], Fiddle::TYPE_VOIDP).call
get_info = WindowsKernel32.function('K32GetProcessMemoryInfo', [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT], Fiddle::TYPE_INT)
->(buffer) { get_info.call(process, buffer, buffer.bytesize) }
rescue LoadError, Fiddle::DLError, NameError
warn "Failed to get memory counters: #{$!.message}"
nil
end
end
end

# Returns memory counters of this process in bytes. The working set is the Windows counterpart of RSS,
# and the commit charge (PagefileUsage) is the private memory the process has committed.
def get_windows_memory_counters
get_info = WindowsMemoryCounters.fn
return nil unless get_info

# PROCESS_MEMORY_COUNTERS: two DWORDs followed by eight SIZE_Ts.
buffer = "\0".b * (8 + 8 * Fiddle::SIZEOF_SIZE_T)
buffer[0, 4] = [buffer.bytesize].pack('L')
return nil if get_info.call(buffer).zero?

peak_working_set, working_set, _, _, _, _, commit_charge, peak_commit_charge = buffer.unpack('x8J8')
{
working_set: working_set,
peak_working_set: peak_working_set,
commit_charge: commit_charge,
peak_commit_charge: peak_commit_charge,
}
end

def pin_to_cpu(cpu)
load_fiddle
# Etc.nprocessors counts the CPUs of every processor group, but the mask holds those of one group only.
Expand Down Expand Up @@ -210,6 +252,8 @@ def raise_priority
end

def get_maxrss
return get_windows_memory_counters&.fetch(:peak_working_set) if is_windows

load_fiddle

require 'rbconfig/sizeof'
Expand Down Expand Up @@ -267,6 +311,10 @@ def return_results(warmup_iterations, bench_iterations, **extra)
if maxrss = get_maxrss
ruby_bench_results["maxrss"] = maxrss
end
if is_windows && (counters = get_windows_memory_counters)
ruby_bench_results["commit_charge"] = counters[:commit_charge]
ruby_bench_results["peak_commit_charge"] = counters[:peak_commit_charge]
end

# If YJIT or ZJIT is enabled, show some of its stats unless it does by itself.
if yjit_stats
Expand Down
Loading