1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-31 02:01:16 +00:00

instruments/poller: add ftrace marker support

- Add an option to the poller binary insert a marker into ftrace that
  aligns with the first output entry. The option is exposed as an
  instrument parameter.
- If this parameter is set, the resulting .csv will be post-processed to
  update the timestamps to align with trace-cmd output.
- Change poller artifact names to use - instead of _ to be consistent
  with trace-cmd artifact naming.
This commit is contained in:
Sergei Trofimov 2018-01-25 08:22:21 +00:00 committed by Marc Bonnici
parent 1fe899fd7c
commit 902c3c6ace
4 changed files with 90 additions and 17 deletions

View File

@ -14,8 +14,12 @@
# pylint: disable=access-member-before-definition,attribute-defined-outside-init,unused-argument
import os
import pandas as pd
from wa import Instrument, Parameter, Executable
from wa.framework import signal
from wa.framework.exception import ConfigError, InstrumentError
from wa.utils.trace_cmd import TraceCmdParser
from wa.utils.types import list_or_string
@ -38,9 +42,18 @@ class FilePoller(Instrument):
Parameter('files', kind=list_or_string, mandatory=True,
description="""A list of paths to the files to be polled"""),
Parameter('labels', kind=list_or_string,
description="""A list of lables to be used in the CSV output for
the corresponding files. This cannot be used if
a `*` wildcard is used in a path."""),
description="""
A list of lables to be used in the CSV output for the
corresponding files. This cannot be used if a `*` wildcard is
used in a path.
"""),
Parameter('align_with_ftrace', kind=bool, default=False,
description="""
Insert a marker into ftrace that aligns with the first
timestamp. During output processing, extract the marker
and use it's timestamp to adjust the timestamps in the collected
csv so that they align with ftrace.
"""),
Parameter('as_root', kind=bool, default=False,
description="""
Whether or not the poller will be run as root. This should be
@ -74,12 +87,17 @@ class FilePoller(Instrument):
self.target_output_path = self.target.path.join(self.target.working_directory, 'poller.csv')
self.target_log_path = self.target.path.join(self.target.working_directory, 'poller.log')
self.command = '{} -t {} -l {} {} > {} 2>{}'.format(target_poller,
self.sample_interval * 1000,
','.join(self.labels),
' '.join(self.files),
self.target_output_path,
self.target_log_path)
marker_option = ''
if self.align_with_ftrace:
marker_option = '-m'
signal.connect(self._adjust_timestamps, signal.AFTER_JOB_OUTPUT_PROCESSED)
self.command = '{} -t {} {} -l {} {} > {} 2>{}'.format(target_poller,
self.sample_interval * 1000,
marker_option,
','.join(self.labels),
' '.join(self.files),
self.target_output_path,
self.target_log_path)
def start(self, context):
self.target.kick_off(self.command, as_root=self.as_root)
@ -90,10 +108,11 @@ class FilePoller(Instrument):
def update_output(self, context):
host_output_file = os.path.join(context.output_directory, 'poller.csv')
self.target.pull(self.target_output_path, host_output_file)
context.add_artifact('poller_output', host_output_file, kind='data')
context.add_artifact('poller-output', host_output_file, kind='data')
host_log_file = os.path.join(context.output_directory, 'poller.log')
self.target.pull(self.target_log_path, host_log_file)
context.add_artifact('poller_log', host_log_file, kind='log')
context.add_artifact('poller-log', host_log_file, kind='log')
with open(host_log_file) as fh:
for line in fh:
@ -120,3 +139,24 @@ class FilePoller(Instrument):
label_parts.append(pp[-1]) # always use file name even if same for all
labels.append('-'.join(label_parts))
return labels
def _adjust_timestamps(self, context):
output_file = context.get_artifact_path('poller-output')
message = 'Adjusting timestamps inside "{}" to align with ftrace'
self.logger.debug(message.format(output_file))
trace_txt = context.get_artifact_path('trace-cmd-txt')
trace_parser = TraceCmdParser(filter_markers=False)
marker_timestamp = None
for event in trace_parser.parse(trace_txt):
if event.name == 'print' and 'POLLER_START' in event.text:
marker_timestamp = event.timestamp
break
if marker_timestamp is None:
raise InstrumentError('Did not see poller marker in ftrace')
df = pd.read_csv(output_file)
df.time -= df.time[0]
df.time += marker_timestamp
df.to_csv(output_file, index=False)

View File

@ -1,7 +1,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
@ -31,6 +31,23 @@ typedef struct {
char *path;
} poll_source_t;
int write_trace_marker(char *marker, int size)
{
int ret;
FILE *file;
file = fopen("/sys/kernel/debug/tracing/trace_marker", "w");
if (file == NULL) {
return -errno;
}
ret = fwrite(marker, sizeof(char), size, file);
fclose(file);
return ret;
}
int main(int argc, char ** argv) {
extern char *optarg;
@ -40,16 +57,21 @@ int main(int argc, char ** argv) {
useconds_t interval = 1000000;
char buf[1024];
memset(buf, 0, sizeof(buf));
struct timeval current_time;
struct timespec current_time;
double time_float;
char *labels;
int labelCount = 0;
int should_write_marker = 0;
int ret;
static char usage[] = "usage: %s [-h] [-t INTERVAL] FILE [FILE ...]\n"
static char usage[] = "usage: %s [-h] [-m] [-t INTERVAL] FILE [FILE ...]\n"
"polls FILE(s) every INTERVAL microseconds and outputs\n"
"the results in CSV format including a timestamp to STDOUT\n"
"\n"
" -h Display this message\n"
" -m Insert a marker into ftrace at the time of the first\n"
" sample. This marker may be used to align the timestamps\n"
" produced by the poller with those of ftrace events.\n"
" -t The polling sample interval in microseconds\n"
" Defaults to 1000000 (1 second)\n"
" -l Comma separated list of labels to use in the CSV\n"
@ -57,7 +79,7 @@ int main(int argc, char ** argv) {
//Handling command line arguments
while ((c = getopt(argc, argv, "ht:l:")) != -1)
while ((c = getopt(argc, argv, "hmt:l:")) != -1)
{
switch(c) {
case 'h':
@ -65,6 +87,9 @@ int main(int argc, char ** argv) {
default:
show_help = 1;
break;
case 'm':
should_write_marker = 1;
break;
case 't':
interval = (useconds_t)atoi(optarg);
break;
@ -131,9 +156,17 @@ int main(int argc, char ** argv) {
//Poll files
int bytes_read = 0;
while (!done) {
gettimeofday(&current_time, NULL);
clock_gettime(CLOCK_BOOTTIME, &current_time);
if (should_write_marker) {
ret = write_trace_marker("POLLER_START", 12);
if (ret < 0) {
fprintf(stderr, "ERROR writing trace marker: %s\n", strerror(ret));
exit(ret);
}
}
time_float = (double)current_time.tv_sec;
time_float += ((double)current_time.tv_usec)/1000/1000;
time_float += ((double)current_time.tv_nsec)/1000/1000/1000;
printf("%f", time_float);
for (i = 0; i < num_files; i++) {
lseek(files_to_poll[i].fd, 0, SEEK_SET);