123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- /*
- * Copyright (C) STMicroelectronics SA 2015
- * Authors: Yannick Fertre <yannick.fertre@st.com>
- * Hugues Fruchet <hugues.fruchet@st.com>
- * License terms: GNU General Public License (GPL), version 2
- */
- #include <linux/debugfs.h>
- #include "hva.h"
- #include "hva-hw.h"
- static void format_ctx(struct seq_file *s, struct hva_ctx *ctx)
- {
- struct hva_streaminfo *stream = &ctx->streaminfo;
- struct hva_frameinfo *frame = &ctx->frameinfo;
- struct hva_controls *ctrls = &ctx->ctrls;
- struct hva_ctx_dbg *dbg = &ctx->dbg;
- u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp;
- seq_printf(s, "|-%s\n |\n", ctx->name);
- seq_printf(s, " |-[%sframe info]\n",
- ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default ");
- seq_printf(s, " | |- pixel format=%4.4s\n"
- " | |- wxh=%dx%d\n"
- " | |- wxh (w/ encoder alignment constraint)=%dx%d\n"
- " |\n",
- (char *)&frame->pixelformat,
- frame->width, frame->height,
- frame->aligned_width, frame->aligned_height);
- seq_printf(s, " |-[%sstream info]\n",
- ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default ");
- seq_printf(s, " | |- stream format=%4.4s\n"
- " | |- wxh=%dx%d\n"
- " | |- %s\n"
- " | |- %s\n"
- " |\n",
- (char *)&stream->streamformat,
- stream->width, stream->height,
- stream->profile, stream->level);
- bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
- aspect = V4L2_CID_MPEG_VIDEO_ASPECT;
- seq_puts(s, " |-[parameters]\n");
- seq_printf(s, " | |- %s\n"
- " | |- bitrate=%d bps\n"
- " | |- GOP size=%d\n"
- " | |- video aspect=%s\n"
- " | |- framerate=%d/%d\n",
- v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode],
- ctrls->bitrate,
- ctrls->gop_size,
- v4l2_ctrl_get_menu(aspect)[ctrls->aspect],
- ctrls->time_per_frame.denominator,
- ctrls->time_per_frame.numerator);
- entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE;
- vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC;
- sei_fp = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE;
- if (stream->streamformat == V4L2_PIX_FMT_H264) {
- seq_printf(s, " | |- %s entropy mode\n"
- " | |- CPB size=%d kB\n"
- " | |- DCT8x8 enable=%s\n"
- " | |- qpmin=%d\n"
- " | |- qpmax=%d\n"
- " | |- PAR enable=%s\n"
- " | |- PAR id=%s\n"
- " | |- SEI frame packing enable=%s\n"
- " | |- SEI frame packing type=%s\n",
- v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode],
- ctrls->cpb_size,
- ctrls->dct8x8 ? "true" : "false",
- ctrls->qpmin,
- ctrls->qpmax,
- ctrls->vui_sar ? "true" : "false",
- v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc],
- ctrls->sei_fp ? "true" : "false",
- v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]);
- }
- if (ctx->sys_errors || ctx->encode_errors || ctx->frame_errors) {
- seq_puts(s, " |\n |-[errors]\n");
- seq_printf(s, " | |- system=%d\n"
- " | |- encoding=%d\n"
- " | |- frame=%d\n",
- ctx->sys_errors,
- ctx->encode_errors,
- ctx->frame_errors);
- }
- seq_puts(s, " |\n |-[performances]\n");
- seq_printf(s, " | |- frames encoded=%d\n"
- " | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n"
- " | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n"
- " | |- avg fps (0.1Hz)=%d\n"
- " | |- max reachable fps (0.1Hz)=%d\n"
- " | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n"
- " | |- last bitrate (kbps)=%d\n",
- dbg->cnt_duration,
- dbg->avg_duration,
- dbg->min_duration,
- dbg->max_duration,
- dbg->avg_period,
- dbg->min_period,
- dbg->max_period,
- dbg->avg_fps,
- dbg->max_fps,
- dbg->avg_bitrate,
- dbg->min_bitrate,
- dbg->max_bitrate,
- dbg->last_bitrate);
- }
- /*
- * performance debug info
- */
- void hva_dbg_perf_begin(struct hva_ctx *ctx)
- {
- u64 div;
- u32 period;
- u32 bitrate;
- struct hva_ctx_dbg *dbg = &ctx->dbg;
- ktime_t prev = dbg->begin;
- dbg->begin = ktime_get();
- if (dbg->is_valid_period) {
- /* encoding period */
- div = (u64)ktime_us_delta(dbg->begin, prev);
- do_div(div, 100);
- period = (u32)div;
- dbg->min_period = min(period, dbg->min_period);
- dbg->max_period = max(period, dbg->max_period);
- dbg->total_period += period;
- dbg->cnt_period++;
- /*
- * minimum and maximum bitrates are based on the
- * encoding period values upon a window of 32 samples
- */
- dbg->window_duration += period;
- dbg->cnt_window++;
- if (dbg->cnt_window >= 32) {
- /*
- * bitrate in kbps = (size * 8 / 1000) /
- * (duration / 10000)
- * = size * 80 / duration
- */
- if (dbg->window_duration > 0) {
- div = (u64)dbg->window_stream_size * 80;
- do_div(div, dbg->window_duration);
- bitrate = (u32)div;
- dbg->last_bitrate = bitrate;
- dbg->min_bitrate = min(bitrate,
- dbg->min_bitrate);
- dbg->max_bitrate = max(bitrate,
- dbg->max_bitrate);
- }
- dbg->window_stream_size = 0;
- dbg->window_duration = 0;
- dbg->cnt_window = 0;
- }
- }
- /*
- * filter sequences valid for performance:
- * - begin/begin (no stream available) is an invalid sequence
- * - begin/end is a valid sequence
- */
- dbg->is_valid_period = false;
- }
- void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream)
- {
- struct device *dev = ctx_to_dev(ctx);
- u64 div;
- u32 duration;
- u32 bytesused;
- u32 timestamp;
- struct hva_ctx_dbg *dbg = &ctx->dbg;
- ktime_t end = ktime_get();
- /* stream bytesused and timestamp in us */
- bytesused = vb2_get_plane_payload(&stream->vbuf.vb2_buf, 0);
- div = stream->vbuf.vb2_buf.timestamp;
- do_div(div, 1000);
- timestamp = (u32)div;
- /* encoding duration */
- div = (u64)ktime_us_delta(end, dbg->begin);
- dev_dbg(dev,
- "%s perf stream[%d] dts=%d encoded using %d bytes in %d us",
- ctx->name,
- stream->vbuf.sequence,
- timestamp,
- bytesused, (u32)div);
- do_div(div, 100);
- duration = (u32)div;
- dbg->min_duration = min(duration, dbg->min_duration);
- dbg->max_duration = max(duration, dbg->max_duration);
- dbg->total_duration += duration;
- dbg->cnt_duration++;
- /*
- * the average bitrate is based on the total stream size
- * and the total encoding periods
- */
- dbg->total_stream_size += bytesused;
- dbg->window_stream_size += bytesused;
- dbg->is_valid_period = true;
- }
- static void hva_dbg_perf_compute(struct hva_ctx *ctx)
- {
- u64 div;
- struct hva_ctx_dbg *dbg = &ctx->dbg;
- if (dbg->cnt_duration > 0) {
- div = (u64)dbg->total_duration;
- do_div(div, dbg->cnt_duration);
- dbg->avg_duration = (u32)div;
- } else {
- dbg->avg_duration = 0;
- }
- if (dbg->total_duration > 0) {
- div = (u64)dbg->cnt_duration * 100000;
- do_div(div, dbg->total_duration);
- dbg->max_fps = (u32)div;
- } else {
- dbg->max_fps = 0;
- }
- if (dbg->cnt_period > 0) {
- div = (u64)dbg->total_period;
- do_div(div, dbg->cnt_period);
- dbg->avg_period = (u32)div;
- } else {
- dbg->avg_period = 0;
- }
- if (dbg->total_period > 0) {
- div = (u64)dbg->cnt_period * 100000;
- do_div(div, dbg->total_period);
- dbg->avg_fps = (u32)div;
- } else {
- dbg->avg_fps = 0;
- }
- if (dbg->total_period > 0) {
- /*
- * bitrate in kbps = (video size * 8 / 1000) /
- * (video duration / 10000)
- * = video size * 80 / video duration
- */
- div = (u64)dbg->total_stream_size * 80;
- do_div(div, dbg->total_period);
- dbg->avg_bitrate = (u32)div;
- } else {
- dbg->avg_bitrate = 0;
- }
- }
- /*
- * device debug info
- */
- static int hva_dbg_device(struct seq_file *s, void *data)
- {
- struct hva_dev *hva = s->private;
- seq_printf(s, "[%s]\n", hva->v4l2_dev.name);
- seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num);
- return 0;
- }
- static int hva_dbg_encoders(struct seq_file *s, void *data)
- {
- struct hva_dev *hva = s->private;
- unsigned int i = 0;
- seq_printf(s, "[encoders]\n|- %d registered encoders:\n",
- hva->nb_of_encoders);
- while (hva->encoders[i]) {
- seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name,
- (char *)&hva->encoders[i]->pixelformat,
- (char *)&hva->encoders[i]->streamformat);
- i++;
- }
- return 0;
- }
- static int hva_dbg_last(struct seq_file *s, void *data)
- {
- struct hva_dev *hva = s->private;
- struct hva_ctx *last_ctx = &hva->dbg.last_ctx;
- if (last_ctx->flags & HVA_FLAG_STREAMINFO) {
- seq_puts(s, "[last encoding]\n");
- hva_dbg_perf_compute(last_ctx);
- format_ctx(s, last_ctx);
- } else {
- seq_puts(s, "[no information recorded about last encoding]\n");
- }
- return 0;
- }
- static int hva_dbg_regs(struct seq_file *s, void *data)
- {
- struct hva_dev *hva = s->private;
- hva_hw_dump_regs(hva, s);
- return 0;
- }
- #define hva_dbg_declare(name) \
- static int hva_dbg_##name##_open(struct inode *i, struct file *f) \
- { \
- return single_open(f, hva_dbg_##name, i->i_private); \
- } \
- static const struct file_operations hva_dbg_##name##_fops = { \
- .open = hva_dbg_##name##_open, \
- .read = seq_read, \
- .llseek = seq_lseek, \
- .release = single_release, \
- }
- #define hva_dbg_create_entry(name) \
- debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
- &hva_dbg_##name##_fops)
- hva_dbg_declare(device);
- hva_dbg_declare(encoders);
- hva_dbg_declare(last);
- hva_dbg_declare(regs);
- void hva_debugfs_create(struct hva_dev *hva)
- {
- hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL);
- if (!hva->dbg.debugfs_entry)
- goto err;
- if (!hva_dbg_create_entry(device))
- goto err;
- if (!hva_dbg_create_entry(encoders))
- goto err;
- if (!hva_dbg_create_entry(last))
- goto err;
- if (!hva_dbg_create_entry(regs))
- goto err;
- return;
- err:
- hva_debugfs_remove(hva);
- }
- void hva_debugfs_remove(struct hva_dev *hva)
- {
- debugfs_remove_recursive(hva->dbg.debugfs_entry);
- hva->dbg.debugfs_entry = NULL;
- }
- /*
- * context (instance) debug info
- */
- static int hva_dbg_ctx(struct seq_file *s, void *data)
- {
- struct hva_ctx *ctx = s->private;
- seq_printf(s, "[running encoding %d]\n", ctx->id);
- hva_dbg_perf_compute(ctx);
- format_ctx(s, ctx);
- return 0;
- }
- hva_dbg_declare(ctx);
- void hva_dbg_ctx_create(struct hva_ctx *ctx)
- {
- struct hva_dev *hva = ctx->hva_dev;
- char name[4] = "";
- ctx->dbg.min_duration = UINT_MAX;
- ctx->dbg.min_period = UINT_MAX;
- ctx->dbg.min_bitrate = UINT_MAX;
- snprintf(name, sizeof(name), "%d", hva->instance_id);
- ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444,
- hva->dbg.debugfs_entry,
- ctx, &hva_dbg_ctx_fops);
- }
- void hva_dbg_ctx_remove(struct hva_ctx *ctx)
- {
- struct hva_dev *hva = ctx->hva_dev;
- if (ctx->flags & HVA_FLAG_STREAMINFO)
- /* save context before removing */
- memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx));
- debugfs_remove(ctx->dbg.debugfs_entry);
- }
|