Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/env python
0002 # SPDX-License-Identifier: GPL-2.0-only
0003 # -*- coding: utf-8 -*-
0004 #
0005 """ This utility can be used to debug and tune the performance of the
0006 intel_pstate driver. This utility can be used in two ways:
0007 - If there is Linux trace file with pstate_sample events enabled, then
0008 this utility can parse the trace file and generate performance plots.
0009 - If user has not specified a trace file as input via command line parameters,
0010 then this utility enables and collects trace data for a user specified interval
0011 and generates performance plots.
0012 
0013 Prerequisites:
0014     Python version 2.7.x or higher
0015     gnuplot 5.0 or higher
0016     gnuplot-py 1.8 or higher
0017     (Most of the distributions have these required packages. They may be called
0018      gnuplot-py, phython-gnuplot or phython3-gnuplot, gnuplot-nox, ... )
0019 
0020     HWP (Hardware P-States are disabled)
0021     Kernel config for Linux trace is enabled
0022 
0023     see print_help(): for Usage and Output details
0024 
0025 """
0026 from __future__ import print_function
0027 from datetime import datetime
0028 import subprocess
0029 import os
0030 import time
0031 import re
0032 import signal
0033 import sys
0034 import getopt
0035 import Gnuplot
0036 from numpy import *
0037 from decimal import *
0038 
0039 __author__ = "Srinivas Pandruvada"
0040 __copyright__ = " Copyright (c) 2017, Intel Corporation. "
0041 __license__ = "GPL version 2"
0042 
0043 
0044 MAX_CPUS = 256
0045 
0046 # Define the csv file columns
0047 C_COMM = 18
0048 C_GHZ = 17
0049 C_ELAPSED = 16
0050 C_SAMPLE = 15
0051 C_DURATION = 14
0052 C_LOAD = 13
0053 C_BOOST = 12
0054 C_FREQ = 11
0055 C_TSC = 10
0056 C_APERF = 9
0057 C_MPERF = 8
0058 C_TO = 7
0059 C_FROM = 6
0060 C_SCALED = 5
0061 C_CORE = 4
0062 C_USEC = 3
0063 C_SEC = 2
0064 C_CPU = 1
0065 
0066 global sample_num, last_sec_cpu, last_usec_cpu, start_time, testname, trace_file
0067 
0068 # 11 digits covers uptime to 115 days
0069 getcontext().prec = 11
0070 
0071 sample_num =0
0072 last_sec_cpu = [0] * MAX_CPUS
0073 last_usec_cpu = [0] * MAX_CPUS
0074 
0075 def print_help(driver_name):
0076     print('%s_tracer.py:'%driver_name)
0077     print('  Usage:')
0078     print('    If the trace file is available, then to simply parse and plot, use (sudo not required):')
0079     print('      ./%s_tracer.py [-c cpus] -t <trace_file> -n <test_name>'%driver_name)
0080     print('    Or')
0081     print('      ./%s_tracer.py [--cpu cpus] ---trace_file <trace_file> --name <test_name>'%driver_name)
0082     print('    To generate trace file, parse and plot, use (sudo required):')
0083     print('      sudo ./%s_tracer.py [-c cpus] -i <interval> -n <test_name> -m <kbytes>'%driver_name)
0084     print('    Or')
0085     print('      sudo ./%s_tracer.py [--cpu cpus] --interval <interval> --name <test_name> --memory <kbytes>'%driver_name)
0086     print('    Optional argument:')
0087     print('      cpus:   comma separated list of CPUs')
0088     print('      kbytes: Kilo bytes of memory per CPU to allocate to the trace buffer. Default: 10240')
0089     print('  Output:')
0090     print('    If not already present, creates a "results/test_name" folder in the current working directory with:')
0091     print('      cpu.csv - comma seperated values file with trace contents and some additional calculations.')
0092     print('      cpu???.csv - comma seperated values file for CPU number ???.')
0093     print('      *.png - a variety of PNG format plot files created from the trace contents and the additional calculations.')
0094     print('  Notes:')
0095     print('    Avoid the use of _ (underscore) in test names, because in gnuplot it is a subscript directive.')
0096     print('    Maximum number of CPUs is {0:d}. If there are more the script will abort with an error.'.format(MAX_CPUS))
0097     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.')
0098     print('    Empty y range warnings for autoscaled plots can occur and can be ignored.')
0099 
0100 def plot_perf_busy_with_sample(cpu_index):
0101     """ Plot method to per cpu information """
0102 
0103     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
0104     if os.path.exists(file_name):
0105         output_png = "cpu%03d_perf_busy_vs_samples.png" % cpu_index
0106         g_plot = common_all_gnuplot_settings(output_png)
0107 #   autoscale this one, no set y1 range
0108         g_plot('set y2range [0:200]')
0109         g_plot('set y2tics 0, 10')
0110         g_plot('set title "{} : cpu perf busy vs. sample : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
0111 #       Override common
0112         g_plot('set xlabel "Samples"')
0113         g_plot('set ylabel "P-State"')
0114         g_plot('set y2label "Scaled Busy/performance/io-busy(%)"')
0115         set_4_plot_linestyles(g_plot)
0116         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_SAMPLE, C_CORE))
0117         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_SAMPLE, C_SCALED))
0118         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_SAMPLE, C_BOOST))
0119         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_SAMPLE, C_TO))
0120 
0121 def plot_perf_busy(cpu_index):
0122     """ Plot some per cpu information """
0123 
0124     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
0125     if os.path.exists(file_name):
0126         output_png = "cpu%03d_perf_busy.png" % cpu_index
0127         g_plot = common_all_gnuplot_settings(output_png)
0128 #   autoscale this one, no set y1 range
0129         g_plot('set y2range [0:200]')
0130         g_plot('set y2tics 0, 10')
0131         g_plot('set title "{} : perf busy : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
0132         g_plot('set ylabel "P-State"')
0133         g_plot('set y2label "Scaled Busy/performance/io-busy(%)"')
0134         set_4_plot_linestyles(g_plot)
0135         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_ELAPSED, C_CORE))
0136         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_ELAPSED, C_SCALED))
0137         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_ELAPSED, C_BOOST))
0138         g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_ELAPSED, C_TO))
0139 
0140 def plot_durations(cpu_index):
0141     """ Plot per cpu durations """
0142 
0143     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
0144     if os.path.exists(file_name):
0145         output_png = "cpu%03d_durations.png" % cpu_index
0146         g_plot = common_all_gnuplot_settings(output_png)
0147 #       autoscale this one, no set y range
0148         g_plot('set title "{} : durations : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
0149         g_plot('set ylabel "Timer Duration (MilliSeconds)"')
0150 #       override common
0151         g_plot('set key off')
0152         set_4_plot_linestyles(g_plot)
0153         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_DURATION))
0154 
0155 def plot_loads(cpu_index):
0156     """ Plot per cpu loads """
0157 
0158     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
0159     if os.path.exists(file_name):
0160         output_png = "cpu%03d_loads.png" % cpu_index
0161         g_plot = common_all_gnuplot_settings(output_png)
0162         g_plot('set yrange [0:100]')
0163         g_plot('set ytics 0, 10')
0164         g_plot('set title "{} : loads : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
0165         g_plot('set ylabel "CPU load (percent)"')
0166 #       override common
0167         g_plot('set key off')
0168         set_4_plot_linestyles(g_plot)
0169         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_LOAD))
0170 
0171 def plot_pstate_cpu_with_sample():
0172     """ Plot all cpu information """
0173 
0174     if os.path.exists('cpu.csv'):
0175         output_png = 'all_cpu_pstates_vs_samples.png'
0176         g_plot = common_all_gnuplot_settings(output_png)
0177 #       autoscale this one, no set y range
0178 #       override common
0179         g_plot('set xlabel "Samples"')
0180         g_plot('set ylabel "P-State"')
0181         g_plot('set title "{} : cpu pstate vs. sample : {:%F %H:%M}"'.format(testname, datetime.now()))
0182         title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0183         plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_SAMPLE, C_TO)
0184         g_plot('title_list = "{}"'.format(title_list))
0185         g_plot(plot_str)
0186 
0187 def plot_pstate_cpu():
0188     """ Plot all cpu information from csv files """
0189 
0190     output_png = 'all_cpu_pstates.png'
0191     g_plot = common_all_gnuplot_settings(output_png)
0192 #   autoscale this one, no set y range
0193     g_plot('set ylabel "P-State"')
0194     g_plot('set title "{} : cpu pstates : {:%F %H:%M}"'.format(testname, datetime.now()))
0195 
0196 #    the following command is really cool, but doesn't work with the CPU masking option because it aborts on the first missing file.
0197 #    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'
0198 #
0199     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0200     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_TO)
0201     g_plot('title_list = "{}"'.format(title_list))
0202     g_plot(plot_str)
0203 
0204 def plot_load_cpu():
0205     """ Plot all cpu loads """
0206 
0207     output_png = 'all_cpu_loads.png'
0208     g_plot = common_all_gnuplot_settings(output_png)
0209     g_plot('set yrange [0:100]')
0210     g_plot('set ylabel "CPU load (percent)"')
0211     g_plot('set title "{} : cpu loads : {:%F %H:%M}"'.format(testname, datetime.now()))
0212 
0213     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0214     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_LOAD)
0215     g_plot('title_list = "{}"'.format(title_list))
0216     g_plot(plot_str)
0217 
0218 def plot_frequency_cpu():
0219     """ Plot all cpu frequencies """
0220 
0221     output_png = 'all_cpu_frequencies.png'
0222     g_plot = common_all_gnuplot_settings(output_png)
0223 #   autoscale this one, no set y range
0224     g_plot('set ylabel "CPU Frequency (GHz)"')
0225     g_plot('set title "{} : cpu frequencies : {:%F %H:%M}"'.format(testname, datetime.now()))
0226 
0227     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0228     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_FREQ)
0229     g_plot('title_list = "{}"'.format(title_list))
0230     g_plot(plot_str)
0231 
0232 def plot_duration_cpu():
0233     """ Plot all cpu durations """
0234 
0235     output_png = 'all_cpu_durations.png'
0236     g_plot = common_all_gnuplot_settings(output_png)
0237 #   autoscale this one, no set y range
0238     g_plot('set ylabel "Timer Duration (MilliSeconds)"')
0239     g_plot('set title "{} : cpu durations : {:%F %H:%M}"'.format(testname, datetime.now()))
0240 
0241     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0242     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_DURATION)
0243     g_plot('title_list = "{}"'.format(title_list))
0244     g_plot(plot_str)
0245 
0246 def plot_scaled_cpu():
0247     """ Plot all cpu scaled busy """
0248 
0249     output_png = 'all_cpu_scaled.png'
0250     g_plot = common_all_gnuplot_settings(output_png)
0251 #   autoscale this one, no set y range
0252     g_plot('set ylabel "Scaled Busy (Unitless)"')
0253     g_plot('set title "{} : cpu scaled busy : {:%F %H:%M}"'.format(testname, datetime.now()))
0254 
0255     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0256     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_SCALED)
0257     g_plot('title_list = "{}"'.format(title_list))
0258     g_plot(plot_str)
0259 
0260 def plot_boost_cpu():
0261     """ Plot all cpu IO Boosts """
0262 
0263     output_png = 'all_cpu_boost.png'
0264     g_plot = common_all_gnuplot_settings(output_png)
0265     g_plot('set yrange [0:100]')
0266     g_plot('set ylabel "CPU IO Boost (percent)"')
0267     g_plot('set title "{} : cpu io boost : {:%F %H:%M}"'.format(testname, datetime.now()))
0268 
0269     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0270     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_BOOST)
0271     g_plot('title_list = "{}"'.format(title_list))
0272     g_plot(plot_str)
0273 
0274 def plot_ghz_cpu():
0275     """ Plot all cpu tsc ghz """
0276 
0277     output_png = 'all_cpu_ghz.png'
0278     g_plot = common_all_gnuplot_settings(output_png)
0279 #   autoscale this one, no set y range
0280     g_plot('set ylabel "TSC Frequency (GHz)"')
0281     g_plot('set title "{} : cpu TSC Frequencies (Sanity check calculation) : {:%F %H:%M}"'.format(testname, datetime.now()))
0282 
0283     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
0284     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_GHZ)
0285     g_plot('title_list = "{}"'.format(title_list))
0286     g_plot(plot_str)
0287 
0288 def common_all_gnuplot_settings(output_png):
0289     """ common gnuplot settings for multiple CPUs one one graph. """
0290 
0291     g_plot = common_gnuplot_settings()
0292     g_plot('set output "' + output_png + '"')
0293     return(g_plot)
0294 
0295 def common_gnuplot_settings():
0296     """ common gnuplot settings. """
0297 
0298     g_plot = Gnuplot.Gnuplot(persist=1)
0299 #   The following line is for rigor only. It seems to be assumed for .csv files
0300     g_plot('set datafile separator \",\"')
0301     g_plot('set ytics nomirror')
0302     g_plot('set xtics nomirror')
0303     g_plot('set xtics font ", 10"')
0304     g_plot('set ytics font ", 10"')
0305     g_plot('set tics out scale 1.0')
0306     g_plot('set grid')
0307     g_plot('set key out horiz')
0308     g_plot('set key bot center')
0309     g_plot('set key samplen 2 spacing .8 font ", 9"')
0310     g_plot('set term png size 1200, 600')
0311     g_plot('set title font ", 11"')
0312     g_plot('set ylabel font ", 10"')
0313     g_plot('set xlabel font ", 10"')
0314     g_plot('set xlabel offset 0, 0.5')
0315     g_plot('set xlabel "Elapsed Time (Seconds)"')
0316     return(g_plot)
0317 
0318 def set_4_plot_linestyles(g_plot):
0319     """ set the linestyles used for 4 plots in 1 graphs. """
0320 
0321     g_plot('set style line 1 linetype 1 linecolor rgb "green" pointtype -1')
0322     g_plot('set style line 2 linetype 1 linecolor rgb "red" pointtype -1')
0323     g_plot('set style line 3 linetype 1 linecolor rgb "purple" pointtype -1')
0324     g_plot('set style line 4 linetype 1 linecolor rgb "blue" pointtype -1')
0325 
0326 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):
0327     """ Store master csv file information """
0328 
0329     global graph_data_present
0330 
0331     if cpu_mask[cpu_int] == 0:
0332         return
0333 
0334     try:
0335         f_handle = open('cpu.csv', 'a')
0336         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)
0337         f_handle.write(string_buffer);
0338         f_handle.close()
0339     except:
0340         print('IO error cpu.csv')
0341         return
0342 
0343     graph_data_present = True;
0344 
0345 def split_csv(current_max_cpu, cpu_mask):
0346     """ seperate the all csv file into per CPU csv files. """
0347 
0348     if os.path.exists('cpu.csv'):
0349         for index in range(0, current_max_cpu + 1):
0350             if cpu_mask[int(index)] != 0:
0351                 os.system('grep -m 1 common_cpu cpu.csv > cpu{:0>3}.csv'.format(index))
0352                 os.system('grep CPU_{:0>3} cpu.csv >> cpu{:0>3}.csv'.format(index, index))
0353 
0354 def fix_ownership(path):
0355     """Change the owner of the file to SUDO_UID, if required"""
0356 
0357     uid = os.environ.get('SUDO_UID')
0358     gid = os.environ.get('SUDO_GID')
0359     if uid is not None:
0360         os.chown(path, int(uid), int(gid))
0361 
0362 def cleanup_data_files():
0363     """ clean up existing data files """
0364 
0365     if os.path.exists('cpu.csv'):
0366         os.remove('cpu.csv')
0367     f_handle = open('cpu.csv', 'a')
0368     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')
0369     f_handle.write('\n')
0370     f_handle.close()
0371 
0372 def clear_trace_file():
0373     """ Clear trace file """
0374 
0375     try:
0376         f_handle = open('/sys/kernel/debug/tracing/trace', 'w')
0377         f_handle.close()
0378     except:
0379         print('IO error clearing trace file ')
0380         sys.exit(2)
0381 
0382 def enable_trace(trace_file):
0383     """ Enable trace """
0384 
0385     try:
0386         open(trace_file,'w').write("1")
0387     except:
0388         print('IO error enabling trace ')
0389         sys.exit(2)
0390 
0391 def disable_trace(trace_file):
0392     """ Disable trace """
0393 
0394     try:
0395        open(trace_file, 'w').write("0")
0396     except:
0397         print('IO error disabling trace ')
0398         sys.exit(2)
0399 
0400 def set_trace_buffer_size(memory):
0401     """ Set trace buffer size """
0402 
0403     try:
0404        with open('/sys/kernel/debug/tracing/buffer_size_kb', 'w') as fp:
0405           fp.write(memory)
0406     except:
0407        print('IO error setting trace buffer size ')
0408        sys.exit(2)
0409 
0410 def free_trace_buffer():
0411     """ Free the trace buffer memory """
0412 
0413     try:
0414        open('/sys/kernel/debug/tracing/buffer_size_kb'
0415                  , 'w').write("1")
0416     except:
0417         print('IO error freeing trace buffer ')
0418         sys.exit(2)
0419 
0420 def read_trace_data(filename, cpu_mask):
0421     """ Read and parse trace data """
0422 
0423     global current_max_cpu
0424     global sample_num, last_sec_cpu, last_usec_cpu, start_time
0425 
0426     try:
0427         data = open(filename, 'r').read()
0428     except:
0429         print('Error opening ', filename)
0430         sys.exit(2)
0431 
0432     for line in data.splitlines():
0433         search_obj = \
0434             re.search(r'(^(.*?)\[)((\d+)[^\]])(.*?)(\d+)([.])(\d+)(.*?core_busy=)(\d+)(.*?scaled=)(\d+)(.*?from=)(\d+)(.*?to=)(\d+)(.*?mperf=)(\d+)(.*?aperf=)(\d+)(.*?tsc=)(\d+)(.*?freq=)(\d+)'
0435                       , line)
0436 
0437         if search_obj:
0438             cpu = search_obj.group(3)
0439             cpu_int = int(cpu)
0440             cpu = str(cpu_int)
0441 
0442             time_pre_dec = search_obj.group(6)
0443             time_post_dec = search_obj.group(8)
0444             core_busy = search_obj.group(10)
0445             scaled = search_obj.group(12)
0446             _from = search_obj.group(14)
0447             _to = search_obj.group(16)
0448             mperf = search_obj.group(18)
0449             aperf = search_obj.group(20)
0450             tsc = search_obj.group(22)
0451             freq = search_obj.group(24)
0452             common_comm = search_obj.group(2).replace(' ', '')
0453 
0454             # Not all kernel versions have io_boost field
0455             io_boost = '0'
0456             search_obj = re.search(r'.*?io_boost=(\d+)', line)
0457             if search_obj:
0458                 io_boost = search_obj.group(1)
0459 
0460             if sample_num == 0 :
0461                 start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000)
0462             sample_num += 1
0463 
0464             if last_sec_cpu[cpu_int] == 0 :
0465                 last_sec_cpu[cpu_int] = time_pre_dec
0466                 last_usec_cpu[cpu_int] = time_post_dec
0467             else :
0468                 duration_us = (int(time_pre_dec) - int(last_sec_cpu[cpu_int])) * 1000000 + (int(time_post_dec) - int(last_usec_cpu[cpu_int]))
0469                 duration_ms = Decimal(duration_us) / Decimal(1000)
0470                 last_sec_cpu[cpu_int] = time_pre_dec
0471                 last_usec_cpu[cpu_int] = time_post_dec
0472                 elapsed_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000) - start_time
0473                 load = Decimal(int(mperf)*100)/ Decimal(tsc)
0474                 freq_ghz = Decimal(freq)/Decimal(1000000)
0475 #               Sanity check calculation, typically anomalies indicate missed samples
0476 #               However, check for 0 (should never occur)
0477                 tsc_ghz = Decimal(0)
0478                 if duration_ms != Decimal(0) :
0479                     tsc_ghz = Decimal(tsc)/duration_ms/Decimal(1000000)
0480                 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)
0481 
0482             if cpu_int > current_max_cpu:
0483                 current_max_cpu = cpu_int
0484 # End of for each trace line loop
0485 # Now seperate the main overall csv file into per CPU csv files.
0486     split_csv(current_max_cpu, cpu_mask)
0487 
0488 def signal_handler(signal, frame):
0489     print(' SIGINT: Forcing cleanup before exit.')
0490     if interval:
0491         disable_trace(trace_file)
0492         clear_trace_file()
0493         # Free the memory
0494         free_trace_buffer()
0495         sys.exit(0)
0496 
0497 if __name__ == "__main__":
0498     trace_file = "/sys/kernel/debug/tracing/events/power/pstate_sample/enable"
0499     signal.signal(signal.SIGINT, signal_handler)
0500 
0501     interval = ""
0502     filename = ""
0503     cpu_list = ""
0504     testname = ""
0505     memory = "10240"
0506     graph_data_present = False;
0507 
0508     valid1 = False
0509     valid2 = False
0510 
0511     cpu_mask = zeros((MAX_CPUS,), dtype=int)
0512 
0513     try:
0514         opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:m:",["help","trace_file=","interval=","cpu=","name=","memory="])
0515     except getopt.GetoptError:
0516         print_help('intel_pstate')
0517         sys.exit(2)
0518     for opt, arg in opts:
0519         if opt == '-h':
0520             print_help('intel_pstate')
0521             sys.exit()
0522         elif opt in ("-t", "--trace_file"):
0523             valid1 = True
0524             location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
0525             filename = os.path.join(location, arg)
0526         elif opt in ("-i", "--interval"):
0527             valid1 = True
0528             interval = arg
0529         elif opt in ("-c", "--cpu"):
0530             cpu_list = arg
0531         elif opt in ("-n", "--name"):
0532             valid2 = True
0533             testname = arg
0534         elif opt in ("-m", "--memory"):
0535             memory = arg
0536 
0537     if not (valid1 and valid2):
0538         print_help('intel_pstate')
0539         sys.exit()
0540 
0541     if cpu_list:
0542         for p in re.split("[,]", cpu_list):
0543             if int(p) < MAX_CPUS :
0544                 cpu_mask[int(p)] = 1
0545     else:
0546         for i in range (0, MAX_CPUS):
0547             cpu_mask[i] = 1
0548 
0549     if not os.path.exists('results'):
0550         os.mkdir('results')
0551         # The regular user needs to own the directory, not root.
0552         fix_ownership('results')
0553 
0554     os.chdir('results')
0555     if os.path.exists(testname):
0556         print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.')
0557         sys.exit()
0558     os.mkdir(testname)
0559     # The regular user needs to own the directory, not root.
0560     fix_ownership(testname)
0561     os.chdir(testname)
0562 
0563     # Temporary (or perhaps not)
0564     cur_version = sys.version_info
0565     print('python version (should be >= 2.7):')
0566     print(cur_version)
0567 
0568     # Left as "cleanup" for potential future re-run ability.
0569     cleanup_data_files()
0570 
0571     if interval:
0572         filename = "/sys/kernel/debug/tracing/trace"
0573         clear_trace_file()
0574         set_trace_buffer_size(memory)
0575         enable_trace(trace_file)
0576         print('Sleeping for ', interval, 'seconds')
0577         time.sleep(int(interval))
0578         disable_trace(trace_file)
0579 
0580     current_max_cpu = 0
0581 
0582     read_trace_data(filename, cpu_mask)
0583 
0584     if interval:
0585         clear_trace_file()
0586         # Free the memory
0587         free_trace_buffer()
0588 
0589     if graph_data_present == False:
0590         print('No valid data to plot')
0591         sys.exit(2)
0592 
0593     for cpu_no in range(0, current_max_cpu + 1):
0594         plot_perf_busy_with_sample(cpu_no)
0595         plot_perf_busy(cpu_no)
0596         plot_durations(cpu_no)
0597         plot_loads(cpu_no)
0598 
0599     plot_pstate_cpu_with_sample()
0600     plot_pstate_cpu()
0601     plot_load_cpu()
0602     plot_frequency_cpu()
0603     plot_duration_cpu()
0604     plot_scaled_cpu()
0605     plot_boost_cpu()
0606     plot_ghz_cpu()
0607 
0608     # It is preferrable, but not necessary, that the regular user owns the files, not root.
0609     for root, dirs, files in os.walk('.'):
0610         for f in files:
0611             fix_ownership(f)
0612 
0613     os.chdir('../../')