GNU Linux-libre 4.14.254-gnu1
[releases.git] / tools / power / x86 / intel_pstate_tracer / intel_pstate_tracer.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 """ This utility can be used to debug and tune the performance of the
5 intel_pstate driver. This utility can be used in two ways:
6 - If there is Linux trace file with pstate_sample events enabled, then
7 this 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,
9 then this utility enables and collects trace data for a user specified interval
10 and generates performance plots.
11
12 Prerequisites:
13     Python version 2.7.x or higher
14     gnuplot 5.0 or higher
15     gnuplot-py 1.8 or higher
16     (Most of the distributions have these required packages. They may be called
17      gnuplot-py, phython-gnuplot or phython3-gnuplot, gnuplot-nox, ... )
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 """
25 from __future__ import print_function
26 from datetime import datetime
27 import subprocess
28 import os
29 import time
30 import re
31 import sys
32 import getopt
33 import Gnuplot
34 from numpy import *
35 from decimal import *
36
37 __author__ = "Srinivas Pandruvada"
38 __copyright__ = " Copyright (c) 2017, Intel Corporation. "
39 __license__ = "GPL version 2"
40
41
42 MAX_CPUS = 256
43
44 # Define the csv file columns
45 C_COMM = 18
46 C_GHZ = 17
47 C_ELAPSED = 16
48 C_SAMPLE = 15
49 C_DURATION = 14
50 C_LOAD = 13
51 C_BOOST = 12
52 C_FREQ = 11
53 C_TSC = 10
54 C_APERF = 9
55 C_MPERF = 8
56 C_TO = 7
57 C_FROM = 6
58 C_SCALED = 5
59 C_CORE = 4
60 C_USEC = 3
61 C_SEC = 2
62 C_CPU = 1
63
64 global sample_num, last_sec_cpu, last_usec_cpu, start_time, testname
65
66 # 11 digits covers uptime to 115 days
67 getcontext().prec = 11
68
69 sample_num =0
70 last_sec_cpu = [0] * MAX_CPUS
71 last_usec_cpu = [0] * MAX_CPUS
72
73 def print_help():
74     print('intel_pstate_tracer.py:')
75     print('  Usage:')
76     print('    If the trace file is available, then to simply parse and plot, use (sudo not required):')
77     print('      ./intel_pstate_tracer.py [-c cpus] -t <trace_file> -n <test_name>')
78     print('    Or')
79     print('      ./intel_pstate_tracer.py [--cpu cpus] ---trace_file <trace_file> --name <test_name>')
80     print('    To generate trace file, parse and plot, use (sudo required):')
81     print('      sudo ./intel_pstate_tracer.py [-c cpus] -i <interval> -n <test_name>')
82     print('    Or')
83     print('      sudo ./intel_pstate_tracer.py [--cpu cpus] --interval <interval> --name <test_name>')
84     print('    Optional argument:')
85     print('      cpus:  comma separated list of CPUs')
86     print('  Output:')
87     print('    If not already present, creates a "results/test_name" folder in the current working directory with:')
88     print('      cpu.csv - comma seperated values file with trace contents and some additional calculations.')
89     print('      cpu???.csv - comma seperated values file for CPU number ???.')
90     print('      *.png - a variety of PNG format plot files created from the trace contents and the additional calculations.')
91     print('  Notes:')
92     print('    Avoid the use of _ (underscore) in test names, because in gnuplot it is a subscript directive.')
93     print('    Maximum number of CPUs is {0:d}. If there are more the script will abort with an error.'.format(MAX_CPUS))
94     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.')
95     print('    Empty y range warnings for autoscaled plots can occur and can be ignored.')
96
97 def plot_perf_busy_with_sample(cpu_index):
98     """ Plot method to per cpu information """
99
100     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
101     if os.path.exists(file_name):
102         output_png = "cpu%03d_perf_busy_vs_samples.png" % cpu_index
103         g_plot = common_all_gnuplot_settings(output_png)
104         g_plot('set yrange [0:40]')
105         g_plot('set y2range [0:200]')
106         g_plot('set y2tics 0, 10')
107         g_plot('set title "{} : cpu perf busy vs. sample : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
108 #       Override common
109         g_plot('set xlabel "Samples"')
110         g_plot('set ylabel "P-State"')
111         g_plot('set y2label "Scaled Busy/performance/io-busy(%)"')
112         set_4_plot_linestyles(g_plot)
113         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_SAMPLE, C_CORE))
114         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_SAMPLE, C_SCALED))
115         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_SAMPLE, C_BOOST))
116         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_SAMPLE, C_TO))
117
118 def plot_perf_busy(cpu_index):
119     """ Plot some per cpu information """
120
121     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
122     if os.path.exists(file_name):
123         output_png = "cpu%03d_perf_busy.png" % cpu_index
124         g_plot = common_all_gnuplot_settings(output_png)
125         g_plot('set yrange [0:40]')
126         g_plot('set y2range [0:200]')
127         g_plot('set y2tics 0, 10')
128         g_plot('set title "{} : perf busy : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
129         g_plot('set ylabel "P-State"')
130         g_plot('set y2label "Scaled Busy/performance/io-busy(%)"')
131         set_4_plot_linestyles(g_plot)
132         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_ELAPSED, C_CORE))
133         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_ELAPSED, C_SCALED))
134         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_ELAPSED, C_BOOST))
135         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_ELAPSED, C_TO))
136
137 def plot_durations(cpu_index):
138     """ Plot per cpu durations """
139
140     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
141     if os.path.exists(file_name):
142         output_png = "cpu%03d_durations.png" % cpu_index
143         g_plot = common_all_gnuplot_settings(output_png)
144 #       Should autoscale be used here? Should seconds be used here?
145         g_plot('set yrange [0:5000]')
146         g_plot('set ytics 0, 500')
147         g_plot('set title "{} : durations : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
148         g_plot('set ylabel "Timer Duration (MilliSeconds)"')
149 #       override common
150         g_plot('set key off')
151         set_4_plot_linestyles(g_plot)
152         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_DURATION))
153
154 def plot_loads(cpu_index):
155     """ Plot per cpu loads """
156
157     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
158     if os.path.exists(file_name):
159         output_png = "cpu%03d_loads.png" % cpu_index
160         g_plot = common_all_gnuplot_settings(output_png)
161         g_plot('set yrange [0:100]')
162         g_plot('set ytics 0, 10')
163         g_plot('set title "{} : loads : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
164         g_plot('set ylabel "CPU load (percent)"')
165 #       override common
166         g_plot('set key off')
167         set_4_plot_linestyles(g_plot)
168         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_LOAD))
169
170 def plot_pstate_cpu_with_sample():
171     """ Plot all cpu information """
172
173     if os.path.exists('cpu.csv'):
174         output_png = 'all_cpu_pstates_vs_samples.png'
175         g_plot = common_all_gnuplot_settings(output_png)
176         g_plot('set yrange [0:40]')
177 #       override common
178         g_plot('set xlabel "Samples"')
179         g_plot('set ylabel "P-State"')
180         g_plot('set title "{} : cpu pstate vs. sample : {:%F %H:%M}"'.format(testname, datetime.now()))
181         title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
182         plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_SAMPLE, C_TO)
183         g_plot('title_list = "{}"'.format(title_list))
184         g_plot(plot_str)
185
186 def plot_pstate_cpu():
187     """ Plot all cpu information from csv files """
188
189     output_png = 'all_cpu_pstates.png'
190     g_plot = common_all_gnuplot_settings(output_png)
191     g_plot('set yrange [0:40]')
192     g_plot('set ylabel "P-State"')
193     g_plot('set title "{} : cpu pstates : {:%F %H:%M}"'.format(testname, datetime.now()))
194
195 #    the following command is really cool, but doesn't work with the CPU masking option because it aborts on the first missing file.
196 #    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'
197 #
198     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
199     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_TO)
200     g_plot('title_list = "{}"'.format(title_list))
201     g_plot(plot_str)
202
203 def plot_load_cpu():
204     """ Plot all cpu loads """
205
206     output_png = 'all_cpu_loads.png'
207     g_plot = common_all_gnuplot_settings(output_png)
208     g_plot('set yrange [0:100]')
209     g_plot('set ylabel "CPU load (percent)"')
210     g_plot('set title "{} : cpu loads : {:%F %H:%M}"'.format(testname, datetime.now()))
211
212     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
213     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_LOAD)
214     g_plot('title_list = "{}"'.format(title_list))
215     g_plot(plot_str)
216
217 def plot_frequency_cpu():
218     """ Plot all cpu frequencies """
219
220     output_png = 'all_cpu_frequencies.png'
221     g_plot = common_all_gnuplot_settings(output_png)
222     g_plot('set yrange [0:4]')
223     g_plot('set ylabel "CPU Frequency (GHz)"')
224     g_plot('set title "{} : cpu frequencies : {:%F %H:%M}"'.format(testname, datetime.now()))
225
226     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
227     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_FREQ)
228     g_plot('title_list = "{}"'.format(title_list))
229     g_plot(plot_str)
230
231 def plot_duration_cpu():
232     """ Plot all cpu durations """
233
234     output_png = 'all_cpu_durations.png'
235     g_plot = common_all_gnuplot_settings(output_png)
236     g_plot('set yrange [0:5000]')
237     g_plot('set ytics 0, 500')
238     g_plot('set ylabel "Timer Duration (MilliSeconds)"')
239     g_plot('set title "{} : cpu durations : {:%F %H:%M}"'.format(testname, datetime.now()))
240
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)
245
246 def plot_scaled_cpu():
247     """ Plot all cpu scaled busy """
248
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()))
254
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)
259
260 def plot_boost_cpu():
261     """ Plot all cpu IO Boosts """
262
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()))
268
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)
273
274 def plot_ghz_cpu():
275     """ Plot all cpu tsc ghz """
276
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()))
282
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)
287
288 def common_all_gnuplot_settings(output_png):
289     """ common gnuplot settings for multiple CPUs one one graph. """
290
291     g_plot = common_gnuplot_settings()
292     g_plot('set output "' + output_png + '"')
293     return(g_plot)
294
295 def common_gnuplot_settings():
296     """ common gnuplot settings. """
297
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)
317
318 def set_4_plot_linestyles(g_plot):
319     """ set the linestyles used for 4 plots in 1 graphs. """
320
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')
325
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 """
328
329     global graph_data_present
330
331     if cpu_mask[cpu_int] == 0:
332         return
333
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
342
343     graph_data_present = True;
344
345 def split_csv():
346     """ seperate the all csv file into per CPU csv files. """
347
348     global current_max_cpu
349
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))
355
356 def fix_ownership(path):
357     """Change the owner of the file to SUDO_UID, if required"""
358
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))
363
364 def cleanup_data_files():
365     """ clean up existing data files """
366
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()
373
374 def clear_trace_file():
375     """ Clear trace file """
376
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         quit()
383
384 def enable_trace():
385     """ Enable trace """
386
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         quit()
393
394 def disable_trace():
395     """ Disable trace """
396
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         quit()
403
404 def set_trace_buffer_size():
405     """ Set trace buffer size """
406
407     try:
408        open('/sys/kernel/debug/tracing/buffer_size_kb'
409                  , 'w').write("10240")
410     except:
411         print('IO error setting trace buffer size ')
412         quit()
413
414 def read_trace_data(filename):
415     """ Read and parse trace data """
416
417     global current_max_cpu
418     global sample_num, last_sec_cpu, last_usec_cpu, start_time
419
420     try:
421         data = open(filename, 'r').read()
422     except:
423         print('Error opening ', filename)
424         quit()
425
426     for line in data.splitlines():
427         search_obj = \
428             re.search(r'(^(.*?)\[)((\d+)[^\]])(.*?)(\d+)([.])(\d+)(.*?core_busy=)(\d+)(.*?scaled=)(\d+)(.*?from=)(\d+)(.*?to=)(\d+)(.*?mperf=)(\d+)(.*?aperf=)(\d+)(.*?tsc=)(\d+)(.*?freq=)(\d+)'
429                       , line)
430
431         if search_obj:
432             cpu = search_obj.group(3)
433             cpu_int = int(cpu)
434             cpu = str(cpu_int)
435
436             time_pre_dec = search_obj.group(6)
437             time_post_dec = search_obj.group(8)
438             core_busy = search_obj.group(10)
439             scaled = search_obj.group(12)
440             _from = search_obj.group(14)
441             _to = search_obj.group(16)
442             mperf = search_obj.group(18)
443             aperf = search_obj.group(20)
444             tsc = search_obj.group(22)
445             freq = search_obj.group(24)
446             common_comm = search_obj.group(2).replace(' ', '')
447
448             # Not all kernel versions have io_boost field
449             io_boost = '0'
450             search_obj = re.search(r'.*?io_boost=(\d+)', line)
451             if search_obj:
452                 io_boost = search_obj.group(1)
453
454             if sample_num == 0 :
455                 start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000)
456             sample_num += 1
457
458             if last_sec_cpu[cpu_int] == 0 :
459                 last_sec_cpu[cpu_int] = time_pre_dec
460                 last_usec_cpu[cpu_int] = time_post_dec
461             else :
462                 duration_us = (int(time_pre_dec) - int(last_sec_cpu[cpu_int])) * 1000000 + (int(time_post_dec) - int(last_usec_cpu[cpu_int]))
463                 duration_ms = Decimal(duration_us) / Decimal(1000)
464                 last_sec_cpu[cpu_int] = time_pre_dec
465                 last_usec_cpu[cpu_int] = time_post_dec
466                 elapsed_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000) - start_time
467                 load = Decimal(int(mperf)*100)/ Decimal(tsc)
468                 freq_ghz = Decimal(freq)/Decimal(1000000)
469 #               Sanity check calculation, typically anomalies indicate missed samples
470 #               However, check for 0 (should never occur)
471                 tsc_ghz = Decimal(0)
472                 if duration_ms != Decimal(0) :
473                     tsc_ghz = Decimal(tsc)/duration_ms/Decimal(1000000)
474                 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)
475
476             if cpu_int > current_max_cpu:
477                 current_max_cpu = cpu_int
478 # End of for each trace line loop
479 # Now seperate the main overall csv file into per CPU csv files.
480     split_csv()
481
482 interval = ""
483 filename = ""
484 cpu_list = ""
485 testname = ""
486 graph_data_present = False;
487
488 valid1 = False
489 valid2 = False
490
491 cpu_mask = zeros((MAX_CPUS,), dtype=int)
492
493 try:
494     opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:",["help","trace_file=","interval=","cpu=","name="])
495 except getopt.GetoptError:
496     print_help()
497     sys.exit(2)
498 for opt, arg in opts:
499     if opt == '-h':
500         print()
501         sys.exit()
502     elif opt in ("-t", "--trace_file"):
503         valid1 = True
504         location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
505         filename = os.path.join(location, arg)
506     elif opt in ("-i", "--interval"):
507         valid1 = True
508         interval = arg
509     elif opt in ("-c", "--cpu"):
510         cpu_list = arg
511     elif opt in ("-n", "--name"):
512         valid2 = True
513         testname = arg
514
515 if not (valid1 and valid2):
516     print_help()
517     sys.exit()
518
519 if cpu_list:
520     for p in re.split("[,]", cpu_list):
521         if int(p) < MAX_CPUS :
522             cpu_mask[int(p)] = 1
523 else:
524     for i in range (0, MAX_CPUS):
525         cpu_mask[i] = 1
526
527 if not os.path.exists('results'):
528     os.mkdir('results')
529     # The regular user needs to own the directory, not root.
530     fix_ownership('results')
531
532 os.chdir('results')
533 if os.path.exists(testname):
534     print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.')
535     sys.exit()
536 os.mkdir(testname)
537 # The regular user needs to own the directory, not root.
538 fix_ownership(testname)
539 os.chdir(testname)
540
541 # Temporary (or perhaps not)
542 cur_version = sys.version_info
543 print('python version (should be >= 2.7):')
544 print(cur_version)
545
546 # Left as "cleanup" for potential future re-run ability.
547 cleanup_data_files()
548
549 if interval:
550     filename = "/sys/kernel/debug/tracing/trace"
551     clear_trace_file()
552     set_trace_buffer_size()
553     enable_trace()
554     print('Sleeping for ', interval, 'seconds')
555     time.sleep(int(interval))
556     disable_trace()
557
558 current_max_cpu = 0
559
560 read_trace_data(filename)
561
562 if graph_data_present == False:
563     print('No valid data to plot')
564     sys.exit(2)
565
566 for cpu_no in range(0, current_max_cpu + 1):
567     plot_perf_busy_with_sample(cpu_no)
568     plot_perf_busy(cpu_no)
569     plot_durations(cpu_no)
570     plot_loads(cpu_no)
571
572 plot_pstate_cpu_with_sample()
573 plot_pstate_cpu()
574 plot_load_cpu()
575 plot_frequency_cpu()
576 plot_duration_cpu()
577 plot_scaled_cpu()
578 plot_boost_cpu()
579 plot_ghz_cpu()
580
581 # It is preferrable, but not necessary, that the regular user owns the files, not root.
582 for root, dirs, files in os.walk('.'):
583     for f in files:
584         fix_ownership(f)
585
586 os.chdir('../../')