397 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) STMicroelectronics SA 20154 * 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 info118 */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 the141 * encoding period values upon a window of 32 samples142 */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 / duration150 */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 sequence170 * - begin/end is a valid sequence171 */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 size211 * and the total encoding periods212 */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 duration261 */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 info272 */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 info355 */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}397