accel/qaic: Add AIC200 support
[drm/drm-misc.git] / tools / power / x86 / amd_pstate_tracer / amd_pstate_trace.py
blobfeb9f9421c7bcd1e697cad70a17506790775fd90
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0-only
3 # -*- coding: utf-8 -*-
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.
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, ... )
16 Kernel config for Linux trace is enabled
18 see print_help(): for Usage and Output details
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
36 __license__ = "GPL version 2"
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
56 global sample_num, last_sec_cpu, last_usec_cpu, start_time, test_name, trace_file
58 getcontext().prec = 11
60 sample_num =0
61 last_sec_cpu = [0] * MAX_CPUS
62 last_usec_cpu = [0] * MAX_CPUS
64 def plot_per_cpu_freq(cpu_index):
65 """ Plot per cpu frequency """
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))
81 def plot_per_cpu_des_perf(cpu_index):
82 """ Plot per cpu desired perf """
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))
96 def plot_per_cpu_load(cpu_index):
97 """ Plot per cpu load """
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))
112 def plot_all_cpu_frequency():
113 """ Plot all cpu frequencies """
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()))
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)
126 def plot_all_cpu_des_perf():
127 """ Plot all cpu desired perf """
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()))
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)
140 def plot_all_cpu_load():
141 """ Plot all cpu load """
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()))
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)
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 """
158 global graph_data_present
160 if cpu_mask[cpu_int] == 0:
161 return
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
172 graph_data_present = True;
175 def cleanup_data_files():
176 """ clean up existing data files """
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()
185 def read_trace_data(file_name, cpu_mask):
186 """ Read and parse trace data """
188 global current_max_cpu
189 global sample_num, last_sec_cpu, last_usec_cpu, start_time
191 try:
192 data = open(file_name, 'r').read()
193 except:
194 print('Error opening ', file_name)
195 sys.exit(2)
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)
202 if search_obj:
203 cpu = search_obj.group(3)
204 cpu_int = int(cpu)
205 cpu = str(cpu_int)
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)
217 common_comm = search_obj.group(2).replace(' ', '')
219 if sample_num == 0 :
220 start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000)
221 sample_num += 1
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)
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)
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)
250 trace_file = "/sys/kernel/tracing/events/amd_cpu/enable"
251 signal.signal(signal.SIGINT, signal_handler)
253 interval = ""
254 file_name = ""
255 cpu_list = ""
256 test_name = ""
257 memory = "10240"
258 graph_data_present = False;
260 valid1 = False
261 valid2 = False
263 cpu_mask = zeros((MAX_CPUS,), dtype=int)
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
290 if not (valid1 and valid2):
291 ipt.print_help('amd_pstate')
292 sys.exit()
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
302 if not os.path.exists('results'):
303 os.mkdir('results')
304 ipt.fix_ownership('results')
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)
314 cur_version = sys.version_info
315 print('python version (should be >= 2.7):')
316 print(cur_version)
318 cleanup_data_files()
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)
328 current_max_cpu = 0
330 read_trace_data(file_name, cpu_mask)
332 if interval:
333 ipt.clear_trace_file()
334 ipt.free_trace_buffer()
336 if graph_data_present == False:
337 print('No valid data to plot')
338 sys.exit(2)
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)
345 plot_all_cpu_des_perf()
346 plot_all_cpu_frequency()
347 plot_all_cpu_load()
349 for root, dirs, files in os.walk('.'):
350 for f in files:
351 ipt.fix_ownership(f)
353 os.chdir('../../')