1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2015
4 * Authors: Yannick Fertre <yannick.fertre@st.com>
5 * Hugues Fruchet <hugues.fruchet@st.com>
8 #include <linux/debugfs.h>
13 static void format_ctx(struct seq_file
*s
, struct hva_ctx
*ctx
)
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
;
21 seq_printf(s
, "|-%s\n |\n", ctx
->name
);
23 seq_printf(s
, " |-[%sframe info]\n",
24 ctx
->flags
& HVA_FLAG_FRAMEINFO
? "" : "default ");
25 seq_printf(s
, " | |- pixel format=%4.4s\n"
27 " | |- wxh (w/ encoder alignment constraint)=%dx%d\n"
29 (char *)&frame
->pixelformat
,
30 frame
->width
, frame
->height
,
31 frame
->aligned_width
, frame
->aligned_height
);
33 seq_printf(s
, " |-[%sstream info]\n",
34 ctx
->flags
& HVA_FLAG_STREAMINFO
? "" : "default ");
35 seq_printf(s
, " | |- stream format=%4.4s\n"
40 (char *)&stream
->streamformat
,
41 stream
->width
, stream
->height
,
42 stream
->profile
, stream
->level
);
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"
50 " | |- video aspect=%s\n"
51 " | |- framerate=%d/%d\n",
52 v4l2_ctrl_get_menu(bitrate_mode
)[ctrls
->bitrate_mode
],
55 v4l2_ctrl_get_menu(aspect
)[ctrls
->aspect
],
56 ctrls
->time_per_frame
.denominator
,
57 ctrls
->time_per_frame
.numerator
);
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"
68 " | |- PAR enable=%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
],
74 ctrls
->dct8x8
? "true" : "false",
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
]);
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"
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",
117 * performance debug info
119 void hva_dbg_perf_begin(struct hva_ctx
*ctx
)
124 struct hva_ctx_dbg
*dbg
= &ctx
->dbg
;
125 ktime_t prev
= dbg
->begin
;
127 dbg
->begin
= ktime_get();
129 if (dbg
->is_valid_period
) {
130 /* encoding period */
131 div
= (u64
)ktime_us_delta(dbg
->begin
, prev
);
134 dbg
->min_period
= min(period
, dbg
->min_period
);
135 dbg
->max_period
= max(period
, dbg
->max_period
);
136 dbg
->total_period
+= period
;
140 * minimum and maximum bitrates are based on the
141 * encoding period values upon a window of 32 samples
143 dbg
->window_duration
+= period
;
145 if (dbg
->cnt_window
>= 32) {
147 * bitrate in kbps = (size * 8 / 1000) /
149 * = size * 80 / duration
151 if (dbg
->window_duration
> 0) {
152 div
= (u64
)dbg
->window_stream_size
* 80;
153 do_div(div
, dbg
->window_duration
);
155 dbg
->last_bitrate
= bitrate
;
156 dbg
->min_bitrate
= min(bitrate
,
158 dbg
->max_bitrate
= max(bitrate
,
161 dbg
->window_stream_size
= 0;
162 dbg
->window_duration
= 0;
168 * filter sequences valid for performance:
169 * - begin/begin (no stream available) is an invalid sequence
170 * - begin/end is a valid sequence
172 dbg
->is_valid_period
= false;
175 void hva_dbg_perf_end(struct hva_ctx
*ctx
, struct hva_stream
*stream
)
177 struct device
*dev
= ctx_to_dev(ctx
);
182 struct hva_ctx_dbg
*dbg
= &ctx
->dbg
;
183 ktime_t end
= ktime_get();
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
;
189 timestamp
= (u32
)div
;
191 /* encoding duration */
192 div
= (u64
)ktime_us_delta(end
, dbg
->begin
);
195 "%s perf stream[%d] dts=%d encoded using %d bytes in %d us",
197 stream
->vbuf
.sequence
,
199 bytesused
, (u32
)div
);
204 dbg
->min_duration
= min(duration
, dbg
->min_duration
);
205 dbg
->max_duration
= max(duration
, dbg
->max_duration
);
206 dbg
->total_duration
+= duration
;
210 * the average bitrate is based on the total stream size
211 * and the total encoding periods
213 dbg
->total_stream_size
+= bytesused
;
214 dbg
->window_stream_size
+= bytesused
;
216 dbg
->is_valid_period
= true;
219 static void hva_dbg_perf_compute(struct hva_ctx
*ctx
)
222 struct hva_ctx_dbg
*dbg
= &ctx
->dbg
;
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
;
229 dbg
->avg_duration
= 0;
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
;
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
;
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
;
256 if (dbg
->total_period
> 0) {
258 * bitrate in kbps = (video size * 8 / 1000) /
259 * (video duration / 10000)
260 * = video size * 80 / video duration
262 div
= (u64
)dbg
->total_stream_size
* 80;
263 do_div(div
, dbg
->total_period
);
264 dbg
->avg_bitrate
= (u32
)div
;
266 dbg
->avg_bitrate
= 0;
274 static int hva_dbg_device(struct seq_file
*s
, void *data
)
276 struct hva_dev
*hva
= s
->private;
278 seq_printf(s
, "[%s]\n", hva
->v4l2_dev
.name
);
279 seq_printf(s
, "registered as /dev/video%d\n", hva
->vdev
->num
);
284 static int hva_dbg_encoders(struct seq_file
*s
, void *data
)
286 struct hva_dev
*hva
= s
->private;
289 seq_printf(s
, "[encoders]\n|- %d registered encoders:\n",
290 hva
->nb_of_encoders
);
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
);
302 static int hva_dbg_last(struct seq_file
*s
, void *data
)
304 struct hva_dev
*hva
= s
->private;
305 struct hva_ctx
*last_ctx
= &hva
->dbg
.last_ctx
;
307 if (last_ctx
->flags
& HVA_FLAG_STREAMINFO
) {
308 seq_puts(s
, "[last encoding]\n");
310 hva_dbg_perf_compute(last_ctx
);
311 format_ctx(s
, last_ctx
);
313 seq_puts(s
, "[no information recorded about last encoding]\n");
319 static int hva_dbg_regs(struct seq_file
*s
, void *data
)
321 struct hva_dev
*hva
= s
->private;
323 hva_hw_dump_regs(hva
, s
);
328 #define hva_dbg_declare(name) \
329 static int hva_dbg_##name##_open(struct inode *i, struct file *f) \
331 return single_open(f, hva_dbg_##name, i->i_private); \
333 static const struct file_operations hva_dbg_##name##_fops = { \
334 .open = hva_dbg_##name##_open, \
336 .llseek = seq_lseek, \
337 .release = single_release, \
340 #define hva_dbg_create_entry(name) \
341 debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
342 &hva_dbg_##name##_fops)
344 hva_dbg_declare(device
);
345 hva_dbg_declare(encoders
);
346 hva_dbg_declare(last
);
347 hva_dbg_declare(regs
);
349 void hva_debugfs_create(struct hva_dev
*hva
)
351 hva
->dbg
.debugfs_entry
= debugfs_create_dir(HVA_NAME
, NULL
);
352 if (!hva
->dbg
.debugfs_entry
)
355 if (!hva_dbg_create_entry(device
))
358 if (!hva_dbg_create_entry(encoders
))
361 if (!hva_dbg_create_entry(last
))
364 if (!hva_dbg_create_entry(regs
))
370 hva_debugfs_remove(hva
);
373 void hva_debugfs_remove(struct hva_dev
*hva
)
375 debugfs_remove_recursive(hva
->dbg
.debugfs_entry
);
376 hva
->dbg
.debugfs_entry
= NULL
;
380 * context (instance) debug info
383 static int hva_dbg_ctx(struct seq_file
*s
, void *data
)
385 struct hva_ctx
*ctx
= s
->private;
387 seq_printf(s
, "[running encoding %d]\n", ctx
->id
);
389 hva_dbg_perf_compute(ctx
);
395 hva_dbg_declare(ctx
);
397 void hva_dbg_ctx_create(struct hva_ctx
*ctx
)
399 struct hva_dev
*hva
= ctx
->hva_dev
;
402 ctx
->dbg
.min_duration
= UINT_MAX
;
403 ctx
->dbg
.min_period
= UINT_MAX
;
404 ctx
->dbg
.min_bitrate
= UINT_MAX
;
406 snprintf(name
, sizeof(name
), "%d", hva
->instance_id
);
408 ctx
->dbg
.debugfs_entry
= debugfs_create_file(name
, 0444,
409 hva
->dbg
.debugfs_entry
,
410 ctx
, &hva_dbg_ctx_fops
);
413 void hva_dbg_ctx_remove(struct hva_ctx
*ctx
)
415 struct hva_dev
*hva
= ctx
->hva_dev
;
417 if (ctx
->flags
& HVA_FLAG_STREAMINFO
)
418 /* save context before removing */
419 memcpy(&hva
->dbg
.last_ctx
, ctx
, sizeof(*ctx
));
421 debugfs_remove(ctx
->dbg
.debugfs_entry
);