2fa3c5757bcb5b4f72cf85a6bf8a6cbad8efbf6f
[linux-2.6-microblaze.git] / tools / power / x86 / intel_pstate_tracer / intel_pstate_tracer.py
1 #!/usr/bin/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
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 """
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 signal
32 import sys
33 import getopt
34 import Gnuplot
35 from numpy import *
36 from decimal import *
37
38 __author__ = "Srinivas Pandruvada"
39 __copyright__ = " Copyright (c) 2017, Intel Corporation. "
40 __license__ = "GPL version 2"
41
42
43 MAX_CPUS = 256
44
45 # Define the csv file columns
46 C_COMM = 18
47 C_GHZ = 17
48 C_ELAPSED = 16
49 C_SAMPLE = 15
50 C_DURATION = 14
51 C_LOAD = 13
52 C_BOOST = 12
53 C_FREQ = 11
54 C_TSC = 10
55 C_APERF = 9
56 C_MPERF = 8
57 C_TO = 7
58 C_FROM = 6
59 C_SCALED = 5
60 C_CORE = 4
61 C_USEC = 3
62 C_SEC = 2
63 C_CPU = 1
64
65 global sample_num, last_sec_cpu, last_usec_cpu, start_time, testname
66
67 # 11 digits covers uptime to 115 days
68 getcontext().prec = 11
69
70 sample_num =0
71 last_sec_cpu = [0] * MAX_CPUS
72 last_usec_cpu = [0] * MAX_CPUS
73
74 def 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
99 def 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
120 def 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
139 def 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
156 def 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
172 def 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
188 def 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
205 def 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
219 def 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
233 def 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
248 def 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
262 def 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
276 def 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
290 def 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
297 def 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
320 def 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
328 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):
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
347 def 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
358 def 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
366 def 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
376 def 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
386 def 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
396 def 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
406 def 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
416 def 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
426 def 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
494 def 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
503 signal.signal(signal.SIGINT, signal_handler)
504
505 interval = ""
506 filename = ""
507 cpu_list = ""
508 testname = ""
509 memory = "10240"
510 graph_data_present = False;
511
512 valid1 = False
513 valid2 = False
514
515 cpu_mask = zeros((MAX_CPUS,), dtype=int)
516
517 try:
518     opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:m:",["help","trace_file=","interval=","cpu=","name=","memory="])
519 except getopt.GetoptError:
520     print_help()
521     sys.exit(2)
522 for 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
541 if not (valid1 and valid2):
542     print_help()
543     sys.exit()
544
545 if cpu_list:
546     for p in re.split("[,]", cpu_list):
547         if int(p) < MAX_CPUS :
548             cpu_mask[int(p)] = 1
549 else:
550     for i in range (0, MAX_CPUS):
551         cpu_mask[i] = 1
552
553 if 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
558 os.chdir('results')
559 if 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()
562 os.mkdir(testname)
563 # The regular user needs to own the directory, not root.
564 fix_ownership(testname)
565 os.chdir(testname)
566
567 # Temporary (or perhaps not)
568 cur_version = sys.version_info
569 print('python version (should be >= 2.7):')
570 print(cur_version)
571
572 # Left as "cleanup" for potential future re-run ability.
573 cleanup_data_files()
574
575 if 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
584 current_max_cpu = 0
585
586 read_trace_data(filename)
587
588 if interval:
589     clear_trace_file()
590     # Free the memory
591     free_trace_buffer()
592
593 if graph_data_present == False:
594     print('No valid data to plot')
595     sys.exit(2)
596
597 for 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
603 plot_pstate_cpu_with_sample()
604 plot_pstate_cpu()
605 plot_load_cpu()
606 plot_frequency_cpu()
607 plot_duration_cpu()
608 plot_scaled_cpu()
609 plot_boost_cpu()
610 plot_ghz_cpu()
611
612 # It is preferrable, but not necessary, that the regular user owns the files, not root.
613 for root, dirs, files in os.walk('.'):
614     for f in files:
615         fix_ownership(f)
616
617 os.chdir('../../')