Merge branch 'core-objtool-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.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 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, ... )
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 #   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))
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 #   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))
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 #       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))
154
155 def plot_loads(cpu_index):
156     """ Plot per cpu loads """
157
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))
170
171 def plot_pstate_cpu_with_sample():
172     """ Plot all cpu information """
173
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)
186
187 def plot_pstate_cpu():
188     """ Plot all cpu information from csv files """
189
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()))
195
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'
198 #
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)
203
204 def plot_load_cpu():
205     """ Plot all cpu loads """
206
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()))
212
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)
217
218 def plot_frequency_cpu():
219     """ Plot all cpu frequencies """
220
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()))
226
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)
231
232 def plot_duration_cpu():
233     """ Plot all cpu durations """
234
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()))
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         sys.exit(2)
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         sys.exit(2)
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         sys.exit(2)
403
404 def set_trace_buffer_size():
405     """ Set trace buffer size """
406
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)
413
414 def free_trace_buffer():
415     """ Free the trace buffer memory """
416
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)
423
424 def read_trace_data(filename):
425     """ Read and parse trace data """
426
427     global current_max_cpu
428     global sample_num, last_sec_cpu, last_usec_cpu, start_time
429
430     try:
431         data = open(filename, 'r').read()
432     except:
433         print('Error opening ', filename)
434         sys.exit(2)
435
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)
440
441         if search_obj:
442             cpu = search_obj.group(3)
443             cpu_int = int(cpu)
444             cpu = str(cpu_int)
445
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(' ', '')
457
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)
463
464             if sample_num == 0 :
465                 start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000)
466             sample_num += 1
467
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)
485
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()
491
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)
500
501 signal.signal(signal.SIGINT, signal_handler)
502
503 interval = ""
504 filename = ""
505 cpu_list = ""
506 testname = ""
507 memory = "10240"
508 graph_data_present = False;
509
510 valid1 = False
511 valid2 = False
512
513 cpu_mask = zeros((MAX_CPUS,), dtype=int)
514
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
538
539 if not (valid1 and valid2):
540     print_help()
541     sys.exit()
542
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
550
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')
555
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)
564
565 # Temporary (or perhaps not)
566 cur_version = sys.version_info
567 print('python version (should be >= 2.7):')
568 print(cur_version)
569
570 # Left as "cleanup" for potential future re-run ability.
571 cleanup_data_files()
572
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()
581
582 current_max_cpu = 0
583
584 read_trace_data(filename)
585
586 if interval:
587     clear_trace_file()
588     # Free the memory
589     free_trace_buffer()
590
591 if graph_data_present == False:
592     print('No valid data to plot')
593     sys.exit(2)
594
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)
600
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()
609
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)
614
615 os.chdir('../../')