Skip to content

Commit 0da8673

Browse files
committed
Split CPU config into Intel and AMD classes
1 parent 81fc27d commit 0da8673

File tree

2 files changed

+141
-75
lines changed

2 files changed

+141
-75
lines changed

lib/cpu_config.rb

Lines changed: 98 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@
22

33
# Manages CPU frequency and turbo boost configuration for benchmark consistency
44
class CPUConfig
5-
# Configure CPU for benchmarking: disable frequency scaling and verify settings
6-
def self.configure_for_benchmarking(turbo:)
7-
new.configure_for_benchmarking(turbo: turbo)
8-
end
5+
class << self
6+
# Configure CPU for benchmarking: disable frequency scaling and verify settings
7+
def configure_for_benchmarking(turbo:)
8+
build.configure_for_benchmarking(turbo: turbo)
9+
end
910

10-
def initialize
11-
@intel_cpu = File.exist?('/sys/devices/system/cpu/intel_pstate')
12-
@amd_cpu = File.exist?('/sys/devices/system/cpu/cpufreq/boost')
11+
def build
12+
if File.exist?('/sys/devices/system/cpu/intel_pstate')
13+
IntelCPUConfig.new
14+
elsif File.exist?('/sys/devices/system/cpu/cpufreq/boost')
15+
AMDCPUConfig.new
16+
else
17+
NullCPUConfig.new
18+
end
19+
end
1320
end
1421

1522
def configure_for_benchmarking(turbo:)
@@ -19,97 +26,123 @@ def configure_for_benchmarking(turbo:)
1926

2027
private
2128

22-
# Disable Turbo Boost while running benchmarks. Maximize the CPU frequency.
2329
def disable_frequency_scaling(turbo:)
24-
if intel_cpu?
25-
disable_intel_turbo unless turbo
26-
maximize_intel_frequency
27-
elsif amd_cpu?
28-
disable_amd_boost unless turbo
29-
set_performance_governor
30-
end
30+
disable_turbo_boost unless turbo || turbo_disabled?
31+
maximize_frequency unless frequency_maximized?
32+
end
33+
34+
def turbo_disabled?
35+
# Override in subclasses
36+
false
3137
end
3238

33-
def intel_cpu?
34-
@intel_cpu
39+
def frequency_maximized?
40+
# Override in subclasses
41+
false
3542
end
3643

37-
def amd_cpu?
38-
@amd_cpu
44+
def disable_turbo_boost
45+
# Override in subclasses
3946
end
4047

41-
def disable_intel_turbo
42-
return if intel_no_turbo?
48+
def maximize_frequency
49+
# Override in subclasses
50+
end
51+
52+
def check_pstate(turbo:)
53+
# Override in subclasses
54+
end
55+
end
56+
57+
# Intel CPU configuration
58+
class IntelCPUConfig < CPUConfig
59+
private
60+
61+
def disable_turbo_boost
4362
# sudo requires the flag '-S' in order to take input from stdin
4463
BenchmarkRunner.check_call("sudo -S sh -c 'echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo'")
4564
at_exit { BenchmarkRunner.check_call("sudo -S sh -c 'echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo'", quiet: true) }
4665
end
4766

48-
def maximize_intel_frequency
49-
return if intel_perf_100pct?
67+
def maximize_frequency
5068
# Disabling Turbo Boost reduces the CPU frequency, so this should be run after that.
5169
BenchmarkRunner.check_call("sudo -S sh -c 'echo 100 > /sys/devices/system/cpu/intel_pstate/min_perf_pct'")
5270
end
5371

54-
def disable_amd_boost
55-
return if amd_no_boost?
56-
# sudo requires the flag '-S' in order to take input from stdin
57-
BenchmarkRunner.check_call("sudo -S sh -c 'echo 0 > /sys/devices/system/cpu/cpufreq/boost'")
58-
at_exit { BenchmarkRunner.check_call("sudo -S sh -c 'echo 1 > /sys/devices/system/cpu/cpufreq/boost'", quiet: true) }
72+
def turbo_disabled?
73+
@turbo_disabled ||= File.exist?('/sys/devices/system/cpu/intel_pstate/no_turbo') &&
74+
File.read('/sys/devices/system/cpu/intel_pstate/no_turbo').strip == '1'
5975
end
6076

61-
def set_performance_governor
62-
return if performance_governor?
63-
BenchmarkRunner.check_call("sudo -S cpupower frequency-set -g performance")
77+
def frequency_maximized?
78+
@frequency_maximized ||= File.exist?('/sys/devices/system/cpu/intel_pstate/min_perf_pct') &&
79+
File.read('/sys/devices/system/cpu/intel_pstate/min_perf_pct').strip == '100'
6480
end
6581

66-
def intel_no_turbo?
67-
File.exist?('/sys/devices/system/cpu/intel_pstate/no_turbo') &&
68-
File.read('/sys/devices/system/cpu/intel_pstate/no_turbo').strip == '1'
82+
def check_pstate(turbo:)
83+
unless turbo || turbo_disabled?
84+
puts("You forgot to disable turbo:")
85+
puts(" sudo sh -c 'echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo'")
86+
exit(-1)
87+
end
88+
89+
unless frequency_maximized?
90+
puts("You forgot to set the min perf percentage to 100:")
91+
puts(" sudo sh -c 'echo 100 > /sys/devices/system/cpu/intel_pstate/min_perf_pct'")
92+
exit(-1)
93+
end
6994
end
95+
end
7096

71-
def intel_perf_100pct?
72-
File.exist?('/sys/devices/system/cpu/intel_pstate/min_perf_pct') &&
73-
File.read('/sys/devices/system/cpu/intel_pstate/min_perf_pct').strip == '100'
97+
# AMD CPU configuration
98+
class AMDCPUConfig < CPUConfig
99+
private
100+
101+
def disable_turbo_boost
102+
# sudo requires the flag '-S' in order to take input from stdin
103+
BenchmarkRunner.check_call("sudo -S sh -c 'echo 0 > /sys/devices/system/cpu/cpufreq/boost'")
104+
at_exit { BenchmarkRunner.check_call("sudo -S sh -c 'echo 1 > /sys/devices/system/cpu/cpufreq/boost'", quiet: true) }
74105
end
75106

76-
def amd_no_boost?
77-
File.exist?('/sys/devices/system/cpu/cpufreq/boost') &&
107+
def maximize_frequency
108+
BenchmarkRunner.check_call("sudo -S cpupower frequency-set -g performance")
109+
end
110+
111+
def turbo_disabled?
112+
@turbo_disabled ||= File.exist?('/sys/devices/system/cpu/cpufreq/boost') &&
78113
File.read('/sys/devices/system/cpu/cpufreq/boost').strip == '0'
79114
end
80115

81-
def performance_governor?
82-
Dir.glob('/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor').all? do |governor|
116+
def frequency_maximized?
117+
@frequency_maximized ||= Dir.glob('/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor').all? do |governor|
83118
File.read(governor).strip == 'performance'
84119
end
85120
end
86121

87-
# Verify that CPU frequency settings have been configured correctly
88122
def check_pstate(turbo:)
89-
if intel_cpu?
90-
unless turbo || intel_no_turbo?
91-
puts("You forgot to disable turbo:")
92-
puts(" sudo sh -c 'echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo'")
93-
exit(-1)
94-
end
95-
96-
unless intel_perf_100pct?
97-
puts("You forgot to set the min perf percentage to 100:")
98-
puts(" sudo sh -c 'echo 100 > /sys/devices/system/cpu/intel_pstate/min_perf_pct'")
99-
exit(-1)
100-
end
101-
elsif amd_cpu?
102-
unless turbo || amd_no_boost?
103-
puts("You forgot to disable boost:")
104-
puts(" sudo sh -c 'echo 0 > /sys/devices/system/cpu/cpufreq/boost'")
105-
exit(-1)
106-
end
123+
unless turbo || turbo_disabled?
124+
puts("You forgot to disable boost:")
125+
puts(" sudo sh -c 'echo 0 > /sys/devices/system/cpu/cpufreq/boost'")
126+
exit(-1)
127+
end
107128

108-
unless performance_governor?
109-
puts("You forgot to set the performance governor:")
110-
puts(" sudo cpupower frequency-set -g performance")
111-
exit(-1)
112-
end
129+
unless frequency_maximized?
130+
puts("You forgot to set the performance governor:")
131+
puts(" sudo cpupower frequency-set -g performance")
132+
exit(-1)
113133
end
114134
end
115135
end
136+
137+
# Null object for unsupported CPUs
138+
class NullCPUConfig < CPUConfig
139+
private
140+
141+
def disable_frequency_scaling(turbo:)
142+
# Do nothing
143+
end
144+
145+
def check_pstate(turbo:)
146+
# Do nothing
147+
end
148+
end

test/cpu_config_test.rb

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,39 @@
33
require_relative '../lib/benchmark_runner'
44

55
describe CPUConfig do
6+
describe '.build' do
7+
it 'returns IntelCPUConfig when Intel pstate files exist' do
8+
File.stub :exist?, ->(path) { path.include?('intel_pstate') } do
9+
config = CPUConfig.build
10+
assert_instance_of IntelCPUConfig, config
11+
end
12+
end
13+
14+
it 'returns AMDCPUConfig when AMD cpufreq files exist' do
15+
File.stub :exist?, ->(path) { path.include?('cpufreq/boost') } do
16+
config = CPUConfig.build
17+
assert_instance_of AMDCPUConfig, config
18+
end
19+
end
20+
21+
it 'returns NullCPUConfig when no CPU files exist' do
22+
File.stub :exist?, false do
23+
config = CPUConfig.build
24+
assert_instance_of NullCPUConfig, config
25+
end
26+
end
27+
end
28+
end
29+
30+
describe NullCPUConfig do
631
describe '#configure_for_benchmarking' do
732
it 'does nothing when CPU frequency files do not exist' do
833
call_count = 0
934
at_exit_called = false
1035
exit_called = false
1136

1237
File.stub :exist?, false do
13-
cpu_config = CPUConfig.new
38+
cpu_config = NullCPUConfig.new
1439
cpu_config.stub :at_exit, ->(&block) { at_exit_called = true } do
1540
cpu_config.stub :exit, ->(code) { exit_called = true } do
1641
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) { call_count += 1 } do
@@ -25,14 +50,18 @@
2550
end
2651
end
2752
end
53+
end
54+
end
2855

56+
describe IntelCPUConfig do
57+
describe '#configure_for_benchmarking' do
2958
it 'does not call commands or exit when Intel CPU is already properly configured with turbo disabled' do
3059
call_count = 0
3160
at_exit_called = false
3261
exit_called = false
3362

3463
File.stub :exist?, ->(path) { path.include?('intel_pstate') } do
35-
cpu_config = CPUConfig.new
64+
cpu_config = IntelCPUConfig.new
3665
cpu_config.stub :at_exit, ->(&block) { at_exit_called = true } do
3766
cpu_config.stub :exit, ->(code) { exit_called = true } do
3867
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) { call_count += 1 } do
@@ -62,7 +91,7 @@
6291
exit_called = false
6392

6493
File.stub :exist?, ->(path) { path.include?('intel_pstate') } do
65-
cpu_config = CPUConfig.new
94+
cpu_config = IntelCPUConfig.new
6695
cpu_config.stub :at_exit, ->(&block) { at_exit_called = true } do
6796
cpu_config.stub :exit, ->(code) { exit_called = true } do
6897
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) { call_count += 1 } do
@@ -94,7 +123,7 @@
94123
read_count = 0
95124

96125
File.stub :exist?, ->(path) { path.include?('intel_pstate') } do
97-
cpu_config = CPUConfig.new
126+
cpu_config = IntelCPUConfig.new
98127
cpu_config.stub :at_exit, ->(&block) { at_exit_called = true; at_exit_block = block } do
99128
cpu_config.stub :exit, ->(code) { exit_called = true } do
100129
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) { call_count += 1 } do
@@ -138,7 +167,7 @@
138167
exit_code = nil
139168
output = capture_io do
140169
File.stub :exist?, ->(path) { path.include?('intel_pstate') } do
141-
cpu_config = CPUConfig.new
170+
cpu_config = IntelCPUConfig.new
142171
cpu_config.stub :at_exit, ->(&block) {} do
143172
cpu_config.stub :exit, ->(code) { exit_code = code } do
144173
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) {} do
@@ -166,7 +195,7 @@
166195
exit_code = nil
167196
output = capture_io do
168197
File.stub :exist?, ->(path) { path.include?('intel_pstate') } do
169-
cpu_config = CPUConfig.new
198+
cpu_config = IntelCPUConfig.new
170199
cpu_config.stub :at_exit, ->(&block) {} do
171200
cpu_config.stub :exit, ->(code) { exit_code = code } do
172201
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) {} do
@@ -189,14 +218,18 @@
189218
assert_includes output[0], "You forgot to set the min perf percentage to 100"
190219
assert_includes output[0], "sudo sh -c 'echo 100 > /sys/devices/system/cpu/intel_pstate/min_perf_pct'"
191220
end
221+
end
222+
end
192223

224+
describe AMDCPUConfig do
225+
describe '#configure_for_benchmarking' do
193226
it 'does not call commands or exit when AMD CPU is already properly configured with turbo disabled' do
194227
call_count = 0
195228
at_exit_called = false
196229
exit_called = false
197230

198231
File.stub :exist?, ->(path) { path.include?('cpufreq/boost') } do
199-
cpu_config = CPUConfig.new
232+
cpu_config = AMDCPUConfig.new
200233
cpu_config.stub :at_exit, ->(&block) { at_exit_called = true } do
201234
cpu_config.stub :exit, ->(code) { exit_called = true } do
202235
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) { call_count += 1 } do
@@ -230,7 +263,7 @@
230263
read_count = 0
231264

232265
File.stub :exist?, ->(path) { path.include?('cpufreq/boost') } do
233-
cpu_config = CPUConfig.new
266+
cpu_config = AMDCPUConfig.new
234267
cpu_config.stub :at_exit, ->(&block) { at_exit_called = true; at_exit_block = block } do
235268
cpu_config.stub :exit, ->(code) { exit_called = true } do
236269
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) { call_count += 1 } do
@@ -273,7 +306,7 @@
273306
exit_code = nil
274307
output = capture_io do
275308
File.stub :exist?, ->(path) { path.include?('cpufreq/boost') } do
276-
cpu_config = CPUConfig.new
309+
cpu_config = AMDCPUConfig.new
277310
cpu_config.stub :at_exit, ->(&block) {} do
278311
cpu_config.stub :exit, ->(code) { exit_code = code } do
279312
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) {} do
@@ -303,7 +336,7 @@
303336
exit_code = nil
304337
output = capture_io do
305338
File.stub :exist?, ->(path) { path.include?('cpufreq/boost') } do
306-
cpu_config = CPUConfig.new
339+
cpu_config = AMDCPUConfig.new
307340
cpu_config.stub :at_exit, ->(&block) {} do
308341
cpu_config.stub :exit, ->(code) { exit_code = code } do
309342
BenchmarkRunner.stub :check_call, ->(*_args, **_kwargs) {} do

0 commit comments

Comments
 (0)