├── .gitignore ├── LICENSE ├── README.md ├── conf └── events_example.conf └── src ├── Makefile ├── config.c ├── config.h ├── quickhpc.c └── test_reset_counters.c /.gitignore: -------------------------------------------------------------------------------- 1 | papi-5.4.1 2 | quickhpc 3 | papi-examples 4 | papi_avail_output.txt 5 | *.o 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) Marco Chiappetta (chpmrc) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Why this tool? 2 | 3 | You could use `perf-stat` (included in Linux) but its minimum resolution is 100 ms. This tool reached a resolution of 3 microseconds in some cases. More than 30000 times faster! I used this tool for some of my projects and even though it is extremely simple I could not find anything similar online (suggestions are welcome). So here it is. 4 | 5 | # Build 6 | 7 | * Download and untar [PAPI](http://icl.cs.utk.edu/papi/) 8 | * Set the right path to PAPI's folder in the `Makefile` (variable `PAPI_DIR`) 9 | * Build PAPI (`./configure; make` is enough) 10 | * Run `make` 11 | 12 | That's it! 13 | 14 | # Usage 15 | 16 | `./quickhpc OPTIONS` 17 | 18 | where `OPTIONS` can be: 19 | 20 | * `-c` Path to the file that contains the list of events (one per line) to monitor (make sure they are available by running `papi_avail`) 21 | * `-a` PID of the process to attach to 22 | * `-n` Number of iterations, each iteration lasts the duration of an interval 23 | * `-i` Interval for each measurement (i.e. time between then the hpc is start and stopped) in the order of microseconds 24 | 25 | The output of the program is organized as CSV data complete with headers and (for the time being) some debug prints at the top. An example follows: 26 | 27 | Using config file: /home/user/events.conf 28 | Monitoring the following events: 29 | PAPI_TOT_INS 30 | PAPI_L3_TCM 31 | PAPI_L3_TCA 32 | Monitoring for 10000 iterations 33 | Attaching to PID: 5403 34 | PAPI_TOT_INS,PAPI_L3_TCM,PAPI_L3_TCA 35 | 142948,9,307 36 | 128214,9,266 37 | 78173,69,363 38 | 124587,32,168 39 | 116464,38,209 40 | 126420,28,177 41 | 126188,27,133 42 | 118189,41,170 43 | 127132,25,179 44 | 130775,28,144 45 | ... 46 | 47 | A sane, standard format. 48 | 49 | # Example 50 | 51 | * Collect data during an openssl signature for 1000 iterations (each iteration is as fast as `papi_clockres` reports): 52 | 53 | `openssl dgst -sha1 -sign test_data/private.pem test_data/test.pdf & quickhpc -a ${!} -c ~/papi/events.conf -n 10000 > data` 54 | 55 | * Collect data about process 1234 for 100 iterations of 100 ms each: 56 | 57 | `quickhpc -a 1234 -n 100 -i 100000 -c my_events.conf` 58 | 59 | # Events file 60 | 61 | A simple file with the names of the events you want to monitor (you can retrieve the complete list of supported events by running `papi_avail`). 62 | 63 | ## Example 64 | 65 | PAPI_TOT_INS 66 | PAPI_L3_TCM 67 | PAPI_L3_TCA 68 | 69 | Is used to retrieve total CPU instructions, total L3 cache misses and total L3 cache accesses. 70 | -------------------------------------------------------------------------------- /conf/events_example.conf: -------------------------------------------------------------------------------- 1 | PAPI_TOT_INS 2 | PAPI_TOT_CYC 3 | PAPI_L3_TCA 4 | PAPI_L3_TCM 5 | PAPI_L2_TCA 6 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | PROGRAM=quickhpc 3 | PAPI_DIR=../../papi/src 4 | LIBS_STATIC=${PAPI_DIR}/libpapi.a 5 | OBJS=config.o 6 | EXTERNAL_OBJS=${PAPI_DIR}/testlib/do_loops.o \ 7 | ${PAPI_DIR}/testlib/test_utils.o \ 8 | # ${PAPI_DIR}/testlib/dummy.o 9 | INC=-I${PAPI_DIR} -I${PAPI_DIR} -I${PAPI_DIR}/testlib 10 | 11 | 12 | all: config 13 | ${CC} ${DEBUG_FLAG} ${INC} -g -Wall ${PROGRAM}.c \ 14 | ${EXTERNAL_OBJS} \ 15 | ${LIBS_STATIC} \ 16 | ${OBJS} -o ../${PROGRAM} 17 | 18 | debug: CC += -D_DEBUG 19 | debug: all 20 | 21 | config: 22 | ${CC} ${INC} -g -c config.c 23 | 24 | clean: 25 | -rm ../${PROGRAM} 26 | -rm ${OBJS} 27 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "config.h" 6 | 7 | bool attach; // True if the monitor has to attach to a given PID 8 | bool run; // True if the monitor has to start the command given as argument 9 | char cmd[MAX_CMD_SIZE]; // The command to be run if run is true 10 | int pid; 11 | 12 | void reset_config(config *cfg) { 13 | cfg->attach = false; 14 | cfg->run = false; // TODO not used 15 | cfg->pid = -128; 16 | cfg->numEvents = 0; 17 | cfg->interval = 0; // As fast as possible 18 | cfg->iterations = -1; // Infinite 19 | } 20 | 21 | void readEventNames(char *filePath, config *cfg) { 22 | int i = 0; 23 | size_t len = 0; 24 | FILE *fp; 25 | char *tempStr; 26 | fp = fopen(filePath, "r"); 27 | if (fp == NULL) { 28 | perror("Configuration file error:"); 29 | exit(1); 30 | } 31 | while (getline(&tempStr, &len, fp) != -1){ 32 | if (tempStr[0] != '#') { 33 | strncpy(cfg->events[i], tempStr, strlen(tempStr) - 1); // Remove final LF 34 | cfg->events[i][strlen(tempStr) - 1] = '\0'; 35 | i++; 36 | } 37 | } 38 | free(tempStr); 39 | cfg->numEvents = i; 40 | // Test 41 | fprintf(stderr, "Monitoring %d events:\n", cfg->numEvents); 42 | for (i = 0; i < cfg->numEvents; i++) { 43 | fprintf(stderr, "%s\n", cfg->events[i]); 44 | } 45 | fprintf(stderr, "\n"); 46 | fclose(fp); 47 | } 48 | 49 | void setup_config(int argc, char **argv, config *cfg) { 50 | int i = 1; 51 | char configFilePath[MAX_PATH_CHAR_SIZE]; 52 | int interval = 0; 53 | char iterations[MAX_STR_LEN] = "infinite"; 54 | reset_config(cfg); 55 | for (; i < argc; i++) { 56 | // Attached PID 57 | if (!strcmp(argv[i], "-a")) { 58 | cfg->attach = true; 59 | cfg->pid = atoi(argv[i+1]); 60 | } else 61 | // Configuration file 62 | if (!strcmp(argv[i], "-c")) { 63 | strcpy(configFilePath, argv[i+1]); 64 | fprintf(stderr, "Using config file: %s\n", configFilePath); 65 | readEventNames(configFilePath, cfg); 66 | } else 67 | if (!strcmp(argv[i], "-i")) { 68 | interval = atoi(argv[i+1]); 69 | fprintf(stderr, "Using interval: %d usec\n", interval); 70 | cfg->interval = interval; 71 | } else 72 | if (!strcmp(argv[i], "-n")) { 73 | if (atoi(argv[i]) > -1) 74 | strcpy(iterations, argv[i+1]); 75 | fprintf(stderr, "Monitoring for %s iterations\n", iterations); 76 | cfg->iterations = atoi(iterations); 77 | } else 78 | // Run new process 79 | if (!strcmp(argv[i], "-r")) { 80 | cfg->run = true; 81 | } else { 82 | if (i == 0){ 83 | // The first argument must be an option 84 | fprintf(stderr, "The first argument must be an option! (E.g. -a, -r).\n"); 85 | exit(1); 86 | } 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H 2 | #define _CONFIG_H 3 | 4 | #include "papi_test.h" 5 | #include "papi.h" 6 | 7 | #define bool int 8 | #define true 1 9 | #define false 0 10 | #define MAX_CMD_SIZE 2048 11 | #define MAX_EVENTS 50 12 | #define MAX_STR_LEN PAPI_MAX_STR_LEN 13 | #define MAX_PATH_CHAR_SIZE 4096 14 | 15 | typedef struct config_struct { 16 | bool attach; // True if the monitor has to attach to a given PID 17 | bool run; // True if the monitor has to start the command given as argument 18 | char cmd[MAX_CMD_SIZE]; // The command to be run if run is true 19 | int pid; 20 | int numEvents; 21 | char events[MAX_EVENTS][MAX_STR_LEN]; 22 | int interval; 23 | int iterations; 24 | } config; 25 | 26 | /** 27 | * @brief Build the config from the given parameters. 28 | */ 29 | void setup_config(int, char **, config *); 30 | 31 | void reset_config(config *); 32 | 33 | 34 | #endif // #CONFIG_H 35 | -------------------------------------------------------------------------------- /src/quickhpc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "config.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef _AIX 11 | #define _LINUX_SOURCE_COMPAT 12 | #endif 13 | 14 | #if defined(__FreeBSD__) 15 | # define PTRACE_ATTACH PT_ATTACH 16 | # define PTRACE_CONT PT_CONTINUE 17 | #endif 18 | 19 | inline unsigned long gettime() { 20 | volatile unsigned long tl; 21 | asm __volatile__("lfence\nrdtsc" : "=a" (tl): : "%edx"); 22 | return tl; 23 | } 24 | 25 | struct timespec timer_start(); 26 | long timer_end(struct timespec start_time); 27 | void initPapi(); 28 | void initEventSet(int *); 29 | void addEvent(int, char *eventName); 30 | void monitor(int, long long **values); 31 | void buildCSVLine(char *line, long long *values, int numItems); 32 | void cleanup(int *eventSet); 33 | void usage(char *name); 34 | 35 | int main( int argc, char *argv[] ) 36 | { 37 | #ifdef _DEBUG 38 | unsigned long t1, t2; // Used to measure timing of various calls 39 | struct timespec vartime; 40 | long time_elapsed_nanos; 41 | long samples = 0; 42 | double time_sum = 0; 43 | #endif 44 | int eventSet = PAPI_NULL; 45 | int numEventSets = 1; // One set should be enough 46 | int idx; 47 | int retval; 48 | long long **values; 49 | //long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc; 50 | char monitorLine[PAPI_MAX_STR_LEN]; 51 | pid_t pid = -1; 52 | config cfg; 53 | bool processAlive = true; 54 | 55 | if (argc < 3) { 56 | usage(argv[0]); 57 | } 58 | 59 | initPapi(); 60 | 61 | /* Load configuration from arguments */ 62 | setup_config(argc, argv, &cfg); 63 | 64 | if (cfg.run && cfg.attach) { 65 | fprintf(stderr, "Cannot attach and run! Choose one.\n"); 66 | exit(1); 67 | } 68 | 69 | if (cfg.run) { 70 | pid = 0; // TODO run process and get the PID 71 | } 72 | 73 | if (cfg.attach) { 74 | pid = cfg.pid; 75 | fprintf(stderr, "Attaching to PID: %d\n", pid); 76 | } 77 | 78 | if (pid < 0) { 79 | fprintf(stderr, "Please specify a PID to attach to with -a" /* or -r to run a process*/); 80 | } 81 | 82 | initEventSet(&eventSet); 83 | 84 | for (idx = 0; idx < cfg.numEvents; idx++) { 85 | addEvent(eventSet, cfg.events[idx]); // TODO 86 | } 87 | 88 | retval = PAPI_attach( eventSet, ( unsigned long ) pid ); 89 | if ( retval != PAPI_OK ) 90 | test_fail( __FILE__, __LINE__, "PAPI_attach", retval ); 91 | 92 | values = allocate_test_space(numEventSets, cfg.numEvents); 93 | 94 | /* Print CSV headers */ 95 | fprintf(stderr, "\n"); 96 | for (idx = 0; idx < cfg.numEvents; idx++) { 97 | fprintf(stderr, "%s", cfg.events[idx]); 98 | if (idx < cfg.numEvents - 1) { 99 | fprintf(stderr, ","); 100 | } 101 | } 102 | retval = PAPI_start( eventSet ); 103 | if ( retval != PAPI_OK ) 104 | test_fail( __FILE__, __LINE__, "PAPI_start", retval ); 105 | /* Start monitoring and print values */ 106 | fprintf(stderr, "\n"); 107 | for (idx = 0; processAlive && (idx < cfg.iterations || cfg.iterations == -1); idx++) { 108 | #ifdef _DEBUG 109 | t1 = gettime(); 110 | vartime = timer_start(); // begin a timer called 'vartime' 111 | #endif 112 | monitor(eventSet, values); 113 | // retval = PAPI_read( eventSet, values[0] ); 114 | // if ( retval != PAPI_OK ) 115 | // test_fail( __FILE__, __LINE__, "PAPI_read", retval ); 116 | // retval = PAPI_reset( eventSet ); 117 | // if ( retval != PAPI_OK ) 118 | // test_fail( __FILE__, __LINE__, "PAPI_reset", retval ); 119 | #ifdef _DEBUG 120 | time_elapsed_nanos = timer_end(vartime); 121 | t2 = gettime(); 122 | fprintf(stderr, "Time for one sample (cycles, RDTSC): %lu\n", t2 - t1); 123 | fprintf(stderr, "Time for one sample (nanoseconds, clock_gettime): %lu\n", time_elapsed_nanos); 124 | samples++; 125 | time_sum += time_elapsed_nanos; 126 | #endif 127 | if (cfg.interval > 0) 128 | usleep(cfg.interval); 129 | 130 | // fprintf(stderr, "Time to monitor: %lu\n", t2 - t1); 131 | buildCSVLine(monitorLine, values[0], cfg.numEvents); 132 | fprintf(stdout, "%s\n", monitorLine); 133 | fflush(stdout); 134 | if (kill(pid, 0) < 0) { 135 | /* Process is not active anymore */ 136 | if (errno == ESRCH) { 137 | processAlive = false; 138 | } 139 | } 140 | } 141 | 142 | retval = PAPI_stop( eventSet, values[0]); 143 | if ( retval != PAPI_OK ) 144 | test_fail( __FILE__, __LINE__, "PAPI_stop", retval ); 145 | 146 | cleanup(&eventSet); 147 | 148 | #ifdef _DEBUG 149 | fprintf(stderr, "Mean sampling time: %f\n", time_sum / samples); 150 | #endif 151 | 152 | exit(0); 153 | } 154 | 155 | void initPapi(){ 156 | int retval; 157 | const PAPI_hw_info_t *hw_info; 158 | const PAPI_component_info_t *cmpinfo; 159 | retval = PAPI_library_init( PAPI_VER_CURRENT ); 160 | if ( retval != PAPI_VER_CURRENT ) 161 | test_fail( __FILE__, __LINE__, "PAPI_library_init", retval ); 162 | 163 | if ( ( cmpinfo = PAPI_get_component_info( 0 ) ) == NULL ) 164 | test_fail( __FILE__, __LINE__, "PAPI_get_component_info", 0 ); 165 | 166 | if ( cmpinfo->attach == 0 ) 167 | test_skip( __FILE__, __LINE__, "Platform does not support attaching", 168 | 0 ); 169 | 170 | hw_info = PAPI_get_hardware_info( ); 171 | if ( hw_info == NULL ) 172 | test_fail( __FILE__, __LINE__, "PAPI_get_hardware_info", 0 ); 173 | } 174 | 175 | void initEventSet(int *eventSet) { 176 | int retval; 177 | /* add PAPI_TOT_CYC and one of the events in PAPI_FP_INS, PAPI_FP_OPS or 178 | PAPI_TOT_INS, depending on the availability of the event on the 179 | platform */ 180 | retval = PAPI_create_eventset(eventSet); 181 | if ( retval != PAPI_OK ) 182 | test_fail( __FILE__, __LINE__, "PAPI_create_eventset", retval ); 183 | 184 | /* Here we are testing that this does not cause a fail */ 185 | 186 | retval = PAPI_assign_eventset_component( *eventSet, 0 ); 187 | if ( retval != PAPI_OK ) 188 | test_fail( __FILE__, __LINE__, "PAPI_assign_eventset_component", 189 | retval ); 190 | 191 | /* Enable multiplexing to be able to probe more counters (less precision) */ 192 | // retval = PAPI_set_multiplex(*eventSet); 193 | // if ( retval != PAPI_OK ) 194 | // test_fail( __FILE__, __LINE__, "PAPI_set_multiplex", 195 | // retval ); 196 | } 197 | 198 | void addEvent(int eventSet, char *eventName) { 199 | int eventCode = 0; 200 | int retval; 201 | char msg[PAPI_MAX_STR_LEN]; 202 | PAPI_event_name_to_code(eventName, &eventCode ); 203 | retval = PAPI_add_event(eventSet, eventCode); 204 | if ( retval != PAPI_OK ) { 205 | sprintf(msg, "PAPI_add_event (%s)", eventName); 206 | test_fail( __FILE__, __LINE__, msg, retval ); 207 | } 208 | } 209 | 210 | void monitor(int eventSet, long long **values) { 211 | int retval; 212 | 213 | retval = PAPI_read( eventSet, values[0] ); 214 | if ( retval != PAPI_OK ) 215 | test_fail( __FILE__, __LINE__, "PAPI_read", retval ); 216 | 217 | retval = PAPI_reset( eventSet ); 218 | if ( retval != PAPI_OK ) 219 | test_fail( __FILE__, __LINE__, "PAPI_reset", retval ); 220 | } 221 | 222 | void buildCSVLine(char *line, long long *values, int numItems) { 223 | int i = 0; 224 | if (values == NULL || numItems <= 0) { 225 | fprintf(stderr, "Error: invalid CSV line! (%s, line %d)\n", __FILE__, __LINE__); 226 | exit(1); 227 | } 228 | for (; i < numItems; i++) { 229 | if (i == 0) { 230 | sprintf(line, "%lld", values[i]); 231 | } else { 232 | sprintf(line, "%s,%lld", line, values[i]); 233 | } 234 | } 235 | } 236 | 237 | void cleanup(int *eventSet) { 238 | int retval; 239 | retval = PAPI_cleanup_eventset(*eventSet); 240 | if (retval != PAPI_OK) 241 | test_fail( __FILE__, __LINE__, "PAPI_cleanup_eventset", retval ); 242 | 243 | retval = PAPI_destroy_eventset(eventSet); 244 | if (retval != PAPI_OK) 245 | test_fail( __FILE__, __LINE__, "PAPI_destroy_eventset", retval ); 246 | } 247 | 248 | void usage(char *name) { 249 | fprintf(stderr, "Usage: %s -a PID -c EVENTS_FILE [-i INTERVAL (usecs)] [-n SAMPLES]\n", name); 250 | fprintf(stderr, "\t(If no interval is specified the sampling is performed as quickly as possible)\n"); 251 | fprintf(stderr, "\t(If no number of samples is specified the execution continues until either %s is killed or the attached process terminates)\n", name); 252 | exit(1); 253 | } 254 | 255 | // call this function to start a nanosecond-resolution timer 256 | struct timespec timer_start(){ 257 | struct timespec start_time; 258 | clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time); 259 | return start_time; 260 | } 261 | 262 | // call this function to end a timer, returning nanoseconds elapsed as a long 263 | long timer_end(struct timespec start_time){ 264 | struct timespec end_time; 265 | clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); 266 | long diffInNanos = end_time.tv_nsec - start_time.tv_nsec; 267 | return diffInNanos; 268 | } 269 | -------------------------------------------------------------------------------- /src/test_reset_counters.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "config.h" 4 | 5 | #ifdef _AIX 6 | #define _LINUX_SOURCE_COMPAT 7 | #endif 8 | 9 | #if defined(__FreeBSD__) 10 | # define PTRACE_ATTACH PT_ATTACH 11 | # define PTRACE_CONT PT_CONTINUE 12 | #endif 13 | 14 | inline unsigned long gettime() { 15 | volatile unsigned long tl; 16 | asm __volatile__("lfence\nrdtsc" : "=a" (tl): : "%edx"); 17 | return tl; 18 | } 19 | 20 | void initPapi(); 21 | void initEventSet(int *); 22 | void addEvent(int, char *eventName); 23 | void monitor(int, long long **values, int useconds /* 0 means as fast as possible */); 24 | void buildCSVLine(char *line, long long *values, int numItems); 25 | void cleanup(int *eventSet); 26 | 27 | int main( int argc, char *argv[] ) 28 | { 29 | int eventSet = PAPI_NULL; 30 | unsigned long t1, t2; // Used to measure timing of various calls 31 | int numEventSets = 1; // One set should be enough 32 | int idx; 33 | int retval; 34 | long long **values; 35 | //long long elapsed_us, elapsed_cyc, elapsed_virt_us, elapsed_virt_cyc; 36 | char monitorLine[PAPI_MAX_STR_LEN]; 37 | pid_t pid = -1; 38 | config cfg; 39 | bool processAlive = true; 40 | 41 | initPapi(); 42 | 43 | /* Load configuration from arguments */ 44 | setup_config(argc, argv, &cfg); 45 | 46 | if (cfg.run && cfg.attach) { 47 | fprintf(stderr, "Cannot attach and run! Choose one.\n"); 48 | exit(1); 49 | } 50 | 51 | if (cfg.run) { 52 | pid = 0; // TODO run process and get the PID 53 | } 54 | 55 | if (cfg.attach) { 56 | pid = cfg.pid; 57 | printf("Attaching to PID: %d\n", pid); 58 | } 59 | 60 | if (pid < 0) { 61 | printf("Please specify a PID to attach to with -a" /* or -r to run a process*/); 62 | } 63 | 64 | initEventSet(&eventSet); 65 | 66 | for (idx = 0; idx < cfg.numEvents; idx++) { 67 | addEvent(eventSet, cfg.events[idx]); // TODO 68 | } 69 | 70 | retval = PAPI_attach( eventSet, ( unsigned long ) pid ); 71 | if ( retval != PAPI_OK ) 72 | test_fail_exit( __FILE__, __LINE__, "PAPI_attach", retval ); 73 | 74 | values = allocate_test_space(numEventSets, cfg.numEvents); 75 | 76 | /* Print CSV headers */ 77 | printf("\n"); 78 | for (idx = 0; idx < cfg.numEvents; idx++) { 79 | printf("%s", cfg.events[idx]); 80 | if (idx < cfg.numEvents - 1) { 81 | printf(","); 82 | } 83 | } 84 | /* Start monitoring and print values */ 85 | printf("\n"); 86 | for (idx = 0; processAlive && (idx < cfg.iterations || cfg.iterations == -1); idx++) { 87 | // t1 = gettime(); 88 | monitor(eventSet, values, cfg.interval); 89 | // t2 = gettime(); 90 | // printf("Time to monitor: %lu\n", t2 - t1); 91 | buildCSVLine(monitorLine, values[0], cfg.numEvents); 92 | printf("%s\n", monitorLine); 93 | if (kill(pid, 0) < 0) { 94 | /* Process is not active anymore */ 95 | if (errno == ESRCH) { 96 | processAlive = false; 97 | } 98 | } 99 | // t2 = gettime(); 100 | // printf("Time to end the loop: %lu\n", t2 - t1); 101 | } 102 | cleanup(&eventSet); 103 | 104 | exit(0); 105 | } 106 | 107 | void initPapi(){ 108 | int retval; 109 | const PAPI_hw_info_t *hw_info; 110 | const PAPI_component_info_t *cmpinfo; 111 | retval = PAPI_library_init( PAPI_VER_CURRENT ); 112 | if ( retval != PAPI_VER_CURRENT ) 113 | test_fail_exit( __FILE__, __LINE__, "PAPI_library_init", retval ); 114 | 115 | if ( ( cmpinfo = PAPI_get_component_info( 0 ) ) == NULL ) 116 | test_fail_exit( __FILE__, __LINE__, "PAPI_get_component_info", 0 ); 117 | 118 | if ( cmpinfo->attach == 0 ) 119 | test_skip( __FILE__, __LINE__, "Platform does not support attaching", 120 | 0 ); 121 | 122 | hw_info = PAPI_get_hardware_info( ); 123 | if ( hw_info == NULL ) 124 | test_fail_exit( __FILE__, __LINE__, "PAPI_get_hardware_info", 0 ); 125 | } 126 | 127 | void initEventSet(int *eventSet) { 128 | int retval; 129 | /* add PAPI_TOT_CYC and one of the events in PAPI_FP_INS, PAPI_FP_OPS or 130 | PAPI_TOT_INS, depending on the availability of the event on the 131 | platform */ 132 | retval = PAPI_create_eventset(eventSet); 133 | if ( retval != PAPI_OK ) 134 | test_fail_exit( __FILE__, __LINE__, "PAPI_create_eventset", retval ); 135 | 136 | /* Here we are testing that this does not cause a fail */ 137 | 138 | retval = PAPI_assign_eventset_component( *eventSet, 0 ); 139 | if ( retval != PAPI_OK ) 140 | test_fail( __FILE__, __LINE__, "PAPI_assign_eventset_component", 141 | retval ); 142 | } 143 | 144 | void addEvent(int eventSet, char *eventName) { 145 | int eventCode = 0; 146 | int retval; 147 | PAPI_event_name_to_code(eventName, &eventCode ); 148 | retval = PAPI_add_event(eventSet, eventCode); 149 | if ( retval != PAPI_OK ) 150 | test_fail_exit( __FILE__, __LINE__, "PAPI_add_event", retval ); 151 | } 152 | 153 | void monitor(int eventSet, long long **values, int useconds /* 0 means as fast as possible */) { 154 | int retval; 155 | 156 | retval = PAPI_start( eventSet ); 157 | if ( retval != PAPI_OK ) 158 | test_fail_exit( __FILE__, __LINE__, "PAPI_start", retval ); 159 | 160 | usleep(useconds); 161 | 162 | retval = PAPI_stop( eventSet, values[0] ); 163 | if ( retval != PAPI_OK ) 164 | test_fail_exit( __FILE__, __LINE__, "PAPI_stop", retval ); 165 | } 166 | 167 | void buildCSVLine(char *line, long long *values, int numItems) { 168 | int i = 0; 169 | if (values == NULL || numItems <= 0) { 170 | printf("Error: invalid CSV line! (%s, line %d)\n", __FILE__, __LINE__); 171 | exit(1); 172 | } 173 | for (; i < numItems; i++) { 174 | if (i == 0) { 175 | sprintf(line, "%lld", values[i]); 176 | } else { 177 | sprintf(line, "%s,%lld", line, values[i]); 178 | } 179 | } 180 | } 181 | 182 | void cleanup(int *eventSet) { 183 | int retval; 184 | retval = PAPI_cleanup_eventset(*eventSet); 185 | if (retval != PAPI_OK) 186 | test_fail_exit( __FILE__, __LINE__, "PAPI_cleanup_eventset", retval ); 187 | 188 | retval = PAPI_destroy_eventset(eventSet); 189 | if (retval != PAPI_OK) 190 | test_fail_exit( __FILE__, __LINE__, "PAPI_destroy_eventset", retval ); 191 | } --------------------------------------------------------------------------------