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