~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/usr/bin/env python3
  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 3.6.x or higher
 15     gnuplot 5.0 or higher
 16     python3-gnuplot 1.8 or higher
 17     (Most of the distributions have these required packages. They may be called
 18      gnuplot-py, python-gnuplot or python3-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 
 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, trace_file
 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(driver_name):
 76     print('%s_tracer.py:'%driver_name)
 77     print('  Usage:')
 78     print('    If the trace file is available, then to simply parse and plot, use (sudo not required):')
 79     print('      ./%s_tracer.py [-c cpus] -t <trace_file> -n <test_name>'%driver_name)
 80     print('    Or')
 81     print('      ./%s_tracer.py [--cpu cpus] ---trace_file <trace_file> --name <test_name>'%driver_name)
 82     print('    To generate trace file, parse and plot, use (sudo required):')
 83     print('      sudo ./%s_tracer.py [-c cpus] -i <interval> -n <test_name> -m <kbytes>'%driver_name)
 84     print('    Or')
 85     print('      sudo ./%s_tracer.py [--cpu cpus] --interval <interval> --name <test_name> --memory <kbytes>'%driver_name)
 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, cpu_mask):
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(current_max_cpu, cpu_mask):
346     """ seperate the all csv file into per CPU csv files. """
347 
348     if os.path.exists('cpu.csv'):
349         for index in range(0, current_max_cpu + 1):
350             if cpu_mask[int(index)] != 0:
351                 os.system('grep -m 1 common_cpu cpu.csv > cpu{:0>3}.csv'.format(index))
352                 os.system('grep CPU_{:0>3} cpu.csv >> cpu{:0>3}.csv'.format(index, index))
353 
354 def fix_ownership(path):
355     """Change the owner of the file to SUDO_UID, if required"""
356 
357     uid = os.environ.get('SUDO_UID')
358     gid = os.environ.get('SUDO_GID')
359     if uid is not None:
360         os.chown(path, int(uid), int(gid))
361 
362 def cleanup_data_files():
363     """ clean up existing data files """
364 
365     if os.path.exists('cpu.csv'):
366         os.remove('cpu.csv')
367     f_handle = open('cpu.csv', 'a')
368     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')
369     f_handle.write('\n')
370     f_handle.close()
371 
372 def clear_trace_file():
373     """ Clear trace file """
374 
375     try:
376         f_handle = open('/sys/kernel/tracing/trace', 'w')
377         f_handle.close()
378     except:
379         print('IO error clearing trace file ')
380         sys.exit(2)
381 
382 def enable_trace(trace_file):
383     """ Enable trace """
384 
385     try:
386         open(trace_file,'w').write("1")
387     except:
388         print('IO error enabling trace ')
389         sys.exit(2)
390 
391 def disable_trace(trace_file):
392     """ Disable trace """
393 
394     try:
395        open(trace_file, 'w').write("0")
396     except:
397         print('IO error disabling trace ')
398         sys.exit(2)
399 
400 def set_trace_buffer_size(memory):
401     """ Set trace buffer size """
402 
403     try:
404        with open('/sys/kernel/tracing/buffer_size_kb', 'w') as fp:
405           fp.write(memory)
406     except:
407        print('IO error setting trace buffer size ')
408        sys.exit(2)
409 
410 def free_trace_buffer():
411     """ Free the trace buffer memory """
412 
413     try:
414        open('/sys/kernel/tracing/buffer_size_kb'
415                  , 'w').write("1")
416     except:
417         print('IO error freeing trace buffer ')
418         sys.exit(2)
419 
420 def read_trace_data(filename, cpu_mask):
421     """ Read and parse trace data """
422 
423     global current_max_cpu
424     global sample_num, last_sec_cpu, last_usec_cpu, start_time
425 
426     try:
427         data = open(filename, 'r').read()
428     except:
429         print('Error opening ', filename)
430         sys.exit(2)
431 
432     for line in data.splitlines():
433         search_obj = \
434             re.search(r'(^(.*?)\[)((\d+)[^\]])(.*?)(\d+)([.])(\d+)(.*?core_busy=)(\d+)(.*?scaled=)(\d+)(.*?from=)(\d+)(.*?to=)(\d+)(.*?mperf=)(\d+)(.*?aperf=)(\d+)(.*?tsc=)(\d+)(.*?freq=)(\d+)'
435                       , line)
436 
437         if search_obj:
438             cpu = search_obj.group(3)
439             cpu_int = int(cpu)
440             cpu = str(cpu_int)
441 
442             time_pre_dec = search_obj.group(6)
443             time_post_dec = search_obj.group(8)
444             core_busy = search_obj.group(10)
445             scaled = search_obj.group(12)
446             _from = search_obj.group(14)
447             _to = search_obj.group(16)
448             mperf = search_obj.group(18)
449             aperf = search_obj.group(20)
450             tsc = search_obj.group(22)
451             freq = search_obj.group(24)
452             common_comm = search_obj.group(2).replace(' ', '')
453 
454             # Not all kernel versions have io_boost field
455             io_boost = '0'
456             search_obj = re.search(r'.*?io_boost=(\d+)', line)
457             if search_obj:
458                 io_boost = search_obj.group(1)
459 
460             if sample_num == 0 :
461                 start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000)
462             sample_num += 1
463 
464             if last_sec_cpu[cpu_int] == 0 :
465                 last_sec_cpu[cpu_int] = time_pre_dec
466                 last_usec_cpu[cpu_int] = time_post_dec
467             else :
468                 duration_us = (int(time_pre_dec) - int(last_sec_cpu[cpu_int])) * 1000000 + (int(time_post_dec) - int(last_usec_cpu[cpu_int]))
469                 duration_ms = Decimal(duration_us) / Decimal(1000)
470                 last_sec_cpu[cpu_int] = time_pre_dec
471                 last_usec_cpu[cpu_int] = time_post_dec
472                 elapsed_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000) - start_time
473                 load = Decimal(int(mperf)*100)/ Decimal(tsc)
474                 freq_ghz = Decimal(freq)/Decimal(1000000)
475 #               Sanity check calculation, typically anomalies indicate missed samples
476 #               However, check for 0 (should never occur)
477                 tsc_ghz = Decimal(0)
478                 if duration_ms != Decimal(0) :
479                     tsc_ghz = Decimal(tsc)/duration_ms/Decimal(1000000)
480                 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, cpu_mask)
481 
482             if cpu_int > current_max_cpu:
483                 current_max_cpu = cpu_int
484 # End of for each trace line loop
485 # Now seperate the main overall csv file into per CPU csv files.
486     split_csv(current_max_cpu, cpu_mask)
487 
488 def signal_handler(signal, frame):
489     print(' SIGINT: Forcing cleanup before exit.')
490     if interval:
491         disable_trace(trace_file)
492         clear_trace_file()
493         # Free the memory
494         free_trace_buffer()
495         sys.exit(0)
496 
497 if __name__ == "__main__":
498     trace_file = "/sys/kernel/tracing/events/power/pstate_sample/enable"
499     signal.signal(signal.SIGINT, signal_handler)
500 
501     interval = ""
502     filename = ""
503     cpu_list = ""
504     testname = ""
505     memory = "10240"
506     graph_data_present = False;
507 
508     valid1 = False
509     valid2 = False
510 
511     cpu_mask = zeros((MAX_CPUS,), dtype=int)
512 
513     try:
514         opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:m:",["help","trace_file=","interval=","cpu=","name=","memory="])
515     except getopt.GetoptError:
516         print_help('intel_pstate')
517         sys.exit(2)
518     for opt, arg in opts:
519         if opt == '-h':
520             print_help('intel_pstate')
521             sys.exit()
522         elif opt in ("-t", "--trace_file"):
523             valid1 = True
524             location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
525             filename = os.path.join(location, arg)
526         elif opt in ("-i", "--interval"):
527             valid1 = True
528             interval = arg
529         elif opt in ("-c", "--cpu"):
530             cpu_list = arg
531         elif opt in ("-n", "--name"):
532             valid2 = True
533             testname = arg
534         elif opt in ("-m", "--memory"):
535             memory = arg
536 
537     if not (valid1 and valid2):
538         print_help('intel_pstate')
539         sys.exit()
540 
541     if cpu_list:
542         for p in re.split("[,]", cpu_list):
543             if int(p) < MAX_CPUS :
544                 cpu_mask[int(p)] = 1
545     else:
546         for i in range (0, MAX_CPUS):
547             cpu_mask[i] = 1
548 
549     if not os.path.exists('results'):
550         os.mkdir('results')
551         # The regular user needs to own the directory, not root.
552         fix_ownership('results')
553 
554     os.chdir('results')
555     if os.path.exists(testname):
556         print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.')
557         sys.exit()
558     os.mkdir(testname)
559     # The regular user needs to own the directory, not root.
560     fix_ownership(testname)
561     os.chdir(testname)
562 
563     # Temporary (or perhaps not)
564     cur_version = sys.version_info
565     print('python version (should be >= 3.6):')
566     print(cur_version)
567 
568     # Left as "cleanup" for potential future re-run ability.
569     cleanup_data_files()
570 
571     if interval:
572         filename = "/sys/kernel/tracing/trace"
573         clear_trace_file()
574         set_trace_buffer_size(memory)
575         enable_trace(trace_file)
576         print('Sleeping for ', interval, 'seconds')
577         time.sleep(int(interval))
578         disable_trace(trace_file)
579 
580     current_max_cpu = 0
581 
582     read_trace_data(filename, cpu_mask)
583 
584     if interval:
585         clear_trace_file()
586         # Free the memory
587         free_trace_buffer()
588 
589     if graph_data_present == False:
590         print('No valid data to plot')
591         sys.exit(2)
592 
593     for cpu_no in range(0, current_max_cpu + 1):
594         plot_perf_busy_with_sample(cpu_no)
595         plot_perf_busy(cpu_no)
596         plot_durations(cpu_no)
597         plot_loads(cpu_no)
598 
599     plot_pstate_cpu_with_sample()
600     plot_pstate_cpu()
601     plot_load_cpu()
602     plot_frequency_cpu()
603     plot_duration_cpu()
604     plot_scaled_cpu()
605     plot_boost_cpu()
606     plot_ghz_cpu()
607 
608     # It is preferrable, but not necessary, that the regular user owns the files, not root.
609     for root, dirs, files in os.walk('.'):
610         for f in files:
611             fix_ownership(f)
612 
613     os.chdir('../../')

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php