linux/drivers/media/platform/sti/hva/hva-debugfs.c
<<
>>
Prefs
   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 hva_dbg_device(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 hva_dbg_encoders(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 hva_dbg_last(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 hva_dbg_regs(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_declare(name)                                             \
 329        static int hva_dbg_##name##_open(struct inode *i, struct file *f) \
 330        {                                                                 \
 331                return single_open(f, hva_dbg_##name, i->i_private);      \
 332        }                                                                 \
 333        static const struct file_operations hva_dbg_##name##_fops = {     \
 334                .open           = hva_dbg_##name##_open,                  \
 335                .read           = seq_read,                               \
 336                .llseek         = seq_lseek,                              \
 337                .release        = single_release,                         \
 338        }
 339
 340#define hva_dbg_create_entry(name)                                       \
 341        debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
 342                            &hva_dbg_##name##_fops)
 343
 344hva_dbg_declare(device);
 345hva_dbg_declare(encoders);
 346hva_dbg_declare(last);
 347hva_dbg_declare(regs);
 348
 349void hva_debugfs_create(struct hva_dev *hva)
 350{
 351        hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL);
 352        if (!hva->dbg.debugfs_entry)
 353                goto err;
 354
 355        if (!hva_dbg_create_entry(device))
 356                goto err;
 357
 358        if (!hva_dbg_create_entry(encoders))
 359                goto err;
 360
 361        if (!hva_dbg_create_entry(last))
 362                goto err;
 363
 364        if (!hva_dbg_create_entry(regs))
 365                goto err;
 366
 367        return;
 368
 369err:
 370        hva_debugfs_remove(hva);
 371}
 372
 373void hva_debugfs_remove(struct hva_dev *hva)
 374{
 375        debugfs_remove_recursive(hva->dbg.debugfs_entry);
 376        hva->dbg.debugfs_entry = NULL;
 377}
 378
 379/*
 380 * context (instance) debug info
 381 */
 382
 383static int hva_dbg_ctx(struct seq_file *s, void *data)
 384{
 385        struct hva_ctx *ctx = s->private;
 386
 387        seq_printf(s, "[running encoding %d]\n", ctx->id);
 388
 389        hva_dbg_perf_compute(ctx);
 390        format_ctx(s, ctx);
 391
 392        return 0;
 393}
 394
 395hva_dbg_declare(ctx);
 396
 397void hva_dbg_ctx_create(struct hva_ctx *ctx)
 398{
 399        struct hva_dev *hva = ctx->hva_dev;
 400        char name[4] = "";
 401
 402        ctx->dbg.min_duration = UINT_MAX;
 403        ctx->dbg.min_period = UINT_MAX;
 404        ctx->dbg.min_bitrate = UINT_MAX;
 405
 406        snprintf(name, sizeof(name), "%d", hva->instance_id);
 407
 408        ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444,
 409                                                     hva->dbg.debugfs_entry,
 410                                                     ctx, &hva_dbg_ctx_fops);
 411}
 412
 413void hva_dbg_ctx_remove(struct hva_ctx *ctx)
 414{
 415        struct hva_dev *hva = ctx->hva_dev;
 416
 417        if (ctx->flags & HVA_FLAG_STREAMINFO)
 418                /* save context before removing */
 419                memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx));
 420
 421        debugfs_remove(ctx->dbg.debugfs_entry);
 422}
 423