1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-02-20 20:09:11 +00:00

Merge pull request #164 from ep1cman/poller

Poller: Added an instrument to poll files and output a csv of their v…
This commit is contained in:
setrofim 2016-05-26 16:33:59 +01:00
commit 6e4f6af942
5 changed files with 242 additions and 7 deletions

View File

@ -446,22 +446,20 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223
else:
return adb_shell(self.adb_name, command, timeout, check_exit_code, as_root)
def kick_off(self, command, as_root=True):
def kick_off(self, command, as_root=None):
"""
Like execute but closes adb session and returns immediately, leaving the command running on the
device (this is different from execute(background=True) which keeps adb connection open and returns
a subprocess object).
.. note:: This relies on busybox's nohup applet and so won't work on unrooted devices.
Added in version 2.1.4
"""
if not self.is_rooted or not as_root:
raise DeviceError('kick_off uses busybox\'s nohup applet and so can only be run a rooted device.')
if as_root is None:
as_root = self.is_rooted
try:
command = 'cd {} && busybox nohup {}'.format(self.working_directory, command)
output = self.execute(command, timeout=1, as_root=True)
command = 'cd {} && {} nohup {}'.format(self.working_directory, self.busybox, command)
output = self.execute(command, timeout=1, as_root=as_root)
except TimeoutError:
pass
else:

View File

@ -0,0 +1,105 @@
# Copyright 2015 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.
# pylint: disable=access-member-before-definition,attribute-defined-outside-init,unused-argument
from wlauto import Instrument, Parameter, Executable
from wlauto.exceptions import ConfigError
from wlauto.utils.types import list_or_string
class FilePoller(Instrument):
name = 'file_poller'
description = """
Polls the given files at a set sample interval. The values are output in CSV format.
This instrument places a file called poller.csv in each iterations result directory.
This file will contain a timestamp column which will be in uS, the rest of the columns
will be the contents of the polled files at that time.
This instrument can poll any file whos contents do not contain a new line since this
breaks the CSV formatting.
"""
parameters = [
Parameter('sample_interval', kind=int, default=1000,
description="""The interval between samples in mS."""),
Parameter('files', kind=list_or_string,
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."""),
Parameter('as_root', kind=bool, default=False,
description="""
Whether or not the poller will be run as root. This should be
used when the file you need to poll can only be accessed by root.
"""),
]
def validate(self):
if not self.device.is_rooted and self.as_root:
raise ConfigError('The device is not rooted, cannot run poller as root.')
if self.labels and any(['*' in f for f in self.files]):
raise ConfigError('You cannot used manual labels with `*` wildcards')
def initialize(self, context):
host_poller = context.resolver.get(Executable(self, self.device.abi,
"poller"))
target_poller = self.device.install_if_needed(host_poller)
expanded_paths = []
for path in self.files:
if "*" in path:
for p in self.device.listdir(path):
expanded_paths.append(p)
else:
expanded_paths.append(path)
self.files = expanded_paths
if not self.labels:
self.labels = self._generate_labels()
self.target_output_path = self.device.path.join(self.device.working_directory, 'poller.csv')
self.command = '{} -t {} -l {} {} > {}'.format(target_poller,
self.sample_interval * 1000,
','.join(self.labels),
' '.join(self.files),
self.target_output_path)
def start(self, context):
self.device.kick_off(self.command, as_root=self.as_root)
def stop(self, context):
self.device.killall('poller', signal='TERM', as_root=self.as_root)
def update_result(self, context):
self.device.pull_file(self.target_output_path, context.output_directory)
def teardown(self, context):
self.device.delete_file(self.target_output_path)
def _generate_labels(self):
# Split paths into their parts
path_parts = [f.split(self.device.path.sep) for f in self.files]
# Identify which parts differ between at least two of the paths
differ_map = [len(set(x)) > 1 for x in zip(*path_parts)]
# compose labels from path parts that differ
labels = []
for pp in path_parts:
label_parts = [p for i, p in enumerate(pp[:-1])
if i >= len(differ_map) or differ_map[i]]
label_parts.append(pp[-1]) # always use file name even if same for all
labels.append('-'.join(label_parts))
return labels

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,132 @@
#include <fcntl.h>
#include <stdio.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
volatile sig_atomic_t done = 0;
void term(int signum)
{
done = 1;
}
int main(int argc, char ** argv) {
extern char *optarg;
extern int optind;
int c = 0;
int show_help = 0;
useconds_t interval = 1000000;
char buf[1024];
memset(buf, 0, sizeof(buf));
struct timeval current_time;
double time_float;
int files_to_poll[argc-optind];
char *labels;
int labelCount = 0;
static char usage[] = "usage: %s [-h] [-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"
" -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"
" output. This should match the number of files\n";
//Handling command line arguments
while ((c = getopt(argc, argv, "ht:l:")) != -1)
{
switch(c) {
case 'h':
case '?':
default:
show_help = 1;
break;
case 't':
interval = (useconds_t)atoi(optarg);
break;
case 'l':
labels = optarg;
labelCount = 1;
int i;
for (i=0; labels[i]; i++)
labelCount += (labels[i] == ',');
}
}
if (show_help) {
fprintf(stderr, usage, argv[0]);
exit(1);
}
if (optind >= argc) {
fprintf(stderr, "%s: missiing file path(s)\n", argv[0]);
fprintf(stderr, usage, argv[0]);
exit(1);
}
if (labelCount && labelCount != argc-optind)
{
fprintf(stderr, "%s: %d labels specified but %d files specified\n", argv[0],
labelCount,
argc-optind);
fprintf(stderr, usage, argv[0]);
exit(1);
}
//Print headers and open files to poll
printf("time");
if(labelCount)
{
printf(",%s", labels);
}
int i;
for (i = 0; i < (argc - optind); i++)
{
files_to_poll[i] = open(argv[optind + i], O_RDONLY);
if(!labelCount) {
printf(",%s", argv[optind + i]);
}
}
printf("\n");
//Setup SIGTERM handler
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = term;
sigaction(SIGTERM, &action, NULL);
//Poll files
while (!done) {
gettimeofday(&current_time, NULL);
time_float = (double)current_time.tv_sec;
time_float += ((double)current_time.tv_usec)/1000/1000;
printf("%f", time_float);
for (i = 0; i < (argc - optind); i++) {
read(files_to_poll[i], buf, 1024);
lseek(files_to_poll[i], 0, SEEK_SET);
//Removes trailing "\n"
int new_line = strlen(buf) -1;
if (buf[new_line] == '\n')
buf[new_line] = '\0';
printf(",%s", buf);
}
printf("\n");
usleep(interval);
}
//Close files
for (i = 0; i < (argc - optind); i++)
{
files_to_poll[i] = open(argv[optind + i], O_RDONLY);
}
exit(0);
}