]>
Commit | Line | Data |
---|---|---|
9ed785a9 | 1 | // SPDX-License-Identifier: GPL-2.0 |
c610b5a8 JCT |
2 | /* |
3 | * Copyright (C) STMicroelectronics SA 2015 | |
4 | * Authors: Yannick Fertre <yannick.fertre@st.com> | |
5 | * Hugues Fruchet <hugues.fruchet@st.com> | |
c610b5a8 JCT |
6 | */ |
7 | ||
8 | #include <linux/debugfs.h> | |
9 | ||
10 | #include "hva.h" | |
11 | #include "hva-hw.h" | |
12 | ||
13 | static void format_ctx(struct seq_file *s, struct hva_ctx *ctx) | |
14 | { | |
15 | struct hva_streaminfo *stream = &ctx->streaminfo; | |
16 | struct hva_frameinfo *frame = &ctx->frameinfo; | |
17 | struct hva_controls *ctrls = &ctx->ctrls; | |
18 | struct hva_ctx_dbg *dbg = &ctx->dbg; | |
19 | u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp; | |
20 | ||
21 | seq_printf(s, "|-%s\n |\n", ctx->name); | |
22 | ||
23 | seq_printf(s, " |-[%sframe info]\n", | |
24 | ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default "); | |
25 | seq_printf(s, " | |- pixel format=%4.4s\n" | |
26 | " | |- wxh=%dx%d\n" | |
27 | " | |- wxh (w/ encoder alignment constraint)=%dx%d\n" | |
28 | " |\n", | |
29 | (char *)&frame->pixelformat, | |
30 | frame->width, frame->height, | |
31 | frame->aligned_width, frame->aligned_height); | |
32 | ||
33 | seq_printf(s, " |-[%sstream info]\n", | |
34 | ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default "); | |
35 | seq_printf(s, " | |- stream format=%4.4s\n" | |
36 | " | |- wxh=%dx%d\n" | |
37 | " | |- %s\n" | |
38 | " | |- %s\n" | |
39 | " |\n", | |
40 | (char *)&stream->streamformat, | |
41 | stream->width, stream->height, | |
42 | stream->profile, stream->level); | |
43 | ||
44 | bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE; | |
45 | aspect = V4L2_CID_MPEG_VIDEO_ASPECT; | |
46 | seq_puts(s, " |-[parameters]\n"); | |
47 | seq_printf(s, " | |- %s\n" | |
48 | " | |- bitrate=%d bps\n" | |
49 | " | |- GOP size=%d\n" | |
50 | " | |- video aspect=%s\n" | |
51 | " | |- framerate=%d/%d\n", | |
52 | v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode], | |
53 | ctrls->bitrate, | |
54 | ctrls->gop_size, | |
55 | v4l2_ctrl_get_menu(aspect)[ctrls->aspect], | |
56 | ctrls->time_per_frame.denominator, | |
57 | ctrls->time_per_frame.numerator); | |
58 | ||
59 | entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; | |
60 | vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC; | |
61 | sei_fp = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE; | |
62 | if (stream->streamformat == V4L2_PIX_FMT_H264) { | |
63 | seq_printf(s, " | |- %s entropy mode\n" | |
64 | " | |- CPB size=%d kB\n" | |
65 | " | |- DCT8x8 enable=%s\n" | |
66 | " | |- qpmin=%d\n" | |
67 | " | |- qpmax=%d\n" | |
68 | " | |- PAR enable=%s\n" | |
69 | " | |- PAR id=%s\n" | |
70 | " | |- SEI frame packing enable=%s\n" | |
71 | " | |- SEI frame packing type=%s\n", | |
72 | v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode], | |
73 | ctrls->cpb_size, | |
74 | ctrls->dct8x8 ? "true" : "false", | |
75 | ctrls->qpmin, | |
76 | ctrls->qpmax, | |
77 | ctrls->vui_sar ? "true" : "false", | |
78 | v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc], | |
79 | ctrls->sei_fp ? "true" : "false", | |
80 | v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]); | |
81 | } | |
82 | ||
83 | if (ctx->sys_errors || ctx->encode_errors || ctx->frame_errors) { | |
84 | seq_puts(s, " |\n |-[errors]\n"); | |
85 | seq_printf(s, " | |- system=%d\n" | |
86 | " | |- encoding=%d\n" | |
87 | " | |- frame=%d\n", | |
88 | ctx->sys_errors, | |
89 | ctx->encode_errors, | |
90 | ctx->frame_errors); | |
91 | } | |
92 | ||
93 | seq_puts(s, " |\n |-[performances]\n"); | |
94 | seq_printf(s, " | |- frames encoded=%d\n" | |
95 | " | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n" | |
96 | " | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n" | |
97 | " | |- avg fps (0.1Hz)=%d\n" | |
98 | " | |- max reachable fps (0.1Hz)=%d\n" | |
99 | " | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n" | |
100 | " | |- last bitrate (kbps)=%d\n", | |
101 | dbg->cnt_duration, | |
102 | dbg->avg_duration, | |
103 | dbg->min_duration, | |
104 | dbg->max_duration, | |
105 | dbg->avg_period, | |
106 | dbg->min_period, | |
107 | dbg->max_period, | |
108 | dbg->avg_fps, | |
109 | dbg->max_fps, | |
110 | dbg->avg_bitrate, | |
111 | dbg->min_bitrate, | |
112 | dbg->max_bitrate, | |
113 | dbg->last_bitrate); | |
114 | } | |
115 | ||
116 | /* | |
117 | * performance debug info | |
118 | */ | |
119 | void hva_dbg_perf_begin(struct hva_ctx *ctx) | |
120 | { | |
121 | u64 div; | |
122 | u32 period; | |
123 | u32 bitrate; | |
124 | struct hva_ctx_dbg *dbg = &ctx->dbg; | |
125 | ktime_t prev = dbg->begin; | |
126 | ||
127 | dbg->begin = ktime_get(); | |
128 | ||
129 | if (dbg->is_valid_period) { | |
130 | /* encoding period */ | |
131 | div = (u64)ktime_us_delta(dbg->begin, prev); | |
132 | do_div(div, 100); | |
133 | period = (u32)div; | |
134 | dbg->min_period = min(period, dbg->min_period); | |
135 | dbg->max_period = max(period, dbg->max_period); | |
136 | dbg->total_period += period; | |
137 | dbg->cnt_period++; | |
138 | ||
139 | /* | |
140 | * minimum and maximum bitrates are based on the | |
141 | * encoding period values upon a window of 32 samples | |
142 | */ | |
143 | dbg->window_duration += period; | |
144 | dbg->cnt_window++; | |
145 | if (dbg->cnt_window >= 32) { | |
146 | /* | |
147 | * bitrate in kbps = (size * 8 / 1000) / | |
148 | * (duration / 10000) | |
149 | * = size * 80 / duration | |
150 | */ | |
151 | if (dbg->window_duration > 0) { | |
152 | div = (u64)dbg->window_stream_size * 80; | |
153 | do_div(div, dbg->window_duration); | |
154 | bitrate = (u32)div; | |
155 | dbg->last_bitrate = bitrate; | |
156 | dbg->min_bitrate = min(bitrate, | |
157 | dbg->min_bitrate); | |
158 | dbg->max_bitrate = max(bitrate, | |
159 | dbg->max_bitrate); | |
160 | } | |
161 | dbg->window_stream_size = 0; | |
162 | dbg->window_duration = 0; | |
163 | dbg->cnt_window = 0; | |
164 | } | |
165 | } | |
166 | ||
167 | /* | |
168 | * filter sequences valid for performance: | |
169 | * - begin/begin (no stream available) is an invalid sequence | |
170 | * - begin/end is a valid sequence | |
171 | */ | |
172 | dbg->is_valid_period = false; | |
173 | } | |
174 | ||
175 | void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream) | |
176 | { | |
177 | struct device *dev = ctx_to_dev(ctx); | |
178 | u64 div; | |
179 | u32 duration; | |
180 | u32 bytesused; | |
181 | u32 timestamp; | |
182 | struct hva_ctx_dbg *dbg = &ctx->dbg; | |
183 | ktime_t end = ktime_get(); | |
184 | ||
185 | /* stream bytesused and timestamp in us */ | |
186 | bytesused = vb2_get_plane_payload(&stream->vbuf.vb2_buf, 0); | |
187 | div = stream->vbuf.vb2_buf.timestamp; | |
188 | do_div(div, 1000); | |
189 | timestamp = (u32)div; | |
190 | ||
191 | /* encoding duration */ | |
192 | div = (u64)ktime_us_delta(end, dbg->begin); | |
193 | ||
194 | dev_dbg(dev, | |
195 | "%s perf stream[%d] dts=%d encoded using %d bytes in %d us", | |
196 | ctx->name, | |
197 | stream->vbuf.sequence, | |
198 | timestamp, | |
199 | bytesused, (u32)div); | |
200 | ||
201 | do_div(div, 100); | |
202 | duration = (u32)div; | |
203 | ||
204 | dbg->min_duration = min(duration, dbg->min_duration); | |
205 | dbg->max_duration = max(duration, dbg->max_duration); | |
206 | dbg->total_duration += duration; | |
207 | dbg->cnt_duration++; | |
208 | ||
209 | /* | |
210 | * the average bitrate is based on the total stream size | |
211 | * and the total encoding periods | |
212 | */ | |
213 | dbg->total_stream_size += bytesused; | |
214 | dbg->window_stream_size += bytesused; | |
215 | ||
216 | dbg->is_valid_period = true; | |
217 | } | |
218 | ||
219 | static void hva_dbg_perf_compute(struct hva_ctx *ctx) | |
220 | { | |
221 | u64 div; | |
222 | struct hva_ctx_dbg *dbg = &ctx->dbg; | |
223 | ||
224 | if (dbg->cnt_duration > 0) { | |
225 | div = (u64)dbg->total_duration; | |
226 | do_div(div, dbg->cnt_duration); | |
227 | dbg->avg_duration = (u32)div; | |
228 | } else { | |
229 | dbg->avg_duration = 0; | |
230 | } | |
231 | ||
232 | if (dbg->total_duration > 0) { | |
233 | div = (u64)dbg->cnt_duration * 100000; | |
234 | do_div(div, dbg->total_duration); | |
235 | dbg->max_fps = (u32)div; | |
236 | } else { | |
237 | dbg->max_fps = 0; | |
238 | } | |
239 | ||
240 | if (dbg->cnt_period > 0) { | |
241 | div = (u64)dbg->total_period; | |
242 | do_div(div, dbg->cnt_period); | |
243 | dbg->avg_period = (u32)div; | |
244 | } else { | |
245 | dbg->avg_period = 0; | |
246 | } | |
247 | ||
248 | if (dbg->total_period > 0) { | |
249 | div = (u64)dbg->cnt_period * 100000; | |
250 | do_div(div, dbg->total_period); | |
251 | dbg->avg_fps = (u32)div; | |
252 | } else { | |
253 | dbg->avg_fps = 0; | |
254 | } | |
255 | ||
256 | if (dbg->total_period > 0) { | |
257 | /* | |
258 | * bitrate in kbps = (video size * 8 / 1000) / | |
259 | * (video duration / 10000) | |
260 | * = video size * 80 / video duration | |
261 | */ | |
262 | div = (u64)dbg->total_stream_size * 80; | |
263 | do_div(div, dbg->total_period); | |
264 | dbg->avg_bitrate = (u32)div; | |
265 | } else { | |
266 | dbg->avg_bitrate = 0; | |
267 | } | |
268 | } | |
269 | ||
270 | /* | |
271 | * device debug info | |
272 | */ | |
273 | ||
5e22c19f | 274 | static int device_show(struct seq_file *s, void *data) |
c610b5a8 JCT |
275 | { |
276 | struct hva_dev *hva = s->private; | |
277 | ||
278 | seq_printf(s, "[%s]\n", hva->v4l2_dev.name); | |
279 | seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num); | |
280 | ||
281 | return 0; | |
282 | } | |
283 | ||
5e22c19f | 284 | static int encoders_show(struct seq_file *s, void *data) |
c610b5a8 JCT |
285 | { |
286 | struct hva_dev *hva = s->private; | |
287 | unsigned int i = 0; | |
288 | ||
289 | seq_printf(s, "[encoders]\n|- %d registered encoders:\n", | |
290 | hva->nb_of_encoders); | |
291 | ||
292 | while (hva->encoders[i]) { | |
293 | seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name, | |
294 | (char *)&hva->encoders[i]->pixelformat, | |
295 | (char *)&hva->encoders[i]->streamformat); | |
296 | i++; | |
297 | } | |
298 | ||
299 | return 0; | |
300 | } | |
301 | ||
5e22c19f | 302 | static int last_show(struct seq_file *s, void *data) |
c610b5a8 JCT |
303 | { |
304 | struct hva_dev *hva = s->private; | |
305 | struct hva_ctx *last_ctx = &hva->dbg.last_ctx; | |
306 | ||
307 | if (last_ctx->flags & HVA_FLAG_STREAMINFO) { | |
308 | seq_puts(s, "[last encoding]\n"); | |
309 | ||
310 | hva_dbg_perf_compute(last_ctx); | |
311 | format_ctx(s, last_ctx); | |
312 | } else { | |
313 | seq_puts(s, "[no information recorded about last encoding]\n"); | |
314 | } | |
315 | ||
316 | return 0; | |
317 | } | |
318 | ||
5e22c19f | 319 | static int regs_show(struct seq_file *s, void *data) |
c610b5a8 JCT |
320 | { |
321 | struct hva_dev *hva = s->private; | |
322 | ||
323 | hva_hw_dump_regs(hva, s); | |
324 | ||
325 | return 0; | |
326 | } | |
327 | ||
c610b5a8 JCT |
328 | #define hva_dbg_create_entry(name) \ |
329 | debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \ | |
5e22c19f | 330 | &name##_fops) |
c610b5a8 | 331 | |
5e22c19f YL |
332 | DEFINE_SHOW_ATTRIBUTE(device); |
333 | DEFINE_SHOW_ATTRIBUTE(encoders); | |
334 | DEFINE_SHOW_ATTRIBUTE(last); | |
335 | DEFINE_SHOW_ATTRIBUTE(regs); | |
c610b5a8 JCT |
336 | |
337 | void hva_debugfs_create(struct hva_dev *hva) | |
338 | { | |
339 | hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL); | |
340 | if (!hva->dbg.debugfs_entry) | |
341 | goto err; | |
342 | ||
343 | if (!hva_dbg_create_entry(device)) | |
344 | goto err; | |
345 | ||
346 | if (!hva_dbg_create_entry(encoders)) | |
347 | goto err; | |
348 | ||
349 | if (!hva_dbg_create_entry(last)) | |
350 | goto err; | |
351 | ||
352 | if (!hva_dbg_create_entry(regs)) | |
353 | goto err; | |
354 | ||
355 | return; | |
356 | ||
357 | err: | |
358 | hva_debugfs_remove(hva); | |
359 | } | |
360 | ||
361 | void hva_debugfs_remove(struct hva_dev *hva) | |
362 | { | |
363 | debugfs_remove_recursive(hva->dbg.debugfs_entry); | |
364 | hva->dbg.debugfs_entry = NULL; | |
365 | } | |
366 | ||
367 | /* | |
368 | * context (instance) debug info | |
369 | */ | |
370 | ||
5e22c19f | 371 | static int ctx_show(struct seq_file *s, void *data) |
c610b5a8 JCT |
372 | { |
373 | struct hva_ctx *ctx = s->private; | |
374 | ||
375 | seq_printf(s, "[running encoding %d]\n", ctx->id); | |
376 | ||
377 | hva_dbg_perf_compute(ctx); | |
378 | format_ctx(s, ctx); | |
379 | ||
380 | return 0; | |
381 | } | |
382 | ||
5e22c19f | 383 | DEFINE_SHOW_ATTRIBUTE(ctx); |
c610b5a8 JCT |
384 | |
385 | void hva_dbg_ctx_create(struct hva_ctx *ctx) | |
386 | { | |
387 | struct hva_dev *hva = ctx->hva_dev; | |
388 | char name[4] = ""; | |
389 | ||
390 | ctx->dbg.min_duration = UINT_MAX; | |
391 | ctx->dbg.min_period = UINT_MAX; | |
392 | ctx->dbg.min_bitrate = UINT_MAX; | |
393 | ||
394 | snprintf(name, sizeof(name), "%d", hva->instance_id); | |
395 | ||
396 | ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444, | |
397 | hva->dbg.debugfs_entry, | |
5e22c19f | 398 | ctx, &ctx_fops); |
c610b5a8 JCT |
399 | } |
400 | ||
401 | void hva_dbg_ctx_remove(struct hva_ctx *ctx) | |
402 | { | |
403 | struct hva_dev *hva = ctx->hva_dev; | |
404 | ||
405 | if (ctx->flags & HVA_FLAG_STREAMINFO) | |
406 | /* save context before removing */ | |
407 | memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx)); | |
408 | ||
409 | debugfs_remove(ctx->dbg.debugfs_entry); | |
410 | } |