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