hva-debugfs.c (10178B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) STMicroelectronics SA 2015 4 * Authors: Yannick Fertre <yannick.fertre@st.com> 5 * Hugues Fruchet <hugues.fruchet@st.com> 6 */ 7 8#include <linux/debugfs.h> 9 10#include "hva.h" 11#include "hva-hw.h" 12 13static 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 */ 119void 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 175void 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 219static 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 274static int device_show(struct seq_file *s, void *data) 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 284static int encoders_show(struct seq_file *s, void *data) 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 302static int last_show(struct seq_file *s, void *data) 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 319static int regs_show(struct seq_file *s, void *data) 320{ 321 struct hva_dev *hva = s->private; 322 323 hva_hw_dump_regs(hva, s); 324 325 return 0; 326} 327 328#define hva_dbg_create_entry(name) \ 329 debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \ 330 &name##_fops) 331 332DEFINE_SHOW_ATTRIBUTE(device); 333DEFINE_SHOW_ATTRIBUTE(encoders); 334DEFINE_SHOW_ATTRIBUTE(last); 335DEFINE_SHOW_ATTRIBUTE(regs); 336 337void hva_debugfs_create(struct hva_dev *hva) 338{ 339 hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL); 340 341 hva_dbg_create_entry(device); 342 hva_dbg_create_entry(encoders); 343 hva_dbg_create_entry(last); 344 hva_dbg_create_entry(regs); 345} 346 347void hva_debugfs_remove(struct hva_dev *hva) 348{ 349 debugfs_remove_recursive(hva->dbg.debugfs_entry); 350 hva->dbg.debugfs_entry = NULL; 351} 352 353/* 354 * context (instance) debug info 355 */ 356 357static int ctx_show(struct seq_file *s, void *data) 358{ 359 struct hva_ctx *ctx = s->private; 360 361 seq_printf(s, "[running encoding %d]\n", ctx->id); 362 363 hva_dbg_perf_compute(ctx); 364 format_ctx(s, ctx); 365 366 return 0; 367} 368 369DEFINE_SHOW_ATTRIBUTE(ctx); 370 371void hva_dbg_ctx_create(struct hva_ctx *ctx) 372{ 373 struct hva_dev *hva = ctx->hva_dev; 374 char name[4] = ""; 375 376 ctx->dbg.min_duration = UINT_MAX; 377 ctx->dbg.min_period = UINT_MAX; 378 ctx->dbg.min_bitrate = UINT_MAX; 379 380 snprintf(name, sizeof(name), "%d", hva->instance_id); 381 382 ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444, 383 hva->dbg.debugfs_entry, 384 ctx, &ctx_fops); 385} 386 387void hva_dbg_ctx_remove(struct hva_ctx *ctx) 388{ 389 struct hva_dev *hva = ctx->hva_dev; 390 391 if (ctx->flags & HVA_FLAG_STREAMINFO) 392 /* save context before removing */ 393 memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx)); 394 395 debugfs_remove(ctx->dbg.debugfs_entry); 396}