Skip to content

Commit 4c0a877

Browse files
Merge pull request #276 from KernelTuner/pmt_continuous_observer
base implementation for pmt continuous observer
2 parents 0b5fffc + 0a96c86 commit 4c0a877

File tree

1 file changed

+57
-2
lines changed

1 file changed

+57
-2
lines changed

kernel_tuner/observers/pmt.py

+57-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import numpy as np
22

3-
from kernel_tuner.observers.observer import BenchmarkObserver
3+
from kernel_tuner.observers.observer import BenchmarkObserver, ContinuousObserver
44

55
# check if pmt is installed
66
try:
@@ -28,9 +28,25 @@ class PMTObserver(BenchmarkObserver):
2828
2929
:type observables: string,list/dictionary
3030
31+
32+
:param use_continuous_observer:
33+
Boolean to control whether or not to measure power/energy using
34+
Kernel Tuner's continuous benchmarking mode. This improves measurement
35+
accuracy when using internal power sensors, such as NVML or ROCM,
36+
which have limited sampling frequency and might return averages
37+
instead of instantaneous power readings. Default value: False.
38+
39+
:type use_continuous_observer: boolean
40+
41+
42+
:param continuous_duration:
43+
Number of seconds to measure continuously for.
44+
45+
:type continuous_duration: scalar
46+
3147
"""
3248

33-
def __init__(self, observable=None):
49+
def __init__(self, observable=None, use_continuous_observer=False, continuous_duration=1):
3450
if not pmt:
3551
raise ImportError("could not import pmt")
3652

@@ -54,6 +70,9 @@ def __init__(self, observable=None):
5470
self.begin_states = [None] * len(self.pms)
5571
self.initialize_results(self.pm_names)
5672

73+
if use_continuous_observer:
74+
self.continuous_observer = PMTContinuousObserver("pmt", [], self, continuous_duration=continuous_duration)
75+
5776
def initialize_results(self, pm_names):
5877
self.results = dict()
5978
for pm_name in pm_names:
@@ -82,3 +101,39 @@ def get_results(self):
82101
averages = {key: np.average(values) for key, values in self.results.items()}
83102
self.initialize_results(self.pm_names)
84103
return averages
104+
105+
106+
class PMTContinuousObserver(ContinuousObserver):
107+
"""Generic observer that measures power while and continuous benchmarking.
108+
109+
To support continuous benchmarking an Observer should support:
110+
a .read_power() method, which the ContinuousObserver can call to read power in Watt
111+
"""
112+
def before_start(self):
113+
""" Override default method in ContinuousObserver """
114+
pass
115+
116+
def after_start(self):
117+
self.parent.after_start()
118+
119+
def during(self):
120+
""" Override default method in ContinuousObserver """
121+
pass
122+
123+
def after_finish(self):
124+
self.parent.after_finish()
125+
126+
def get_results(self):
127+
average_kernel_execution_time_ms = self.results["time"]
128+
129+
averages = {key: np.average(values) for key, values in self.results.items()}
130+
self.parent.initialize_results(self.parent.pm_names)
131+
132+
# correct energy measurement, because current _energy number is collected over the entire duration
133+
# we estimate energy as the average power over the continuous duration times the kernel execution time
134+
for pm_name in self.parent.pm_names:
135+
energy_result_name = f"{pm_name}_energy"
136+
power_result_name = f"{pm_name}_power"
137+
averages[energy_result_name] = averages[power_result_name] * (average_kernel_execution_time_ms / 1e3)
138+
139+
return averages

0 commit comments

Comments
 (0)