1
0
mirror of https://github.com/ARM-software/devlib.git synced 2024-10-06 10:50:51 +01:00

Merge pull request #134 from qperret/gem5stats-instru

instrument: Add power monitoring support on Gem5 platforms
This commit is contained in:
setrofim 2017-07-10 12:59:37 +01:00 committed by GitHub
commit 3f1a1c4086
3 changed files with 103 additions and 12 deletions

View File

@ -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

View 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()

View File

@ -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):
'''