mirror of
				https://github.com/ARM-software/workload-automation.git
				synced 2025-11-04 09:02:12 +00:00 
			
		
		
		
	Poller: Added an instrument to poll files and output a csv of their values
This commit is contained in:
		
							
								
								
									
										105
									
								
								wlauto/instrumentation/poller/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								wlauto/instrumentation/poller/__init__.py
									
									
									
									
									
										Normal 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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								wlauto/instrumentation/poller/bin/arm64/poller
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wlauto/instrumentation/poller/bin/arm64/poller
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								wlauto/instrumentation/poller/bin/armeabi/poller
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wlauto/instrumentation/poller/bin/armeabi/poller
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										132
									
								
								wlauto/instrumentation/poller/poller.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								wlauto/instrumentation/poller/poller.c
									
									
									
									
									
										Normal 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(¤t_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);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user