mirror of
https://github.com/ARM-software/devlib.git
synced 2025-01-31 02:00:45 +00:00
instrument/daq: Add an explicit time column to the DAQ measurements
Add the monotonic clock time to the energy measurements to help correlate the measurement with those of other collectors, like FtraceCollector or LogcatCollector.
This commit is contained in:
parent
72ded188fa
commit
92e16ee873
BIN
devlib/bin/arm64/get_clock_monotonic
Executable file
BIN
devlib/bin/arm64/get_clock_monotonic
Executable file
Binary file not shown.
BIN
devlib/bin/armeabi/get_clock_monotonic
Executable file
BIN
devlib/bin/armeabi/get_clock_monotonic
Executable file
Binary file not shown.
@ -16,8 +16,10 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import time
|
||||||
from itertools import chain, zip_longest
|
from itertools import chain, zip_longest
|
||||||
|
|
||||||
|
from devlib.host import PACKAGE_BIN_DIRECTORY
|
||||||
from devlib.instrument import Instrument, MeasurementsCsv, CONTINUOUS
|
from devlib.instrument import Instrument, MeasurementsCsv, CONTINUOUS
|
||||||
from devlib.exception import HostError
|
from devlib.exception import HostError
|
||||||
from devlib.utils.csvutil import csvwriter, create_reader
|
from devlib.utils.csvutil import csvwriter, create_reader
|
||||||
@ -45,7 +47,8 @@ class DaqInstrument(Instrument):
|
|||||||
dv_range=0.2,
|
dv_range=0.2,
|
||||||
sample_rate_hz=10000,
|
sample_rate_hz=10000,
|
||||||
channel_map=(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23),
|
channel_map=(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23),
|
||||||
keep_raw=False
|
keep_raw=False,
|
||||||
|
time_as_clock_monotonic=True
|
||||||
):
|
):
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
super(DaqInstrument, self).__init__(target)
|
super(DaqInstrument, self).__init__(target)
|
||||||
@ -53,6 +56,7 @@ class DaqInstrument(Instrument):
|
|||||||
self._need_reset = True
|
self._need_reset = True
|
||||||
self._raw_files = []
|
self._raw_files = []
|
||||||
self.tempdir = None
|
self.tempdir = None
|
||||||
|
self.target_monotonic_clock_at_start = 0.0
|
||||||
if DaqClient is None:
|
if DaqClient is None:
|
||||||
raise HostError('Could not import "daqpower": {}'.format(import_error_mesg))
|
raise HostError('Could not import "daqpower": {}'.format(import_error_mesg))
|
||||||
if labels is None:
|
if labels is None:
|
||||||
@ -76,11 +80,30 @@ class DaqInstrument(Instrument):
|
|||||||
channel_map=channel_map,
|
channel_map=channel_map,
|
||||||
labels=labels)
|
labels=labels)
|
||||||
self.sample_rate_hz = sample_rate_hz
|
self.sample_rate_hz = sample_rate_hz
|
||||||
|
self.time_as_clock_monotonic = time_as_clock_monotonic
|
||||||
|
|
||||||
|
self.add_channel('Time', 'time')
|
||||||
for label in labels:
|
for label in labels:
|
||||||
for kind in ['power', 'voltage']:
|
for kind in ['power', 'voltage']:
|
||||||
self.add_channel(label, kind)
|
self.add_channel(label, kind)
|
||||||
|
|
||||||
|
if time_as_clock_monotonic:
|
||||||
|
host_path = os.path.join(PACKAGE_BIN_DIRECTORY, self.target.abi,
|
||||||
|
'get_clock_monotonic')
|
||||||
|
self.clock_monotonic_cmd = self.target.install_if_needed(host_path,
|
||||||
|
search_system_binaries=False)
|
||||||
|
|
||||||
|
def calculate_monotonic_offset(self):
|
||||||
|
time_before = time.time()
|
||||||
|
out = self.target.execute(self.clock_monotonic_cmd)
|
||||||
|
time_after = time.time()
|
||||||
|
|
||||||
|
remote_clock_monotonic = float(out)
|
||||||
|
propagation_delay = (time_after - time_before) / 2
|
||||||
|
monotonic_at_end = remote_clock_monotonic + propagation_delay
|
||||||
|
|
||||||
|
return time_after - monotonic_at_end
|
||||||
|
|
||||||
def reset(self, sites=None, kinds=None, channels=None):
|
def reset(self, sites=None, kinds=None, channels=None):
|
||||||
super(DaqInstrument, self).reset(sites, kinds, channels)
|
super(DaqInstrument, self).reset(sites, kinds, channels)
|
||||||
self.daq_client.close()
|
self.daq_client.close()
|
||||||
@ -90,9 +113,19 @@ class DaqInstrument(Instrument):
|
|||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if self._need_reset:
|
if self._need_reset:
|
||||||
self.reset()
|
# Preserve channel order
|
||||||
|
self.reset(channels=self.channels.keys())
|
||||||
|
|
||||||
|
if self.time_as_clock_monotonic:
|
||||||
|
target_monotonic_offset = self.calculate_monotonic_offset()
|
||||||
|
time_start = time.time()
|
||||||
|
|
||||||
self.daq_client.start()
|
self.daq_client.start()
|
||||||
|
|
||||||
|
if self.time_as_clock_monotonic:
|
||||||
|
time_end = time.time()
|
||||||
|
self.target_monotonic_clock_at_start = (time_start + time_end) / 2 - target_monotonic_offset
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.daq_client.stop()
|
self.daq_client.stop()
|
||||||
self._need_reset = True
|
self._need_reset = True
|
||||||
@ -118,11 +151,12 @@ class DaqInstrument(Instrument):
|
|||||||
site_readers[site] = reader
|
site_readers[site] = reader
|
||||||
file_handles.append(fh)
|
file_handles.append(fh)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
message = 'Could not get DAQ trace for {}; Obtained traces are in {}'
|
if not site.startswith("Time"):
|
||||||
raise HostError(message.format(site, self.tempdir))
|
message = 'Could not get DAQ trace for {}; Obtained traces are in {}'
|
||||||
|
raise HostError(message.format(site, self.tempdir))
|
||||||
|
|
||||||
# The first row is the headers
|
# The first row is the headers
|
||||||
channel_order = []
|
channel_order = ['Time_time']
|
||||||
for site, reader in site_readers.items():
|
for site, reader in site_readers.items():
|
||||||
channel_order.extend(['{}_{}'.format(site, kind)
|
channel_order.extend(['{}_{}'.format(site, kind)
|
||||||
for kind in next(reader)])
|
for kind in next(reader)])
|
||||||
@ -131,7 +165,11 @@ class DaqInstrument(Instrument):
|
|||||||
row_iter = zip_longest(*site_readers.values(), fillvalue=(None, None))
|
row_iter = zip_longest(*site_readers.values(), fillvalue=(None, None))
|
||||||
for raw_row in row_iter:
|
for raw_row in row_iter:
|
||||||
raw_row = list(chain.from_iterable(raw_row))
|
raw_row = list(chain.from_iterable(raw_row))
|
||||||
|
raw_row.insert(0, _read_rows.row_time_s)
|
||||||
yield raw_row
|
yield raw_row
|
||||||
|
_read_rows.row_time_s += 1.0 / self.sample_rate_hz
|
||||||
|
|
||||||
|
_read_rows.row_time_s = self.target_monotonic_clock_at_start
|
||||||
|
|
||||||
with csvwriter(outfile) as writer:
|
with csvwriter(outfile) as writer:
|
||||||
field_names = [c.label for c in self.active_channels]
|
field_names = [c.label for c in self.active_channels]
|
||||||
|
6
src/get_clock_monotonic/Makefile
Normal file
6
src/get_clock_monotonic/Makefile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
CFLAGS=-Wall --pedantic-errors -O2 -static
|
||||||
|
|
||||||
|
all: get_clock_monotonic
|
||||||
|
|
||||||
|
get_clock_monotonic: get_clock_monotonic.c
|
||||||
|
$(CC) $(CFLAGS) $^ -o $@
|
18
src/get_clock_monotonic/get_clock_monotonic.c
Normal file
18
src/get_clock_monotonic/get_clock_monotonic.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int ret;
|
||||||
|
struct timespec tp;
|
||||||
|
|
||||||
|
ret = clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||||
|
if (ret) {
|
||||||
|
perror("clock_gettime()");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%ld.%ld\n", tp.tv_sec, tp.tv_nsec);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user