1#!/usr/bin/python 2# -*- coding: utf-8 -*- 3# 4""" This utility can be used to debug and tune the performance of the 5intel_pstate driver. This utility can be used in two ways: 6- If there is Linux trace file with pstate_sample events enabled, then 7this utility can parse the trace file and generate performance plots. 8- If user has not specified a trace file as input via command line parameters, 9then this utility enables and collects trace data for a user specified interval 10and generates performance plots. 11 12Prerequisites: 13 Python version 2.7.x 14 gnuplot 5.0 or higher 15 gnuplot-py 1.8 16 (Most of the distributions have these required packages. They may be called 17 gnuplot-py, phython-gnuplot. ) 18 19 HWP (Hardware P-States are disabled) 20 Kernel config for Linux trace is enabled 21 22 see print_help(): for Usage and Output details 23 24""" 25from __future__ import print_function 26from datetime import datetime 27import subprocess 28import os 29import time 30import re 31import signal 32import sys 33import getopt 34import Gnuplot 35from numpy import * 36from decimal import * 37 38__author__ = "Srinivas Pandruvada" 39__copyright__ = " Copyright (c) 2017, Intel Corporation. " 40__license__ = "GPL version 2" 41 42 43MAX_CPUS = 256 44 45# Define the csv file columns 46C_COMM = 18 47C_GHZ = 17 48C_ELAPSED = 16 49C_SAMPLE = 15 50C_DURATION = 14 51C_LOAD = 13 52C_BOOST = 12 53C_FREQ = 11 54C_TSC = 10 55C_APERF = 9 56C_MPERF = 8 57C_TO = 7 58C_FROM = 6 59C_SCALED = 5 60C_CORE = 4 61C_USEC = 3 62C_SEC = 2 63C_CPU = 1 64 65global sample_num, last_sec_cpu, last_usec_cpu, start_time, testname 66 67# 11 digits covers uptime to 115 days 68getcontext().prec = 11 69 70sample_num =0 71last_sec_cpu = [0] * MAX_CPUS 72last_usec_cpu = [0] * MAX_CPUS 73 74def print_help(): 75 print('intel_pstate_tracer.py:') 76 print(' Usage:') 77 print(' If the trace file is available, then to simply parse and plot, use (sudo not required):') 78 print(' ./intel_pstate_tracer.py [-c cpus] -t <trace_file> -n <test_name>') 79 print(' Or') 80 print(' ./intel_pstate_tracer.py [--cpu cpus] ---trace_file <trace_file> --name <test_name>') 81 print(' To generate trace file, parse and plot, use (sudo required):') 82 print(' sudo ./intel_pstate_tracer.py [-c cpus] -i <interval> -n <test_name> -m <kbytes>') 83 print(' Or') 84 print(' sudo ./intel_pstate_tracer.py [--cpu cpus] --interval <interval> --name <test_name> --memory <kbytes>') 85 print(' Optional argument:') 86 print(' cpus: comma separated list of CPUs') 87 print(' kbytes: Kilo bytes of memory per CPU to allocate to the trace buffer. Default: 10240') 88 print(' Output:') 89 print(' If not already present, creates a "results/test_name" folder in the current working directory with:') 90 print(' cpu.csv - comma seperated values file with trace contents and some additional calculations.') 91 print(' cpu???.csv - comma seperated values file for CPU number ???.') 92 print(' *.png - a variety of PNG format plot files created from the trace contents and the additional calculations.') 93 print(' Notes:') 94 print(' Avoid the use of _ (underscore) in test names, because in gnuplot it is a subscript directive.') 95 print(' Maximum number of CPUs is {0:d}. If there are more the script will abort with an error.'.format(MAX_CPUS)) 96 print(' Off-line CPUs cause the script to list some warnings, and create some empty files. Use the CPU mask feature for a clean run.') 97 print(' Empty y range warnings for autoscaled plots can occur and can be ignored.') 98 99def plot_perf_busy_with_sample(cpu_index): 100 """ Plot method to per cpu information """ 101 102 file_name = 'cpu{:0>3}.csv'.format(cpu_index) 103 if os.path.exists(file_name): 104 output_png = "cpu%03d_perf_busy_vs_samples.png" % cpu_index 105 g_plot = common_all_gnuplot_settings(output_png) 106 g_plot('set yrange [0:40]') 107 g_plot('set y2range [0:200]') 108 g_plot('set y2tics 0, 10') 109 g_plot('set title "{} : cpu perf busy vs. sample : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now())) 110# Override common 111 g_plot('set xlabel "Samples"') 112 g_plot('set ylabel "P-State"') 113 g_plot('set y2label "Scaled Busy/performance/io-busy(%)"') 114 set_4_plot_linestyles(g_plot) 115 g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_SAMPLE, C_CORE)) 116 g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_SAMPLE, C_SCALED)) 117 g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_SAMPLE, C_BOOST)) 118 g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_SAMPLE, C_TO)) 119 120def plot_perf_busy(cpu_index): 121 """ Plot some per cpu information """ 122 123 file_name = 'cpu{:0>3}.csv'.format(cpu_index) 124 if os.path.exists(file_name): 125 output_png = "cpu%03d_perf_busy.png" % cpu_index 126 g_plot = common_all_gnuplot_settings(output_png) 127 g_plot('set yrange [0:40]') 128 g_plot('set y2range [0:200]') 129 g_plot('set y2tics 0, 10') 130 g_plot('set title "{} : perf busy : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now())) 131 g_plot('set ylabel "P-State"') 132 g_plot('set y2label "Scaled Busy/performance/io-busy(%)"') 133 set_4_plot_linestyles(g_plot) 134 g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_ELAPSED, C_CORE)) 135 g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_ELAPSED, C_SCALED)) 136 g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_ELAPSED, C_BOOST)) 137 g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_ELAPSED, C_TO)) 138 139def plot_durations(cpu_index): 140 """ Plot per cpu durations """ 141 142 file_name = 'cpu{:0>3}.csv'.format(cpu_index) 143 if os.path.exists(file_name): 144 output_png = "cpu%03d_durations.png" % cpu_index 145 g_plot = common_all_gnuplot_settings(output_png) 146# Should autoscale be used here? Should seconds be used here? 147 g_plot('set yrange [0:5000]') 148 g_plot('set ytics 0, 500') 149 g_plot('set title "{} : durations : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now())) 150 g_plot('set ylabel "Timer Duration (MilliSeconds)"') 151# override common 152 g_plot('set key off') 153 set_4_plot_linestyles(g_plot) 154 g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_DURATION)) 155 156def plot_loads(cpu_index): 157 """ Plot per cpu loads """ 158 159 file_name = 'cpu{:0>3}.csv'.format(cpu_index) 160 if os.path.exists(file_name): 161 output_png = "cpu%03d_loads.png" % cpu_index 162 g_plot = common_all_gnuplot_settings(output_png) 163 g_plot('set yrange [0:100]') 164 g_plot('set ytics 0, 10') 165 g_plot('set title "{} : loads : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now())) 166 g_plot('set ylabel "CPU load (percent)"') 167# override common 168 g_plot('set key off') 169 set_4_plot_linestyles(g_plot) 170 g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_LOAD)) 171 172def plot_pstate_cpu_with_sample(): 173 """ Plot all cpu information """ 174 175 if os.path.exists('cpu.csv'): 176 output_png = 'all_cpu_pstates_vs_samples.png' 177 g_plot = common_all_gnuplot_settings(output_png) 178 g_plot('set yrange [0:40]') 179# override common 180 g_plot('set xlabel "Samples"') 181 g_plot('set ylabel "P-State"') 182 g_plot('set title "{} : cpu pstate vs. sample : {:%F %H:%M}"'.format(testname, datetime.now())) 183 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 184 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_SAMPLE, C_TO) 185 g_plot('title_list = "{}"'.format(title_list)) 186 g_plot(plot_str) 187 188def plot_pstate_cpu(): 189 """ Plot all cpu information from csv files """ 190 191 output_png = 'all_cpu_pstates.png' 192 g_plot = common_all_gnuplot_settings(output_png) 193 g_plot('set yrange [0:40]') 194 g_plot('set ylabel "P-State"') 195 g_plot('set title "{} : cpu pstates : {:%F %H:%M}"'.format(testname, datetime.now())) 196 197# the following command is really cool, but doesn't work with the CPU masking option because it aborts on the first missing file. 198# plot_str = 'plot for [i=0:*] file=sprintf("cpu%03d.csv",i) title_s=sprintf("cpu%03d",i) file using 16:7 pt 7 ps 1 title title_s' 199# 200 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 201 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_TO) 202 g_plot('title_list = "{}"'.format(title_list)) 203 g_plot(plot_str) 204 205def plot_load_cpu(): 206 """ Plot all cpu loads """ 207 208 output_png = 'all_cpu_loads.png' 209 g_plot = common_all_gnuplot_settings(output_png) 210 g_plot('set yrange [0:100]') 211 g_plot('set ylabel "CPU load (percent)"') 212 g_plot('set title "{} : cpu loads : {:%F %H:%M}"'.format(testname, datetime.now())) 213 214 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 215 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_LOAD) 216 g_plot('title_list = "{}"'.format(title_list)) 217 g_plot(plot_str) 218 219def plot_frequency_cpu(): 220 """ Plot all cpu frequencies """ 221 222 output_png = 'all_cpu_frequencies.png' 223 g_plot = common_all_gnuplot_settings(output_png) 224 g_plot('set yrange [0:4]') 225 g_plot('set ylabel "CPU Frequency (GHz)"') 226 g_plot('set title "{} : cpu frequencies : {:%F %H:%M}"'.format(testname, datetime.now())) 227 228 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 229 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_FREQ) 230 g_plot('title_list = "{}"'.format(title_list)) 231 g_plot(plot_str) 232 233def plot_duration_cpu(): 234 """ Plot all cpu durations """ 235 236 output_png = 'all_cpu_durations.png' 237 g_plot = common_all_gnuplot_settings(output_png) 238 g_plot('set yrange [0:5000]') 239 g_plot('set ytics 0, 500') 240 g_plot('set ylabel "Timer Duration (MilliSeconds)"') 241 g_plot('set title "{} : cpu durations : {:%F %H:%M}"'.format(testname, datetime.now())) 242 243 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 244 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_DURATION) 245 g_plot('title_list = "{}"'.format(title_list)) 246 g_plot(plot_str) 247 248def plot_scaled_cpu(): 249 """ Plot all cpu scaled busy """ 250 251 output_png = 'all_cpu_scaled.png' 252 g_plot = common_all_gnuplot_settings(output_png) 253# autoscale this one, no set y range 254 g_plot('set ylabel "Scaled Busy (Unitless)"') 255 g_plot('set title "{} : cpu scaled busy : {:%F %H:%M}"'.format(testname, datetime.now())) 256 257 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 258 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_SCALED) 259 g_plot('title_list = "{}"'.format(title_list)) 260 g_plot(plot_str) 261 262def plot_boost_cpu(): 263 """ Plot all cpu IO Boosts """ 264 265 output_png = 'all_cpu_boost.png' 266 g_plot = common_all_gnuplot_settings(output_png) 267 g_plot('set yrange [0:100]') 268 g_plot('set ylabel "CPU IO Boost (percent)"') 269 g_plot('set title "{} : cpu io boost : {:%F %H:%M}"'.format(testname, datetime.now())) 270 271 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 272 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_BOOST) 273 g_plot('title_list = "{}"'.format(title_list)) 274 g_plot(plot_str) 275 276def plot_ghz_cpu(): 277 """ Plot all cpu tsc ghz """ 278 279 output_png = 'all_cpu_ghz.png' 280 g_plot = common_all_gnuplot_settings(output_png) 281# autoscale this one, no set y range 282 g_plot('set ylabel "TSC Frequency (GHz)"') 283 g_plot('set title "{} : cpu TSC Frequencies (Sanity check calculation) : {:%F %H:%M}"'.format(testname, datetime.now())) 284 285 title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ') 286 plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_GHZ) 287 g_plot('title_list = "{}"'.format(title_list)) 288 g_plot(plot_str) 289 290def common_all_gnuplot_settings(output_png): 291 """ common gnuplot settings for multiple CPUs one one graph. """ 292 293 g_plot = common_gnuplot_settings() 294 g_plot('set output "' + output_png + '"') 295 return(g_plot) 296 297def common_gnuplot_settings(): 298 """ common gnuplot settings. """ 299 300 g_plot = Gnuplot.Gnuplot(persist=1) 301# The following line is for rigor only. It seems to be assumed for .csv files 302 g_plot('set datafile separator \",\"') 303 g_plot('set ytics nomirror') 304 g_plot('set xtics nomirror') 305 g_plot('set xtics font ", 10"') 306 g_plot('set ytics font ", 10"') 307 g_plot('set tics out scale 1.0') 308 g_plot('set grid') 309 g_plot('set key out horiz') 310 g_plot('set key bot center') 311 g_plot('set key samplen 2 spacing .8 font ", 9"') 312 g_plot('set term png size 1200, 600') 313 g_plot('set title font ", 11"') 314 g_plot('set ylabel font ", 10"') 315 g_plot('set xlabel font ", 10"') 316 g_plot('set xlabel offset 0, 0.5') 317 g_plot('set xlabel "Elapsed Time (Seconds)"') 318 return(g_plot) 319 320def set_4_plot_linestyles(g_plot): 321 """ set the linestyles used for 4 plots in 1 graphs. """ 322 323 g_plot('set style line 1 linetype 1 linecolor rgb "green" pointtype -1') 324 g_plot('set style line 2 linetype 1 linecolor rgb "red" pointtype -1') 325 g_plot('set style line 3 linetype 1 linecolor rgb "purple" pointtype -1') 326 g_plot('set style line 4 linetype 1 linecolor rgb "blue" pointtype -1') 327 328def store_csv(cpu_int, time_pre_dec, time_post_dec, core_busy, scaled, _from, _to, mperf, aperf, tsc, freq_ghz, io_boost, common_comm, load, duration_ms, sample_num, elapsed_time, tsc_ghz): 329 """ Store master csv file information """ 330 331 global graph_data_present 332 333 if cpu_mask[cpu_int] == 0: 334 return 335 336 try: 337 f_handle = open('cpu.csv', 'a') 338 string_buffer = "CPU_%03u, %05u, %06u, %u, %u, %u, %u, %u, %u, %u, %.4f, %u, %.2f, %.3f, %u, %.3f, %.3f, %s\n" % (cpu_int, int(time_pre_dec), int(time_post_dec), int(core_busy), int(scaled), int(_from), int(_to), int(mperf), int(aperf), int(tsc), freq_ghz, int(io_boost), load, duration_ms, sample_num, elapsed_time, tsc_ghz, common_comm) 339 f_handle.write(string_buffer); 340 f_handle.close() 341 except: 342 print('IO error cpu.csv') 343 return 344 345 graph_data_present = True; 346 347def split_csv(): 348 """ seperate the all csv file into per CPU csv files. """ 349 350 global current_max_cpu 351 352 if os.path.exists('cpu.csv'): 353 for index in range(0, current_max_cpu + 1): 354 if cpu_mask[int(index)] != 0: 355 os.system('grep -m 1 common_cpu cpu.csv > cpu{:0>3}.csv'.format(index)) 356 os.system('grep CPU_{:0>3} cpu.csv >> cpu{:0>3}.csv'.format(index, index)) 357 358def fix_ownership(path): 359 """Change the owner of the file to SUDO_UID, if required""" 360 361 uid = os.environ.get('SUDO_UID') 362 gid = os.environ.get('SUDO_GID') 363 if uid is not None: 364 os.chown(path, int(uid), int(gid)) 365 366def cleanup_data_files(): 367 """ clean up existing data files """ 368 369 if os.path.exists('cpu.csv'): 370 os.remove('cpu.csv') 371 f_handle = open('cpu.csv', 'a') 372 f_handle.write('common_cpu, common_secs, common_usecs, core_busy, scaled_busy, from, to, mperf, aperf, tsc, freq, boost, load, duration_ms, sample_num, elapsed_time, tsc_ghz, common_comm') 373 f_handle.write('\n') 374 f_handle.close() 375 376def clear_trace_file(): 377 """ Clear trace file """ 378 379 try: 380 f_handle = open('/sys/kernel/debug/tracing/trace', 'w') 381 f_handle.close() 382 except: 383 print('IO error clearing trace file ') 384 sys.exit(2) 385 386def enable_trace(): 387 """ Enable trace """ 388 389 try: 390 open('/sys/kernel/debug/tracing/events/power/pstate_sample/enable' 391 , 'w').write("1") 392 except: 393 print('IO error enabling trace ') 394 sys.exit(2) 395 396def disable_trace(): 397 """ Disable trace """ 398 399 try: 400 open('/sys/kernel/debug/tracing/events/power/pstate_sample/enable' 401 , 'w').write("0") 402 except: 403 print('IO error disabling trace ') 404 sys.exit(2) 405 406def set_trace_buffer_size(): 407 """ Set trace buffer size """ 408 409 try: 410 with open('/sys/kernel/debug/tracing/buffer_size_kb', 'w') as fp: 411 fp.write(memory) 412 except: 413 print('IO error setting trace buffer size ') 414 sys.exit(2) 415 416def free_trace_buffer(): 417 """ Free the trace buffer memory """ 418 419 try: 420 open('/sys/kernel/debug/tracing/buffer_size_kb' 421 , 'w').write("1") 422 except: 423 print('IO error freeing trace buffer ') 424 sys.exit(2) 425 426def read_trace_data(filename): 427 """ Read and parse trace data """ 428 429 global current_max_cpu 430 global sample_num, last_sec_cpu, last_usec_cpu, start_time 431 432 try: 433 data = open(filename, 'r').read() 434 except: 435 print('Error opening ', filename) 436 sys.exit(2) 437 438 for line in data.splitlines(): 439 search_obj = \ 440 re.search(r'(^(.*?)\[)((\d+)[^\]])(.*?)(\d+)([.])(\d+)(.*?core_busy=)(\d+)(.*?scaled=)(\d+)(.*?from=)(\d+)(.*?to=)(\d+)(.*?mperf=)(\d+)(.*?aperf=)(\d+)(.*?tsc=)(\d+)(.*?freq=)(\d+)' 441 , line) 442 443 if search_obj: 444 cpu = search_obj.group(3) 445 cpu_int = int(cpu) 446 cpu = str(cpu_int) 447 448 time_pre_dec = search_obj.group(6) 449 time_post_dec = search_obj.group(8) 450 core_busy = search_obj.group(10) 451 scaled = search_obj.group(12) 452 _from = search_obj.group(14) 453 _to = search_obj.group(16) 454 mperf = search_obj.group(18) 455 aperf = search_obj.group(20) 456 tsc = search_obj.group(22) 457 freq = search_obj.group(24) 458 common_comm = search_obj.group(2).replace(' ', '') 459 460 # Not all kernel versions have io_boost field 461 io_boost = '0' 462 search_obj = re.search(r'.*?io_boost=(\d+)', line) 463 if search_obj: 464 io_boost = search_obj.group(1) 465 466 if sample_num == 0 : 467 start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000) 468 sample_num += 1 469 470 if last_sec_cpu[cpu_int] == 0 : 471 last_sec_cpu[cpu_int] = time_pre_dec 472 last_usec_cpu[cpu_int] = time_post_dec 473 else : 474 duration_us = (int(time_pre_dec) - int(last_sec_cpu[cpu_int])) * 1000000 + (int(time_post_dec) - int(last_usec_cpu[cpu_int])) 475 duration_ms = Decimal(duration_us) / Decimal(1000) 476 last_sec_cpu[cpu_int] = time_pre_dec 477 last_usec_cpu[cpu_int] = time_post_dec 478 elapsed_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000) - start_time 479 load = Decimal(int(mperf)*100)/ Decimal(tsc) 480 freq_ghz = Decimal(freq)/Decimal(1000000) 481# Sanity check calculation, typically anomalies indicate missed samples 482# However, check for 0 (should never occur) 483 tsc_ghz = Decimal(0) 484 if duration_ms != Decimal(0) : 485 tsc_ghz = Decimal(tsc)/duration_ms/Decimal(1000000) 486 store_csv(cpu_int, time_pre_dec, time_post_dec, core_busy, scaled, _from, _to, mperf, aperf, tsc, freq_ghz, io_boost, common_comm, load, duration_ms, sample_num, elapsed_time, tsc_ghz) 487 488 if cpu_int > current_max_cpu: 489 current_max_cpu = cpu_int 490# End of for each trace line loop 491# Now seperate the main overall csv file into per CPU csv files. 492 split_csv() 493 494def signal_handler(signal, frame): 495 print(' SIGINT: Forcing cleanup before exit.') 496 if interval: 497 disable_trace() 498 clear_trace_file() 499 # Free the memory 500 free_trace_buffer() 501 sys.exit(0) 502 503signal.signal(signal.SIGINT, signal_handler) 504 505interval = "" 506filename = "" 507cpu_list = "" 508testname = "" 509memory = "10240" 510graph_data_present = False; 511 512valid1 = False 513valid2 = False 514 515cpu_mask = zeros((MAX_CPUS,), dtype=int) 516 517try: 518 opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:m:",["help","trace_file=","interval=","cpu=","name=","memory="]) 519except getopt.GetoptError: 520 print_help() 521 sys.exit(2) 522for opt, arg in opts: 523 if opt == '-h': 524 print() 525 sys.exit() 526 elif opt in ("-t", "--trace_file"): 527 valid1 = True 528 location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) 529 filename = os.path.join(location, arg) 530 elif opt in ("-i", "--interval"): 531 valid1 = True 532 interval = arg 533 elif opt in ("-c", "--cpu"): 534 cpu_list = arg 535 elif opt in ("-n", "--name"): 536 valid2 = True 537 testname = arg 538 elif opt in ("-m", "--memory"): 539 memory = arg 540 541if not (valid1 and valid2): 542 print_help() 543 sys.exit() 544 545if cpu_list: 546 for p in re.split("[,]", cpu_list): 547 if int(p) < MAX_CPUS : 548 cpu_mask[int(p)] = 1 549else: 550 for i in range (0, MAX_CPUS): 551 cpu_mask[i] = 1 552 553if not os.path.exists('results'): 554 os.mkdir('results') 555 # The regular user needs to own the directory, not root. 556 fix_ownership('results') 557 558os.chdir('results') 559if os.path.exists(testname): 560 print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.') 561 sys.exit() 562os.mkdir(testname) 563# The regular user needs to own the directory, not root. 564fix_ownership(testname) 565os.chdir(testname) 566 567# Temporary (or perhaps not) 568cur_version = sys.version_info 569print('python version (should be >= 2.7):') 570print(cur_version) 571 572# Left as "cleanup" for potential future re-run ability. 573cleanup_data_files() 574 575if interval: 576 filename = "/sys/kernel/debug/tracing/trace" 577 clear_trace_file() 578 set_trace_buffer_size() 579 enable_trace() 580 print('Sleeping for ', interval, 'seconds') 581 time.sleep(int(interval)) 582 disable_trace() 583 584current_max_cpu = 0 585 586read_trace_data(filename) 587 588if interval: 589 clear_trace_file() 590 # Free the memory 591 free_trace_buffer() 592 593if graph_data_present == False: 594 print('No valid data to plot') 595 sys.exit(2) 596 597for cpu_no in range(0, current_max_cpu + 1): 598 plot_perf_busy_with_sample(cpu_no) 599 plot_perf_busy(cpu_no) 600 plot_durations(cpu_no) 601 plot_loads(cpu_no) 602 603plot_pstate_cpu_with_sample() 604plot_pstate_cpu() 605plot_load_cpu() 606plot_frequency_cpu() 607plot_duration_cpu() 608plot_scaled_cpu() 609plot_boost_cpu() 610plot_ghz_cpu() 611 612# It is preferrable, but not necessary, that the regular user owns the files, not root. 613for root, dirs, files in os.walk('.'): 614 for f in files: 615 fix_ownership(f) 616 617os.chdir('../../') 618