mirror of
https://github.com/ARM-software/devlib.git
synced 2025-01-31 10:10:46 +00:00
Merge pull request #134 from qperret/gem5stats-instru
instrument: Add power monitoring support on Gem5 platforms
This commit is contained in:
commit
3f1a1c4086
@ -17,6 +17,7 @@ from devlib.instrument.frames import GfxInfoFramesInstrument
|
||||
from devlib.instrument.hwmon import HwmonInstrument
|
||||
from devlib.instrument.monsoon import MonsoonInstrument
|
||||
from devlib.instrument.netstats import NetstatsInstrument
|
||||
from devlib.instrument.gem5power import Gem5PowerInstrument
|
||||
|
||||
from devlib.trace.ftrace import FtraceCollector
|
||||
|
||||
|
74
devlib/instrument/gem5power.py
Normal file
74
devlib/instrument/gem5power.py
Normal file
@ -0,0 +1,74 @@
|
||||
# Copyright 2017 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import division
|
||||
import csv
|
||||
import re
|
||||
|
||||
from devlib.platform.gem5 import Gem5SimulationPlatform
|
||||
from devlib.instrument import Instrument, CONTINUOUS, MeasurementsCsv
|
||||
from devlib.exception import TargetError, HostError
|
||||
|
||||
|
||||
class Gem5PowerInstrument(Instrument):
|
||||
'''
|
||||
Instrument enabling power monitoring in gem5
|
||||
'''
|
||||
|
||||
mode = CONTINUOUS
|
||||
roi_label = 'power_instrument'
|
||||
|
||||
def __init__(self, target, power_sites):
|
||||
'''
|
||||
Parameter power_sites is a list of gem5 identifiers for power values.
|
||||
One example of such a field:
|
||||
system.cluster0.cores0.power_model.static_power
|
||||
'''
|
||||
if not isinstance(target.platform, Gem5SimulationPlatform):
|
||||
raise TargetError('Gem5PowerInstrument requires a gem5 platform')
|
||||
if not target.has('gem5stats'):
|
||||
raise TargetError('Gem5StatsModule is not loaded')
|
||||
super(Gem5PowerInstrument, self).__init__(target)
|
||||
|
||||
# power_sites is assumed to be a list later
|
||||
if isinstance(power_sites, list):
|
||||
self.power_sites = power_sites
|
||||
else:
|
||||
self.power_sites = [power_sites]
|
||||
self.add_channel('sim_seconds', 'time')
|
||||
for field in self.power_sites:
|
||||
self.add_channel(field, 'power')
|
||||
self.target.gem5stats.book_roi(self.roi_label)
|
||||
self.sample_period_ns = 10000000
|
||||
self.target.gem5stats.start_periodic_dump(0, self.sample_period_ns)
|
||||
|
||||
def start(self):
|
||||
self.target.gem5stats.roi_start(self.roi_label)
|
||||
|
||||
def stop(self):
|
||||
self.target.gem5stats.roi_end(self.roi_label)
|
||||
|
||||
def get_data(self, outfile):
|
||||
active_sites = [c.site for c in self.active_channels]
|
||||
with open(outfile, 'wb') as wfh:
|
||||
writer = csv.writer(wfh)
|
||||
writer.writerow([c.label for c in self.active_channels]) # headers
|
||||
for rec, rois in self.target.gem5stats.match_iter(active_sites, [self.roi_label]):
|
||||
writer.writerow([float(rec[s]) for s in active_sites])
|
||||
return MeasurementsCsv(outfile, self.active_channels)
|
||||
|
||||
def reset(self, sites=None, kinds=None, channels=None):
|
||||
super(Gem5PowerInstrument, self).reset(sites, kinds, channels)
|
||||
self.target.gem5stats.reset_origin()
|
||||
|
@ -28,6 +28,7 @@ class Gem5ROI:
|
||||
self.target = target
|
||||
self.number = number
|
||||
self.running = False
|
||||
self.field = 'ROI::{}'.format(number)
|
||||
|
||||
def start(self):
|
||||
if self.running:
|
||||
@ -42,7 +43,7 @@ class Gem5ROI:
|
||||
self.target.execute('m5 roiend {}'.format(self.number))
|
||||
self.running = False
|
||||
return True
|
||||
|
||||
|
||||
class Gem5StatsModule(Module):
|
||||
'''
|
||||
Module controlling Region of Interest (ROIs) markers, satistics dump
|
||||
@ -56,7 +57,7 @@ class Gem5StatsModule(Module):
|
||||
|
||||
@staticmethod
|
||||
def probe(target):
|
||||
return isinstance(target.platform, Gem5SimulationPlatform)
|
||||
return isinstance(target.platform, Gem5SimulationPlatform)
|
||||
|
||||
def __init__(self, target):
|
||||
super(Gem5StatsModule, self).__init__(target)
|
||||
@ -109,6 +110,22 @@ class Gem5StatsModule(Module):
|
||||
in-order list of records for the key under consideration during the
|
||||
active intervals of the ROI.
|
||||
|
||||
Keys must match fields in gem5's statistics log file. Key example:
|
||||
system.cluster0.cores0.power_model.static_power
|
||||
'''
|
||||
records = defaultdict(lambda : defaultdict(list))
|
||||
for record, active_rois in self.match_iter(keys, rois_labels):
|
||||
for key in record:
|
||||
for roi_label in active_rois:
|
||||
records[key][roi_label].append(record[key])
|
||||
return records
|
||||
|
||||
def match_iter(self, keys, rois_labels):
|
||||
'''
|
||||
Yields for each dump since origin a pair containing:
|
||||
1. a dict storing the values corresponding to each of the specified keys
|
||||
2. the list of currently active ROIs among those passed as parameters.
|
||||
|
||||
Keys must match fields in gem5's statistics log file. Key example:
|
||||
system.cluster0.cores0.power_model.static_power
|
||||
'''
|
||||
@ -118,20 +135,19 @@ class Gem5StatsModule(Module):
|
||||
if self.rois[label].running:
|
||||
self.logger.warning('Trying to match records in statistics file'
|
||||
' while ROI {} is running'.format(label))
|
||||
|
||||
def roi_active(roi_label, dump):
|
||||
roi = self.rois[roi_label]
|
||||
return (roi.field in dump) and (int(dump[roi.field]) == 1)
|
||||
|
||||
records = {}
|
||||
for key in keys:
|
||||
records[key] = defaultdict(list)
|
||||
with open(self._stats_file_path, 'r') as stats_file:
|
||||
stats_file.seek(self._current_origin)
|
||||
for dump in iter_statistics_dump(stats_file):
|
||||
for label in rois_labels:
|
||||
# Save records only when ROIs are ON
|
||||
roi_field = 'ROI::{}'.format(self.rois[label].number)
|
||||
if (roi_field in dump) and (int(dump[roi_field]) == 1):
|
||||
for key in keys:
|
||||
records[key][label].append(dump[key])
|
||||
return records
|
||||
active_rois = [l for l in rois_labels if roi_active(l, dump)]
|
||||
if active_rois:
|
||||
record = {k: dump[k] for k in keys}
|
||||
yield (record, active_rois)
|
||||
|
||||
|
||||
def reset_origin(self):
|
||||
'''
|
||||
|
Loading…
x
Reference in New Issue
Block a user