arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / tools / power / x86 / amd_pstate_tracer / amd_pstate_trace.py
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 AMD P-State driver. It imports intel_pstate_tracer to analyze AMD P-State
7 trace event.
8
9 Prerequisites:
10     Python version 2.7.x or higher
11     gnuplot 5.0 or higher
12     gnuplot-py 1.8 or higher
13     (Most of the distributions have these required packages. They may be called
14      gnuplot-py, phython-gnuplot or phython3-gnuplot, gnuplot-nox, ... )
15
16     Kernel config for Linux trace is enabled
17
18     see print_help(): for Usage and Output details
19
20 """
21 from __future__ import print_function
22 from datetime import datetime
23 import subprocess
24 import os
25 import time
26 import re
27 import signal
28 import sys
29 import getopt
30 import Gnuplot
31 from numpy import *
32 from decimal import *
33 sys.path.append(os.path.join(os.path.dirname(__file__), "..", "intel_pstate_tracer"))
34 import intel_pstate_tracer as ipt
35
36 __license__ = "GPL version 2"
37
38 MAX_CPUS = 256
39 # Define the csv file columns
40 C_COMM = 15
41 C_ELAPSED = 14
42 C_SAMPLE = 13
43 C_DURATION = 12
44 C_LOAD = 11
45 C_TSC = 10
46 C_APERF = 9
47 C_MPERF = 8
48 C_FREQ = 7
49 C_MAX_PERF = 6
50 C_DES_PERF = 5
51 C_MIN_PERF = 4
52 C_USEC = 3
53 C_SEC = 2
54 C_CPU = 1
55
56 global sample_num, last_sec_cpu, last_usec_cpu, start_time, test_name, trace_file
57
58 getcontext().prec = 11
59
60 sample_num =0
61 last_sec_cpu = [0] * MAX_CPUS
62 last_usec_cpu = [0] * MAX_CPUS
63
64 def plot_per_cpu_freq(cpu_index):
65     """ Plot per cpu frequency """
66
67     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
68     if os.path.exists(file_name):
69         output_png = "cpu%03d_frequency.png" % cpu_index
70         g_plot = ipt.common_gnuplot_settings()
71         g_plot('set output "' + output_png + '"')
72         g_plot('set yrange [0:7]')
73         g_plot('set ytics 0, 1')
74         g_plot('set ylabel "CPU Frequency (GHz)"')
75         g_plot('set title "{} : frequency : CPU {:0>3} : {:%F %H:%M}"'.format(test_name, cpu_index, datetime.now()))
76         g_plot('set ylabel "CPU frequency"')
77         g_plot('set key off')
78         ipt.set_4_plot_linestyles(g_plot)
79         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_FREQ))
80
81 def plot_per_cpu_des_perf(cpu_index):
82     """ Plot per cpu desired perf """
83
84     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
85     if os.path.exists(file_name):
86         output_png = "cpu%03d_des_perf.png" % cpu_index
87         g_plot = ipt.common_gnuplot_settings()
88         g_plot('set output "' + output_png + '"')
89         g_plot('set yrange [0:255]')
90         g_plot('set ylabel "des perf"')
91         g_plot('set title "{} : cpu des perf : CPU {:0>3} : {:%F %H:%M}"'.format(test_name, cpu_index, datetime.now()))
92         g_plot('set key off')
93         ipt.set_4_plot_linestyles(g_plot)
94         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_DES_PERF))
95
96 def plot_per_cpu_load(cpu_index):
97     """ Plot per cpu load """
98
99     file_name = 'cpu{:0>3}.csv'.format(cpu_index)
100     if os.path.exists(file_name):
101         output_png = "cpu%03d_load.png" % cpu_index
102         g_plot = ipt.common_gnuplot_settings()
103         g_plot('set output "' + output_png + '"')
104         g_plot('set yrange [0:100]')
105         g_plot('set ytics 0, 10')
106         g_plot('set ylabel "CPU load (percent)"')
107         g_plot('set title "{} : cpu load : CPU {:0>3} : {:%F %H:%M}"'.format(test_name, cpu_index, datetime.now()))
108         g_plot('set key off')
109         ipt.set_4_plot_linestyles(g_plot)
110         g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_LOAD))
111
112 def plot_all_cpu_frequency():
113     """ Plot all cpu frequencies """
114
115     output_png = 'all_cpu_frequencies.png'
116     g_plot = ipt.common_gnuplot_settings()
117     g_plot('set output "' + output_png + '"')
118     g_plot('set ylabel "CPU Frequency (GHz)"')
119     g_plot('set title "{} : cpu frequencies : {:%F %H:%M}"'.format(test_name, datetime.now()))
120
121     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
122     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_FREQ)
123     g_plot('title_list = "{}"'.format(title_list))
124     g_plot(plot_str)
125
126 def plot_all_cpu_des_perf():
127     """ Plot all cpu desired perf """
128
129     output_png = 'all_cpu_des_perf.png'
130     g_plot = ipt.common_gnuplot_settings()
131     g_plot('set output "' + output_png + '"')
132     g_plot('set ylabel "des perf"')
133     g_plot('set title "{} : cpu des perf : {:%F %H:%M}"'.format(test_name, datetime.now()))
134
135     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
136     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 255 ps 1 title i".format(C_ELAPSED, C_DES_PERF)
137     g_plot('title_list = "{}"'.format(title_list))
138     g_plot(plot_str)
139
140 def plot_all_cpu_load():
141     """ Plot all cpu load  """
142
143     output_png = 'all_cpu_load.png'
144     g_plot = ipt.common_gnuplot_settings()
145     g_plot('set output "' + output_png + '"')
146     g_plot('set yrange [0:100]')
147     g_plot('set ylabel "CPU load (percent)"')
148     g_plot('set title "{} : cpu load : {:%F %H:%M}"'.format(test_name, datetime.now()))
149
150     title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).decode('utf-8').replace('\n', ' ')
151     plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 255 ps 1 title i".format(C_ELAPSED, C_LOAD)
152     g_plot('title_list = "{}"'.format(title_list))
153     g_plot(plot_str)
154
155 def store_csv(cpu_int, time_pre_dec, time_post_dec, min_perf, des_perf, max_perf, freq_ghz, mperf, aperf, tsc, common_comm, load, duration_ms, sample_num, elapsed_time, cpu_mask):
156     """ Store master csv file information """
157
158     global graph_data_present
159
160     if cpu_mask[cpu_int] == 0:
161         return
162
163     try:
164         f_handle = open('cpu.csv', 'a')
165         string_buffer = "CPU_%03u, %05u, %06u, %u, %u, %u, %.4f, %u, %u, %u, %.2f, %.3f, %u, %.3f, %s\n" % (cpu_int, int(time_pre_dec), int(time_post_dec), int(min_perf), int(des_perf), int(max_perf), freq_ghz, int(mperf), int(aperf), int(tsc), load, duration_ms, sample_num, elapsed_time, common_comm)
166         f_handle.write(string_buffer)
167         f_handle.close()
168     except:
169         print('IO error cpu.csv')
170         return
171
172     graph_data_present = True;
173
174
175 def cleanup_data_files():
176     """ clean up existing data files """
177
178     if os.path.exists('cpu.csv'):
179         os.remove('cpu.csv')
180     f_handle = open('cpu.csv', 'a')
181     f_handle.write('common_cpu, common_secs, common_usecs, min_perf, des_perf, max_perf, freq, mperf, aperf, tsc, load, duration_ms, sample_num, elapsed_time, common_comm')
182     f_handle.write('\n')
183     f_handle.close()
184
185 def read_trace_data(file_name, cpu_mask):
186     """ Read and parse trace data """
187
188     global current_max_cpu
189     global sample_num, last_sec_cpu, last_usec_cpu, start_time
190
191     try:
192         data = open(file_name, 'r').read()
193     except:
194         print('Error opening ', file_name)
195         sys.exit(2)
196
197     for line in data.splitlines():
198         search_obj = \
199             re.search(r'(^(.*?)\[)((\d+)[^\]])(.*?)(\d+)([.])(\d+)(.*?amd_min_perf=)(\d+)(.*?amd_des_perf=)(\d+)(.*?amd_max_perf=)(\d+)(.*?freq=)(\d+)(.*?mperf=)(\d+)(.*?aperf=)(\d+)(.*?tsc=)(\d+)'
200                       , line)
201
202         if search_obj:
203             cpu = search_obj.group(3)
204             cpu_int = int(cpu)
205             cpu = str(cpu_int)
206
207             time_pre_dec = search_obj.group(6)
208             time_post_dec = search_obj.group(8)
209             min_perf = search_obj.group(10)
210             des_perf = search_obj.group(12)
211             max_perf = search_obj.group(14)
212             freq = search_obj.group(16)
213             mperf = search_obj.group(18)
214             aperf = search_obj.group(20)
215             tsc = search_obj.group(22)
216
217             common_comm = search_obj.group(2).replace(' ', '')
218
219             if sample_num == 0 :
220                 start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000)
221             sample_num += 1
222
223             if last_sec_cpu[cpu_int] == 0 :
224                 last_sec_cpu[cpu_int] = time_pre_dec
225                 last_usec_cpu[cpu_int] = time_post_dec
226             else :
227                 duration_us = (int(time_pre_dec) - int(last_sec_cpu[cpu_int])) * 1000000 + (int(time_post_dec) - int(last_usec_cpu[cpu_int]))
228                 duration_ms = Decimal(duration_us) / Decimal(1000)
229                 last_sec_cpu[cpu_int] = time_pre_dec
230                 last_usec_cpu[cpu_int] = time_post_dec
231                 elapsed_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000) - start_time
232                 load = Decimal(int(mperf)*100)/ Decimal(tsc)
233                 freq_ghz = Decimal(freq)/Decimal(1000000)
234                 store_csv(cpu_int, time_pre_dec, time_post_dec, min_perf, des_perf, max_perf, freq_ghz, mperf, aperf, tsc, common_comm, load, duration_ms, sample_num, elapsed_time, cpu_mask)
235
236             if cpu_int > current_max_cpu:
237                 current_max_cpu = cpu_int
238 # Now separate the main overall csv file into per CPU csv files.
239     ipt.split_csv(current_max_cpu, cpu_mask)
240
241
242 def signal_handler(signal, frame):
243     print(' SIGINT: Forcing cleanup before exit.')
244     if interval:
245         ipt.disable_trace(trace_file)
246         ipt.clear_trace_file()
247         ipt.free_trace_buffer()
248         sys.exit(0)
249
250 trace_file = "/sys/kernel/tracing/events/amd_cpu/enable"
251 signal.signal(signal.SIGINT, signal_handler)
252
253 interval = ""
254 file_name = ""
255 cpu_list = ""
256 test_name = ""
257 memory = "10240"
258 graph_data_present = False;
259
260 valid1 = False
261 valid2 = False
262
263 cpu_mask = zeros((MAX_CPUS,), dtype=int)
264
265
266 try:
267     opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:m:",["help","trace_file=","interval=","cpu=","name=","memory="])
268 except getopt.GetoptError:
269     ipt.print_help('amd_pstate')
270     sys.exit(2)
271 for opt, arg in opts:
272     if opt == '-h':
273         print()
274         sys.exit()
275     elif opt in ("-t", "--trace_file"):
276         valid1 = True
277         location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
278         file_name = os.path.join(location, arg)
279     elif opt in ("-i", "--interval"):
280         valid1 = True
281         interval = arg
282     elif opt in ("-c", "--cpu"):
283         cpu_list = arg
284     elif opt in ("-n", "--name"):
285         valid2 = True
286         test_name = arg
287     elif opt in ("-m", "--memory"):
288         memory = arg
289
290 if not (valid1 and valid2):
291     ipt.print_help('amd_pstate')
292     sys.exit()
293
294 if cpu_list:
295     for p in re.split("[,]", cpu_list):
296         if int(p) < MAX_CPUS :
297             cpu_mask[int(p)] = 1
298 else:
299     for i in range (0, MAX_CPUS):
300         cpu_mask[i] = 1
301
302 if not os.path.exists('results'):
303     os.mkdir('results')
304     ipt.fix_ownership('results')
305
306 os.chdir('results')
307 if os.path.exists(test_name):
308     print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.')
309     sys.exit()
310 os.mkdir(test_name)
311 ipt.fix_ownership(test_name)
312 os.chdir(test_name)
313
314 cur_version = sys.version_info
315 print('python version (should be >= 2.7):')
316 print(cur_version)
317
318 cleanup_data_files()
319
320 if interval:
321     file_name = "/sys/kernel/tracing/trace"
322     ipt.clear_trace_file()
323     ipt.set_trace_buffer_size(memory)
324     ipt.enable_trace(trace_file)
325     time.sleep(int(interval))
326     ipt.disable_trace(trace_file)
327
328 current_max_cpu = 0
329
330 read_trace_data(file_name, cpu_mask)
331
332 if interval:
333     ipt.clear_trace_file()
334     ipt.free_trace_buffer()
335
336 if graph_data_present == False:
337     print('No valid data to plot')
338     sys.exit(2)
339
340 for cpu_no in range(0, current_max_cpu + 1):
341     plot_per_cpu_freq(cpu_no)
342     plot_per_cpu_des_perf(cpu_no)
343     plot_per_cpu_load(cpu_no)
344
345 plot_all_cpu_des_perf()
346 plot_all_cpu_frequency()
347 plot_all_cpu_load()
348
349 for root, dirs, files in os.walk('.'):
350     for f in files:
351         ipt.fix_ownership(f)
352
353 os.chdir('../../')