You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2422 lines
75 KiB
2422 lines
75 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2008-2020. All rights reserved.
|
|
* Description: stat drv
|
|
* Author: Hisilicon
|
|
* Create: 2008-12-16
|
|
*/
|
|
#include "drv_stat_ext.h"
|
|
#include "drv_stat.h"
|
|
#include <linux/sort.h>
|
|
#include <linux/file.h>
|
|
#include <linux/kfifo.h>
|
|
#include <linux/uaccess.h>
|
|
#include "linux/huanglong/securec.h"
|
|
#include "drv_ioctl_stat.h"
|
|
#include "drv_proc_ext.h"
|
|
#include "soc_log.h"
|
|
#include "td_type.h"
|
|
#include "osal_ext.h"
|
|
#include "drv_module_ext.h"
|
|
#include "drv_sys_ext.h"
|
|
|
|
#define EXT_STAT_PROC_NAME "stat"
|
|
#define EXT_STAT_FRAME_COUNT_DEFAULT 20
|
|
#define EXT_STAT_FRAME_COUNT_MAX 100
|
|
#define EXT_STAT_MAX_PRINTK_LEN 1024
|
|
#define EXT_STAT_PROC_BUF_RESERVED 1024
|
|
#define EXT_STAT_PROC_BUF_LEN (1024 * 16)
|
|
#define EXT_STAT_TASK_DELAY 8
|
|
#define EXT_STAT_FIFO_SIZE (1024 * 16)
|
|
#define EXT_STAT_PRINT_NUM_OF_LINE 5
|
|
|
|
#define stat_para_equel_null_return(para, desc, value) do { \
|
|
if ((para) == NULL) { \
|
|
soc_log_err("%s 0x%x\n", desc, value); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
typedef struct {
|
|
td_char *buffer;
|
|
td_u32 len;
|
|
td_u32 write_len;
|
|
}drv_stat_buf;
|
|
|
|
typedef struct {
|
|
td_u32 mod_id;
|
|
td_char module_name[STAT_NAME_LEN_MAX];
|
|
/* calc the stat frame count: module cost max min avg */
|
|
td_u64 mod_total_cost_max;
|
|
td_u64 mod_total_cost_min;
|
|
td_u64 mod_total_cost_avg;
|
|
td_bool is_calc;
|
|
struct osal_list_head node;
|
|
}ext_drv_stat_cfg_node;
|
|
|
|
typedef struct {
|
|
td_char step_name[STAT_NAME_LEN_MAX];
|
|
td_u64 us_time;
|
|
td_bool value_invald;
|
|
}ext_drv_stat_step;
|
|
|
|
typedef struct {
|
|
td_u64 mod_total_cost;
|
|
td_u64 *step_cost;
|
|
}ext_drv_stat_calc;
|
|
|
|
typedef struct {
|
|
/* note: This module id is used for marking between modules on the DFX delay path,
|
|
64bit index is the same and the module that instance_id is not equal to 0xFF is the same path. */
|
|
td_u8 mod_id; /* index64:56~63bit */
|
|
td_u8 instance_id; /* index64:48~55bit */
|
|
td_u8 one2multi_id; /* index64:40~47bit */
|
|
td_u8 reserved; /* index64:32~39bit */
|
|
td_u32 frame_index; /* index64:0~31bit */
|
|
}ext_drv_stat_index;
|
|
|
|
typedef struct {
|
|
td_u32 mod_id;
|
|
td_char name[STAT_NAME_LEN_MAX];
|
|
td_s64 pts;
|
|
ext_drv_stat_index stat_index;
|
|
td_u32 step_max;
|
|
td_u32 step_index;
|
|
ext_drv_stat_step *step_info;
|
|
ext_drv_stat_calc *calc_result;
|
|
/* the stat_module add to the stat_frame module list */
|
|
struct osal_list_head node;
|
|
}ext_drv_stat_module;
|
|
|
|
typedef struct {
|
|
td_bool is_vaild;
|
|
td_bool data_vaild;
|
|
td_u32 frame_index;
|
|
td_u32 module_count;
|
|
osal_spinlock frame_lock;
|
|
/* stat module list */
|
|
struct osal_list_head module_list;
|
|
}ext_drv_stat_frame;
|
|
|
|
typedef struct {
|
|
stat_info info;
|
|
td_u64 current_time;
|
|
}ext_drv_stat_info;
|
|
|
|
typedef struct {
|
|
/* stat feature is disable for default */
|
|
td_bool stat_enable;
|
|
/* samping data, the stat_frame no vaild. */
|
|
td_bool finish;
|
|
td_bool calc;
|
|
/* the stat frame count default is 20, the max = 100 */
|
|
td_u32 stat_count;
|
|
/* The actual number of samples.
|
|
The actual number of samples is 2 times that of standard data */
|
|
td_u32 sampling_count;
|
|
osal_task *stat_task;
|
|
/* stat kfifo */
|
|
td_void *info_buf;
|
|
STRUCT_KFIFO_PTR(ext_drv_stat_info) stat_fifo;
|
|
osal_spinlock stat_control;
|
|
ext_drv_stat_frame *stat_frame;
|
|
}ext_drv_stat_control;
|
|
|
|
typedef struct {
|
|
td_u8 path_index;
|
|
td_u32 mod_id;
|
|
td_u64 in_mark;
|
|
ext_drv_stat_index stat_index;
|
|
}ext_drv_stat_mod_info;
|
|
|
|
typedef struct {
|
|
td_char *echo;
|
|
td_char *command;
|
|
td_char *para1;
|
|
td_char *para2;
|
|
td_char *path;
|
|
td_char *explanation;
|
|
}drv_stat_proc_help_info;
|
|
|
|
typedef struct {
|
|
td_u32 mod_step_count;
|
|
td_u32 frame_index;
|
|
}ext_drv_stat_mark;
|
|
|
|
static DEFINE_SPINLOCK(fifo_lock);
|
|
static DEFINE_SPINLOCK(mod_cfg_lock);
|
|
static OSAL_LIST_HEAD(mod_cfg_list);
|
|
static ext_drv_stat_control g_stat_control;
|
|
/* define module name */
|
|
const static td_char *g_mod_name[SOC_ID_TSFW + 1] = {
|
|
/* common */
|
|
[SOC_ID_SYS] = "sys", /* 0x00 */
|
|
[SOC_ID_MODULE] = "module",
|
|
[SOC_ID_LOG] = "log",
|
|
[SOC_ID_PROC] = "proc",
|
|
[SOC_ID_MEM] = "mem",
|
|
[SOC_ID_STAT] = "stat",
|
|
[SOC_ID_PDM] = "pdm",
|
|
[SOC_ID_MEMDEV] = "memdev",
|
|
[SOC_ID_MDDRC] = "mddrc",
|
|
[SOC_ID_MAILBOX] = "mailbox",
|
|
[SOC_ID_RM] = "rm",
|
|
[SOC_ID_PM] = "pm",
|
|
[SOC_ID_DVFS] = "dvfs",
|
|
[SOC_ID_RUNTIME] = "runtime",
|
|
[SOC_ID_SPREAD] = "spread",
|
|
[SOC_ID_CUSTOM] = "custom",
|
|
|
|
/* Peripheral */
|
|
[SOC_ID_FLASH] = "flash", /* 0x10 */
|
|
[SOC_ID_IR] = "ir",
|
|
[SOC_ID_I2C] = "i2c",
|
|
[SOC_ID_GPIO] = "gpio",
|
|
[SOC_ID_GPIO_I2C] = "gpio_i2c",
|
|
[SOC_ID_PWM] = "pwm",
|
|
[SOC_ID_LSADC] = "lsadc",
|
|
[SOC_ID_SPI] = "spi",
|
|
[SOC_ID_KEYLED] = "keyled",
|
|
[SOC_ID_WDG] = "wdg",
|
|
[SOC_ID_CI] = "ci",
|
|
[SOC_ID_SCI] = "sci",
|
|
[SOC_ID_BEIDOU] = "beidou",
|
|
[SOC_ID_BT] = "bt",
|
|
[SOC_ID_FRONTEND] = "frontend", /* 0x1E */
|
|
"unknown",
|
|
|
|
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
|
|
"unknown", "unknown", "unknown",
|
|
/* event */
|
|
[SOC_ID_EVENT] = "event", /* 0x2B */
|
|
/* Demux */
|
|
[SOC_ID_DEMUX] = "demux", /* 0X2C */
|
|
"unknown",
|
|
"unknown",
|
|
"unknown",
|
|
|
|
/* Security */
|
|
[SOC_ID_OTP] = "otp", /* 0x30 */
|
|
[SOC_ID_KLAD] = "klad",
|
|
[SOC_ID_KEYSLOT] = "keyslot",
|
|
[SOC_ID_CIPHER] = "cipher",
|
|
[SOC_ID_TSR2RCIPHER] = "tsr2rcipher",
|
|
[SOC_ID_CERT] = "cert",
|
|
[SOC_ID_TSIO] = "tsio",
|
|
[SOC_ID_SSM] = "ssm",
|
|
[SOC_ID_VMX_ULTRA] = "vmx_ultra",
|
|
[SOC_ID_CASIMAGE] = "casimage",
|
|
[SOC_ID_HDCP] = "hdcp", /* 0x3A */
|
|
"unknown", "unknown", "unknown", "unknown", "unknown",
|
|
|
|
/* Audio */
|
|
[SOC_ID_SIF] = "sif", /* 0x40 */
|
|
[SOC_ID_AIAO] = "aiao",
|
|
[SOC_ID_AI] = "ai",
|
|
[SOC_ID_AENC] = "aenc",
|
|
[SOC_ID_ADEC] = "adec",
|
|
[SOC_ID_AFLT] = "aflt",
|
|
[SOC_ID_ADSP] = "adsp",
|
|
[SOC_ID_ASR] = "asr",
|
|
[SOC_ID_TTS] = "tts",
|
|
[SOC_ID_AO] = "ao",
|
|
[SOC_ID_AMP] = "amp",
|
|
[SOC_ID_EARCTX] = "earctx", /* 0x4B */
|
|
"unknown", "unknown", "unknown", "unknown",
|
|
|
|
/* Video and input/output */
|
|
[SOC_ID_VFE] = "vfe", /* 0x50 */
|
|
[SOC_ID_TVD] = "tvd",
|
|
[SOC_ID_HDDEC] = "hddec",
|
|
[SOC_ID_VBI] = "vbi",
|
|
[SOC_ID_VICAP] = "vicap",
|
|
[SOC_ID_VI] = "vi",
|
|
[SOC_ID_VENC] = "venc",
|
|
[SOC_ID_VFMW] = "vfmw",
|
|
[SOC_ID_VDEC] = "vdec",
|
|
[SOC_ID_PQ] = "pq",
|
|
[SOC_ID_MEMC] = "memc",
|
|
[SOC_ID_FRC] = "frc",
|
|
[SOC_ID_VPSS] = "vpss",
|
|
[SOC_ID_VPLUGIN] = "vplugin",
|
|
[SOC_ID_WIN] = "win",
|
|
[SOC_ID_DISP] = "disp",
|
|
[SOC_ID_HDMIRX] = "hdmirx", /* 0x60 */
|
|
[SOC_ID_HDMITX] = "hdmitx",
|
|
[SOC_ID_PANEL] = "panel",
|
|
[SOC_ID_MIPI] = "mipi",
|
|
[SOC_ID_FDMNG] = "fdmng",
|
|
[SOC_ID_DISPMNG] = "dispmng",
|
|
[SOC_ID_DISPCTRL] = "dispctrl", /* 0x66 */
|
|
"unknown", "unknown", "unknown",
|
|
[SOC_ID_OMXVENC] = "omxvenc", /* 0x6A */
|
|
[SOC_ID_OMXVDEC] = "omxvdec", /* 0x6B */
|
|
"unknown", "unknown", "unknown", "unknown",
|
|
|
|
/* Graphics */
|
|
[SOC_ID_FB] = "fb", /* 0x70 */
|
|
[SOC_ID_GPU] = "gpu",
|
|
[SOC_ID_TDE] = "tde",
|
|
[SOC_ID_GFX2D] = "gfx2d",
|
|
[SOC_ID_JPGDEC] = "jpgdec",
|
|
[SOC_ID_JPGENC] = "jpgenc",
|
|
[SOC_ID_PNG] = "png",
|
|
[SOC_ID_FUX] = "fux", /* 0x77 */
|
|
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
|
|
|
|
/* Player */
|
|
[SOC_ID_AVPLAY] = "avplay", /* 0x80 */
|
|
[SOC_ID_SYNC] = "sync",
|
|
[SOC_ID_VSYNC] = "vsync",
|
|
[SOC_ID_ASYNC] = "async",
|
|
[SOC_ID_PVR] = "pvr", /* 0x84 */
|
|
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
|
|
"unknown", "unknown", "unknown",
|
|
|
|
/* Component */
|
|
[SOC_ID_SUBT] = "subt", /* 0x90 */
|
|
[SOC_ID_TTX] = "ttx",
|
|
[SOC_ID_CC] = "cc",
|
|
[SOC_ID_LOADER] = "loader",
|
|
[SOC_ID_KARAOKE] = "karaoke",
|
|
[SOC_ID_VP] = "vp",
|
|
[SOC_ID_TOKEN] = "token", /* 0x96 */
|
|
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
|
|
"unknown",
|
|
|
|
/* Middleware */
|
|
[SOC_ID_NETFLIX] = "netflix", /* 0xA0 */
|
|
[SOC_ID_TVMW] = "tvmw",
|
|
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
|
|
/* NPU */
|
|
[SOC_ID_NPUDEV] = "npudev", /* 0xAA */
|
|
[SOC_ID_AICPU] = "aicpu",
|
|
[SOC_ID_NPUDFX] = "npudfx",
|
|
[SOC_ID_TSFW] = "tsfw", /* 0xAD */
|
|
};
|
|
|
|
static td_s32 drv_stat_get_module_name(td_u32 mod_id, td_char *name, td_u32 len)
|
|
{
|
|
td_s32 ret;
|
|
|
|
if (mod_id >= SOC_ID_MAX || name == TD_NULL) {
|
|
soc_log_err("drv stat get module name: input params is error .\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (mod_id > SOC_ID_TSFW && mod_id < SOC_ID_MAX) {
|
|
ret = sprintf_s(name, len - 1, "%s_0x%x", "unkown", mod_id);
|
|
if (ret < 0) {
|
|
soc_log_err("drv stat get module name: sprintf_s failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
if (memcpy_s(name, len,
|
|
g_mod_name[mod_id], strlen(g_mod_name[mod_id])) != EOK) {
|
|
soc_log_err("drv stat get module name: memcpy_s failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
static td_s32 drv_stat_cmp(const td_void *a, const td_void *b)
|
|
{
|
|
return (td_s32)(*(td_u64 *)a - *(td_u64 *)b);
|
|
}
|
|
|
|
static td_s32 drv_stat_module_sampling_sort(td_u64 *sampling, td_u32 len)
|
|
{
|
|
if (sampling == TD_NULL || len == 0) {
|
|
soc_log_err("input params are invalid.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
sort(sampling, len, sizeof(td_u64), drv_stat_cmp, TD_NULL);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static ext_drv_stat_cfg_node *drv_stat_module_find_node(const struct osal_list_head *list, td_u32 mod_id)
|
|
{
|
|
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
|
|
|
|
osal_list_for_each_entry(cfg_node, list, node) {
|
|
if (cfg_node->mod_id == mod_id) {
|
|
return cfg_node;
|
|
}
|
|
}
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_s32 drv_stat_module_list_find_node(td_u32 mod_id)
|
|
{
|
|
td_ulong flags;
|
|
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
|
|
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
cfg_node = drv_stat_module_find_node(&mod_cfg_list, mod_id);
|
|
if (cfg_node != TD_NULL) {
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
return TD_SUCCESS;
|
|
}
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
static td_void drv_stat_add_module(ext_drv_stat_cfg_node *mod_cfg)
|
|
{
|
|
td_ulong flags;
|
|
|
|
if (mod_cfg == NULL) {
|
|
soc_log_err("input params is null\n");
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
osal_list_add_tail(&mod_cfg->node, &mod_cfg_list);
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
}
|
|
|
|
static td_void drv_stat_remove_one_module(const ext_drv_stat_cfg_node *mod_cfg)
|
|
{
|
|
if (mod_cfg == TD_NULL) {
|
|
soc_log_err("mod_cfg is null\n");
|
|
return;
|
|
}
|
|
|
|
osal_kfree(mod_cfg);
|
|
mod_cfg = TD_NULL;
|
|
}
|
|
|
|
static td_void drv_stat_remove_all_module(td_void)
|
|
{
|
|
td_ulong flags;
|
|
struct osal_list_head *pos = TD_NULL;
|
|
struct osal_list_head *nex = TD_NULL;
|
|
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
|
|
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
osal_list_for_each_safe(pos, nex, &mod_cfg_list) {
|
|
cfg_node = osal_list_entry(pos, ext_drv_stat_cfg_node, node);
|
|
if (cfg_node != TD_NULL) {
|
|
drv_stat_remove_one_module(cfg_node);
|
|
cfg_node = TD_NULL;
|
|
osal_list_del_init(pos);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
}
|
|
|
|
static td_void drv_stat_reset_module_calc_flag(td_void)
|
|
{
|
|
td_ulong flags;
|
|
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
|
|
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
osal_list_for_each_entry(cfg_node, &mod_cfg_list, node) {
|
|
cfg_node->is_calc = TD_FALSE;
|
|
}
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
}
|
|
|
|
td_void drv_stat_module_cfg_release(const ext_drv_stat_cfg_node *module_node)
|
|
{
|
|
if (module_node == TD_NULL) {
|
|
soc_log_err("module_node is null.\n");
|
|
return;
|
|
}
|
|
|
|
osal_kfree(module_node);
|
|
module_node = TD_NULL;
|
|
}
|
|
|
|
ext_drv_stat_cfg_node *drv_stat_module_cfg_malloc(td_void)
|
|
{
|
|
ext_drv_stat_cfg_node *module_node = TD_NULL;
|
|
|
|
/* module configure */
|
|
module_node = osal_kmalloc(sizeof(ext_drv_stat_cfg_node), OSAL_GFP_KERNEL);
|
|
if (module_node == TD_NULL) {
|
|
soc_log_err("drv stat module cfg malloc: osal kmalloc for stat module node failed.\n");
|
|
return TD_NULL;
|
|
}
|
|
if (memset_s(module_node, sizeof(ext_drv_stat_cfg_node), 0x0, sizeof(ext_drv_stat_cfg_node)) != EOK) {
|
|
soc_log_err("drv_stat_module_cfg_malloc: memset_s failure .\n");
|
|
drv_stat_module_cfg_release(module_node);
|
|
module_node = TD_NULL;
|
|
return TD_NULL;
|
|
}
|
|
|
|
return module_node;
|
|
}
|
|
|
|
td_s32 drv_stat_module_cfg(td_u32 mod_id)
|
|
{
|
|
td_s32 ret;
|
|
ext_drv_stat_cfg_node *module_node = TD_NULL;
|
|
|
|
ret = drv_stat_module_list_find_node(mod_id);
|
|
if (ret == TD_SUCCESS) {
|
|
/* this mod & index is configured */
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
module_node = drv_stat_module_cfg_malloc();
|
|
if (module_node == TD_NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
module_node->mod_id = mod_id;
|
|
module_node->is_calc = TD_FALSE;
|
|
ret = drv_stat_get_module_name(mod_id, module_node->module_name, STAT_NAME_LEN_MAX);
|
|
if (ret != TD_SUCCESS) {
|
|
drv_stat_module_cfg_release(module_node);
|
|
module_node = TD_NULL;
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
/* add node */
|
|
drv_stat_add_module(module_node);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void drv_stat_index_transformation(td_u64 index, ext_drv_stat_index *stat_index)
|
|
{
|
|
if (stat_index == TD_NULL) {
|
|
soc_log_err("input param error.\n");
|
|
return;
|
|
}
|
|
|
|
stat_index->frame_index = (td_u32)(index & 0xffffffff);
|
|
/* note: This module id is used for marking between modules on the DFX delay path,
|
|
64bit index is the same and the module that reserved is not equal to 0xFF is the same path. */
|
|
stat_index->mod_id = (td_u8)(((index >> 0x20) & 0xff000000) >> 0x18);
|
|
stat_index->instance_id = (td_u8)(((index >> 0x20) & 0xff0000) >> 0x10);
|
|
stat_index->one2multi_id = (td_u8)(((index >> 0x20) & 0xff00) >> 0x8);
|
|
/* if reserved == 0xFF, Only in-module performance is counted. */
|
|
stat_index->reserved = (td_u8)((index >> 0x20) & 0xff);
|
|
}
|
|
|
|
static ext_drv_stat_module *drv_stat_list_get_module(const struct osal_list_head *list, const stat_info *info)
|
|
{
|
|
ext_drv_stat_index stat_index;
|
|
ext_drv_stat_module *mod_node = TD_NULL;
|
|
struct osal_list_head *pos = TD_NULL;
|
|
struct osal_list_head *nex = TD_NULL;
|
|
|
|
drv_stat_index_transformation(info->index, &stat_index);
|
|
osal_list_for_each_safe(pos, nex, list) {
|
|
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
|
|
if (mod_node->mod_id == info->mod_id &&
|
|
mod_node->stat_index.mod_id == stat_index.mod_id &&
|
|
mod_node->stat_index.frame_index == stat_index.frame_index &&
|
|
mod_node->stat_index.instance_id == stat_index.instance_id &&
|
|
mod_node->stat_index.one2multi_id == stat_index.one2multi_id) {
|
|
return mod_node;
|
|
}
|
|
}
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
static ext_drv_stat_module *drv_stat_list_get_module_by_module_id(const struct osal_list_head *list, td_u8 mod_id)
|
|
{
|
|
ext_drv_stat_module *mod_node = TD_NULL;
|
|
struct osal_list_head *pos = TD_NULL;
|
|
struct osal_list_head *nex = TD_NULL;
|
|
|
|
osal_list_for_each_safe(pos, nex, list) {
|
|
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
|
|
if (mod_node->mod_id == mod_id) {
|
|
return mod_node;
|
|
}
|
|
}
|
|
return TD_NULL;
|
|
}
|
|
|
|
static ext_drv_stat_frame *drv_stat_get_frame_by_index(td_u32 frame_index)
|
|
{
|
|
td_u32 i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
|
|
if (g_stat_control.stat_frame == TD_NULL) {
|
|
soc_log_err("g_stat_frame is null.\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
if (stat_frame->frame_index == frame_index) {
|
|
return stat_frame;
|
|
}
|
|
}
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
static ext_drv_stat_frame *drv_stat_get_frame_valid(td_void)
|
|
{
|
|
td_u32 i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
|
|
if (g_stat_control.stat_frame == TD_NULL) {
|
|
soc_log_err("g_stat_frame is null.\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
if (stat_frame->is_vaild == TD_TRUE) {
|
|
return stat_frame;
|
|
}
|
|
}
|
|
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_s32 drv_stat_calc_malloc(ext_drv_stat_module *stat_mod)
|
|
{
|
|
errno_t err_ret;
|
|
|
|
if (stat_mod == NULL) {
|
|
soc_log_err("drv stat calc malloc: input params is null\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
stat_mod->calc_result = osal_kmalloc(sizeof(ext_drv_stat_calc), OSAL_GFP_KERNEL);
|
|
if (stat_mod->calc_result == TD_NULL) {
|
|
soc_log_err("drv stat calc malloc: malloc failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
err_ret = memset_s(stat_mod->calc_result, sizeof(ext_drv_stat_calc), 0x0, sizeof(ext_drv_stat_calc));
|
|
if (err_ret != EOK) {
|
|
soc_log_err("drv stat calc malloc: memset_s failure .\n");
|
|
osal_kfree(stat_mod->calc_result);
|
|
stat_mod->calc_result = TD_NULL;
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
stat_mod->calc_result->step_cost = osal_kmalloc(sizeof(td_u64) * (stat_mod->step_max - 1),
|
|
OSAL_GFP_KERNEL);
|
|
if (stat_mod->calc_result->step_cost == TD_NULL) {
|
|
soc_log_err("drv stat calc malloc: step action malloc failed .\n");
|
|
osal_kfree(stat_mod->calc_result);
|
|
stat_mod->calc_result = TD_NULL;
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
err_ret = memset_s(stat_mod->calc_result->step_cost, sizeof(td_u64) * (stat_mod->step_max - 1), 0x0,
|
|
sizeof(td_u64) * (stat_mod->step_max - 1));
|
|
if (err_ret != EOK) {
|
|
soc_log_err("drv stat calc malloc: memset_s failure .\n");
|
|
osal_kfree(stat_mod->calc_result->step_cost);
|
|
stat_mod->calc_result->step_cost = TD_NULL;
|
|
osal_kfree(stat_mod->calc_result);
|
|
stat_mod->calc_result = TD_NULL;
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void drv_stat_calc_release(ext_drv_stat_module *stat_mod)
|
|
{
|
|
if (stat_mod == NULL || stat_mod->calc_result == TD_NULL) {
|
|
/* We only calculate the input sampling data, and not some of the data is involved in the calculation.
|
|
So there is no allocated space. */
|
|
return;
|
|
}
|
|
|
|
if (stat_mod->calc_result->step_cost != TD_NULL) {
|
|
osal_kfree(stat_mod->calc_result->step_cost);
|
|
stat_mod->calc_result->step_cost = TD_NULL;
|
|
}
|
|
|
|
if (stat_mod->calc_result != TD_NULL) {
|
|
osal_kfree(stat_mod->calc_result);
|
|
stat_mod->calc_result = TD_NULL;
|
|
}
|
|
}
|
|
|
|
static td_s32 drv_stat_step_cmp(const td_void *a, const td_void *b)
|
|
{
|
|
ext_drv_stat_step *tmp1 = (ext_drv_stat_step *)a;
|
|
ext_drv_stat_step *tmp2 = (ext_drv_stat_step *)b;
|
|
|
|
if (tmp1->us_time > tmp2->us_time) {
|
|
return 1;
|
|
} else if (tmp1->us_time == tmp2->us_time) {
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static td_void drv_stat_step_sort(ext_drv_stat_step *step, td_u32 size)
|
|
{
|
|
if (step == TD_NULL || size == 0) {
|
|
soc_log_err("input params are invalid.\n");
|
|
return;
|
|
}
|
|
|
|
sort(step, size, sizeof(ext_drv_stat_step), drv_stat_step_cmp, TD_NULL);
|
|
|
|
return;
|
|
}
|
|
static td_void drv_stat_calc_module_cost(ext_drv_stat_module *stat_mod)
|
|
{
|
|
td_u32 i;
|
|
ext_drv_stat_step *stat_step = TD_NULL;
|
|
ext_drv_stat_step *stat_step_n = TD_NULL;
|
|
ext_drv_stat_step *step_out = TD_NULL;
|
|
ext_drv_stat_step *step_in = TD_NULL;
|
|
td_bool in_flag = TD_FALSE;
|
|
if (stat_mod == NULL || stat_mod->step_info == TD_NULL) {
|
|
soc_log_err("input params is null\n");
|
|
return;
|
|
}
|
|
|
|
/* should sort, igore invalid value */
|
|
drv_stat_step_sort(stat_mod->step_info, stat_mod->step_max);
|
|
|
|
for (i = 0; i < stat_mod->step_max - 1; i++) {
|
|
stat_step = &stat_mod->step_info[i];
|
|
if (stat_step->value_invald == TD_FALSE) {
|
|
continue;
|
|
}
|
|
if (in_flag == TD_FALSE && stat_step->value_invald == TD_TRUE) {
|
|
in_flag = TD_TRUE;
|
|
step_in = stat_step;
|
|
}
|
|
stat_step_n = &stat_mod->step_info[i + 1];
|
|
step_out = stat_step_n;
|
|
if (stat_mod->calc_result == TD_NULL) {
|
|
return;
|
|
}
|
|
stat_mod->calc_result->step_cost[i] = stat_step_n->us_time - stat_step->us_time;
|
|
}
|
|
|
|
/* calc this module cost totaly */
|
|
if (step_out == TD_NULL || step_in == TD_NULL) {
|
|
soc_log_err("some error .. samping step data error.\n");
|
|
return;
|
|
}
|
|
|
|
stat_mod->calc_result->mod_total_cost = step_out->us_time - step_in->us_time;
|
|
}
|
|
|
|
static td_s32 drv_stat_step_action_malloc(ext_drv_stat_module *stat_mod)
|
|
{
|
|
ext_drv_stat_step *tmp = TD_NULL;
|
|
td_u32 i;
|
|
|
|
if (stat_mod == NULL) {
|
|
soc_log_err("input params is null\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
stat_mod->step_info = osal_kmalloc(sizeof(ext_drv_stat_step) * stat_mod->step_max, OSAL_GFP_KERNEL);
|
|
if (stat_mod->step_info == TD_NULL) {
|
|
soc_log_err("step action malloc failed .\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (i = 0; i < stat_mod->step_max; i++) {
|
|
tmp = &stat_mod->step_info[i];
|
|
if (memset_s(tmp->step_name, sizeof(tmp->step_name), 0x0, sizeof(tmp->step_name)) != EOK) {
|
|
osal_kfree(stat_mod->step_info);
|
|
stat_mod->step_info = TD_NULL;
|
|
soc_log_err("memset_s failure .\n");
|
|
return TD_FAILURE;
|
|
}
|
|
tmp->us_time = 0;
|
|
tmp->value_invald = TD_FALSE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void drv_stat_step_action_release(ext_drv_stat_module *stat_mod)
|
|
{
|
|
if (stat_mod == NULL) {
|
|
soc_log_err("input params is null\n");
|
|
return;
|
|
}
|
|
|
|
if (stat_mod->step_info != TD_NULL) {
|
|
osal_kfree(stat_mod->step_info);
|
|
stat_mod->step_info = TD_NULL;
|
|
}
|
|
}
|
|
|
|
static td_void drv_stat_step_action_mark(td_u64 cur_time, const stat_info *info, ext_drv_stat_module *stat_mod)
|
|
{
|
|
td_u32 i;
|
|
td_bool is_find_same_step = TD_FALSE;
|
|
ext_drv_stat_step *stat_step = TD_NULL;
|
|
|
|
if (info == TD_NULL || stat_mod == TD_NULL) {
|
|
soc_log_err("input params are invalild.\n");
|
|
return;
|
|
}
|
|
|
|
/* 1. Some events may be threaded, interrupted, and event messages are not sequential to trigger notify functions.
|
|
2. Some events may not be issued.
|
|
3. There is a case where a frame is processed or dropped multiple times, such as frame rate conversion */
|
|
/* the same events trigger notify function, we update the data. */
|
|
if (stat_mod->step_index < stat_mod->step_max) {
|
|
/* if step_name exists in the node of module, do not mark it.
|
|
It means it is only record the first same step. (Interlaced streams) */
|
|
for (i = 0; i < stat_mod->step_max; i++) {
|
|
stat_step = &stat_mod->step_info[i];
|
|
if (strcmp(info->step_name, stat_step->step_name) == 0) {
|
|
is_find_same_step = TD_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (is_find_same_step == TD_FALSE) {
|
|
/* get this module end step information, then we should calc the step cost */
|
|
stat_step = &stat_mod->step_info[stat_mod->step_index];
|
|
stat_step->us_time = cur_time;
|
|
stat_step->value_invald = TD_TRUE;
|
|
if (memcpy_s(stat_step->step_name, STAT_NAME_LEN_MAX, info->step_name, strlen(info->step_name)) != EOK) {
|
|
soc_log_err("memcpy_s step_name failed.\n");
|
|
return;
|
|
}
|
|
stat_mod->step_index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static ext_drv_stat_module *drv_stat_module_create(const stat_info *info)
|
|
{
|
|
td_s32 ret;
|
|
ext_drv_stat_module *stat_mod = TD_NULL;
|
|
|
|
if (info == TD_NULL) {
|
|
return TD_NULL;
|
|
}
|
|
|
|
stat_mod = osal_kmalloc(sizeof(ext_drv_stat_module), OSAL_GFP_KERNEL);
|
|
if (stat_mod == TD_NULL) {
|
|
soc_log_err("malloc failed .\n");
|
|
return TD_NULL;
|
|
}
|
|
if (memset_s(stat_mod, sizeof(ext_drv_stat_module), 0x0, sizeof(ext_drv_stat_module)) != EOK) {
|
|
soc_log_err("memset-s failed.\n");
|
|
goto out0;
|
|
}
|
|
|
|
stat_mod->mod_id = info->mod_id;
|
|
stat_mod->pts = info->pts;
|
|
stat_mod->step_max = info->step_max;
|
|
stat_mod->step_index = 0;
|
|
ret = drv_stat_get_module_name(info->mod_id, stat_mod->name, STAT_NAME_LEN_MAX);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("get mod name failed.\n");
|
|
goto out0;
|
|
}
|
|
|
|
drv_stat_index_transformation(info->index, &stat_mod->stat_index);
|
|
|
|
ret = drv_stat_step_action_malloc(stat_mod);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("step action malloc failed\n");
|
|
goto out0;
|
|
}
|
|
return stat_mod;
|
|
out0:
|
|
osal_kfree(stat_mod);
|
|
stat_mod = TD_NULL;
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_void drv_stat_module_release(ext_drv_stat_frame *stat_frame)
|
|
{
|
|
ext_drv_stat_module *mod_node = TD_NULL;
|
|
struct osal_list_head *pos = TD_NULL;
|
|
struct osal_list_head *nex = TD_NULL;
|
|
|
|
if (stat_frame == TD_NULL || stat_frame->module_list.next == TD_NULL) {
|
|
soc_log_err("stat module release:para is NULL. \n");
|
|
return;
|
|
}
|
|
|
|
osal_spin_lock(&stat_frame->frame_lock);
|
|
osal_list_for_each_safe(pos, nex, &stat_frame->module_list) {
|
|
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
|
|
if (mod_node != TD_NULL) {
|
|
drv_stat_step_action_release(mod_node);
|
|
drv_stat_calc_release(mod_node);
|
|
|
|
osal_list_del_init(pos);
|
|
|
|
osal_kfree(mod_node);
|
|
mod_node = TD_NULL;
|
|
}
|
|
}
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
}
|
|
|
|
static td_void drv_stat_frame_calc_release(ext_drv_stat_frame *stat_frame)
|
|
{
|
|
ext_drv_stat_module *mod_node = TD_NULL;
|
|
struct osal_list_head *pos = TD_NULL;
|
|
struct osal_list_head *nex = TD_NULL;
|
|
|
|
if (stat_frame == TD_NULL || stat_frame->module_list.next == TD_NULL) {
|
|
soc_log_err("stat frame calc release: para is NULL. \n");
|
|
return;
|
|
}
|
|
|
|
osal_spin_lock(&stat_frame->frame_lock);
|
|
osal_list_for_each_safe(pos, nex, &stat_frame->module_list) {
|
|
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
|
|
if (mod_node != TD_NULL) {
|
|
drv_stat_calc_release(mod_node);
|
|
}
|
|
}
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
}
|
|
|
|
static td_s32 drv_stat_calc_module_avg(const td_u64 *sampling, td_u32 size, td_u64 *avg)
|
|
{
|
|
td_u32 i;
|
|
td_u64 total = 0;
|
|
|
|
if (sampling == TD_NULL || avg == TD_NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (size > g_stat_control.stat_count) {
|
|
soc_log_err("input size :0x%x error.\n", size);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (i = 0; i < size - 1; i++) {
|
|
total += sampling[size - 1] - sampling[i];
|
|
}
|
|
|
|
if (size != 0) {
|
|
*avg = (td_u64)(sampling[0] + ((total * 0xa) / size + 0x5) / 0xa);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
static td_s32 drv_stat_calc_get_modulle_cost(
|
|
const ext_drv_stat_cfg_node *cfg_node, td_u64 *sampling, td_u32 *cost_count)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
ext_drv_stat_module *stat_module = TD_NULL;
|
|
td_u32 count = 0;
|
|
|
|
if (cfg_node == TD_NULL || sampling == TD_NULL || cost_count == TD_NULL) {
|
|
soc_log_err("input params null.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
if (stat_frame->data_vaild == TD_FALSE) {
|
|
continue;
|
|
}
|
|
if (count >= g_stat_control.stat_count) {
|
|
break;
|
|
}
|
|
osal_spin_lock(&stat_frame->frame_lock);
|
|
stat_module = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, cfg_node->mod_id);
|
|
if (stat_module == TD_NULL) {
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
soc_log_err("donot find node by mod_id:0x%x\n", cfg_node->mod_id);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = drv_stat_calc_malloc(stat_module);
|
|
if (ret != TD_SUCCESS) {
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
drv_stat_calc_module_cost(stat_module);
|
|
|
|
if (stat_module->calc_result != TD_NULL) {
|
|
sampling[count++] = stat_module->calc_result->mod_total_cost;
|
|
} else {
|
|
soc_log_err("calc result is NULL : mod_id: 0x%x\n", cfg_node->mod_id);
|
|
}
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
}
|
|
|
|
if (count < g_stat_control.stat_count) {
|
|
soc_log_err("stat data some error, sample valid data %d < %d\n", count, g_stat_control.stat_count);
|
|
return TD_FAILURE;
|
|
}
|
|
*cost_count = count;
|
|
return TD_SUCCESS;
|
|
}
|
|
static td_s32 drv_stat_calc_by_module(td_u64 *sampling, ext_drv_stat_cfg_node *cfg_node)
|
|
{
|
|
td_s32 ret;
|
|
td_u64 avg;
|
|
td_u32 count = 0;
|
|
|
|
if (cfg_node == TD_NULL || sampling == TD_NULL) {
|
|
soc_log_err("input params null.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = drv_stat_calc_get_modulle_cost(cfg_node, sampling, &count);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("calc module : 0x%x failed.\n", cfg_node->mod_id);
|
|
return TD_FAILURE;
|
|
}
|
|
ret = drv_stat_module_sampling_sort(sampling, count);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("sort faile..\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
cfg_node->mod_total_cost_min = sampling[0];
|
|
cfg_node->mod_total_cost_max = sampling[count - 1];
|
|
ret = drv_stat_calc_module_avg(sampling, count, &avg);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("calc avg failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
cfg_node->mod_total_cost_avg = avg;
|
|
cfg_node->is_calc = TD_TRUE;
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static ext_drv_stat_mark *drv_stat_malloc_mark(td_void)
|
|
{
|
|
td_u32 i;
|
|
td_u32 samp_count;
|
|
ext_drv_stat_mark *mark = TD_NULL;
|
|
|
|
samp_count = g_stat_control.sampling_count;
|
|
|
|
mark = osal_kmalloc(sizeof(ext_drv_stat_mark) * samp_count, OSAL_GFP_KERNEL);
|
|
if (mark == TD_NULL) {
|
|
soc_log_err("malloc failed .\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
for (i = 0; i < samp_count; i++) {
|
|
mark[i].frame_index = 0;
|
|
mark[i].mod_step_count = 0;
|
|
}
|
|
return mark;
|
|
}
|
|
static td_s32 drv_stat_mark_cmp(const td_void *a, const td_void *b)
|
|
{
|
|
ext_drv_stat_mark *tmp1 = (ext_drv_stat_mark *)a;
|
|
ext_drv_stat_mark *tmp2 = (ext_drv_stat_mark *)b;
|
|
|
|
return tmp1->mod_step_count - tmp2->mod_step_count;
|
|
}
|
|
|
|
static td_void drv_stat_mark_sort(ext_drv_stat_mark *step, td_u32 size)
|
|
{
|
|
if (step == TD_NULL || size == 0) {
|
|
soc_log_err("input params are invalid.\n");
|
|
return;
|
|
}
|
|
|
|
sort(step, size, sizeof(ext_drv_stat_mark), drv_stat_mark_cmp, TD_NULL);
|
|
return;
|
|
}
|
|
static td_void drv_stat_mark_process(const ext_drv_stat_cfg_node *cfg_node, ext_drv_stat_mark *mark)
|
|
{
|
|
td_u32 i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
ext_drv_stat_module *stat_module = TD_NULL;
|
|
td_u32 max_step_count;
|
|
|
|
if (cfg_node == TD_NULL || mark == TD_NULL) {
|
|
soc_log_err("input params null.\n");
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
|
|
osal_spin_lock(&stat_frame->frame_lock);
|
|
|
|
stat_module = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, cfg_node->mod_id);
|
|
if (stat_module == TD_NULL) {
|
|
mark[i].frame_index = stat_frame->frame_index;
|
|
mark[i].mod_step_count = 0;
|
|
} else {
|
|
mark[i].frame_index = stat_module->stat_index.frame_index;
|
|
mark[i].mod_step_count = stat_module->step_index;
|
|
}
|
|
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
}
|
|
|
|
/* sort by step count */
|
|
drv_stat_mark_sort(mark, g_stat_control.sampling_count);
|
|
|
|
/* the last mark is the max step count after sort */
|
|
max_step_count = mark[g_stat_control.sampling_count - 1].mod_step_count;
|
|
|
|
/* mark invalid data */
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
if (mark[i].mod_step_count != max_step_count) {
|
|
stat_frame = drv_stat_get_frame_by_index(mark[i].frame_index);
|
|
if (stat_frame != TD_NULL) {
|
|
stat_frame->data_vaild = TD_FALSE;
|
|
/* shoul make this stat_frame to vaild... */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static td_void drv_stat_mark_invalid_samping(td_void)
|
|
{
|
|
td_u32 samp_count;
|
|
ext_drv_stat_mark *mark = TD_NULL;
|
|
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
|
|
td_ulong flags;
|
|
|
|
samp_count = g_stat_control.sampling_count;
|
|
|
|
mark = drv_stat_malloc_mark();
|
|
if (mark == TD_NULL) {
|
|
soc_log_err("malloc mark memory failed.\n");
|
|
return;
|
|
}
|
|
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
|
|
osal_list_for_each_entry(cfg_node, &mod_cfg_list, node) {
|
|
drv_stat_mark_process(cfg_node, mark);
|
|
}
|
|
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
osal_kfree(mark);
|
|
mark = TD_NULL;
|
|
return;
|
|
}
|
|
static td_s32 drv_stat_calc_all_module(td_void)
|
|
{
|
|
td_s32 ret;
|
|
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
|
|
td_u32 frame_count;
|
|
td_u64 *mod_cost = TD_NULL;
|
|
td_ulong flags;
|
|
|
|
frame_count = g_stat_control.stat_count;
|
|
mod_cost = osal_kmalloc(sizeof(td_u64) * frame_count, OSAL_GFP_KERNEL);
|
|
if (mod_cost == TD_NULL) {
|
|
soc_log_err("malloc failed .\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (memset_s(mod_cost, sizeof(td_u64) * frame_count, 0x0, sizeof(td_u64) * frame_count) != EOK) {
|
|
soc_log_err("memset_s failed.\n");
|
|
osal_kfree(mod_cost);
|
|
mod_cost = TD_NULL;
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
|
|
osal_list_for_each_entry(cfg_node, &mod_cfg_list, node) {
|
|
if (cfg_node->is_calc == TD_TRUE) {
|
|
continue;
|
|
}
|
|
|
|
ret = drv_stat_calc_by_module(mod_cost, cfg_node);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("clac avg mod :0x%x\n", cfg_node->mod_id);
|
|
ret = TD_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
ret = TD_SUCCESS;
|
|
out:
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
osal_kfree(mod_cost);
|
|
mod_cost = TD_NULL;
|
|
return ret;
|
|
}
|
|
|
|
static ext_drv_stat_frame *drv_stat_get_frame(const stat_info *info)
|
|
{
|
|
td_u32 frame_index;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
|
|
/* get frame index */
|
|
frame_index = (td_u32)(info->index & 0xFFFFFFFF);
|
|
|
|
/* get stat_frame by index */
|
|
stat_frame = drv_stat_get_frame_by_index(frame_index);
|
|
if (stat_frame != TD_NULL) {
|
|
return stat_frame;
|
|
}
|
|
/* Determines whether the module info data is valid.
|
|
The judgment based on the first event must be step number is 0x1. */
|
|
|
|
/* find one vaild stat frame */
|
|
stat_frame = drv_stat_get_frame_valid();
|
|
if (stat_frame != TD_NULL) {
|
|
stat_frame->is_vaild = TD_FALSE;
|
|
return stat_frame;
|
|
}
|
|
/* Some modules get video frame processing and wait until the next dozen frames come out. */
|
|
g_stat_control.finish = TD_TRUE;
|
|
return TD_NULL;
|
|
}
|
|
|
|
static td_s32 drv_stat_info_notify_process(const stat_info *info, ext_drv_stat_frame *stat_frame, td_u64 current_us)
|
|
{
|
|
ext_drv_stat_module *module_node = TD_NULL;
|
|
|
|
if (info == TD_NULL || stat_frame == TD_NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
osal_spin_lock(&stat_frame->frame_lock);
|
|
/* find the stat module by frame index & mod id instance_id etc.. */
|
|
module_node = drv_stat_list_get_module(&stat_frame->module_list, info);
|
|
if (module_node != TD_NULL) {
|
|
/* mark other steps time */
|
|
drv_stat_step_action_mark(current_us, info, module_node);
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
return TD_SUCCESS;
|
|
}
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
/* the module id is not in the stat_frame module list.
|
|
so create new one and add to the module_list */
|
|
stat_frame->frame_index = (td_u32)(info->index & 0xFFFFFFFF);
|
|
module_node = drv_stat_module_create(info);
|
|
if (module_node == TD_NULL) {
|
|
soc_log_err("create stat module node failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
/* mark first step time */
|
|
drv_stat_step_action_mark(current_us, info, module_node);
|
|
|
|
osal_spin_lock(&stat_frame->frame_lock);
|
|
/* add stat_mod to stat_frame_list */
|
|
osal_list_add_tail(&module_node->node, &(stat_frame->module_list));
|
|
stat_frame->module_count++;
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 drv_stat_info_notify(const ext_drv_stat_info *sampling_info)
|
|
{
|
|
td_s32 ret;
|
|
const stat_info *info = TD_NULL;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
|
|
if (sampling_info == TD_NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
info = &sampling_info->info;
|
|
ret = drv_stat_module_cfg(info->mod_id);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("mod id:0x%x add module cfg list failed!\n", info->mod_id);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
stat_frame = drv_stat_get_frame(info);
|
|
if (stat_frame == TD_NULL) {
|
|
soc_log_info(" stat finish to get frame information.\n");
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
ret = drv_stat_info_notify_process(info, stat_frame, sampling_info->current_time);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("notify process failed . \n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
td_s32 ext_drv_stat_info_notify(const stat_info *info)
|
|
{
|
|
ext_drv_stat_info notify_info;
|
|
td_u64 current_us = osal_sched_clock();
|
|
|
|
if (g_stat_control.stat_enable == TD_FALSE) {
|
|
/* the stat feature dose not affect business process, so we should return SUCCESS */
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
if (g_stat_control.calc == TD_TRUE) {
|
|
/* calc complete no need insert */
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
if (kfifo_is_full(&g_stat_control.stat_fifo)) {
|
|
/* Sampled data fills up the 4M memory of the kfifo malloced.
|
|
Later you need to implement real-time sampling data acquisition to kfifo_reset and reset related flags.
|
|
for example : kfifo_reset calc finish flag... */
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
if (info == TD_NULL) {
|
|
soc_log_err("invalid input params is null.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (memcpy_s(¬ify_info.info, sizeof(notify_info.info), info, sizeof(stat_info)) != EOK) {
|
|
soc_log_err("memcpy_s failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
notify_info.info.index |= ((td_u64)(notify_info.info.mod_id & 0xFF)) << 56; /* bits[56~63] is mod_id */
|
|
notify_info.current_time = current_us + info->delta;
|
|
|
|
kfifo_in_spinlocked(&g_stat_control.stat_fifo, ¬ify_info, 1, &fifo_lock);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 drv_stat_ioctl(td_u32 cmd, td_void *arg, td_void *private_data)
|
|
{
|
|
switch (cmd) {
|
|
case STAT_CMPI_EVENT: {
|
|
break;
|
|
}
|
|
case STAT_CMPI_LD_EVENT: {
|
|
break;
|
|
}
|
|
case STAT_INFO_NOTIFY: {
|
|
if (arg != TD_NULL) {
|
|
return ext_drv_stat_info_notify((stat_info *)arg);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
soc_log_err("unknown command 0x%x\n", cmd);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 drv_proc_buf_reset(drv_stat_buf *buf)
|
|
{
|
|
td_u32 buf_len = sizeof(td_char) * EXT_STAT_PROC_BUF_LEN;
|
|
|
|
if (buf == TD_NULL || buf->buffer == TD_NULL) {
|
|
soc_log_err("input params is null.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (memset_s(buf->buffer, buf_len, 0x0, buf_len) != EOK) {
|
|
soc_log_err("memset_s failed ..\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
buf->len = buf_len;
|
|
buf->write_len = 0;
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 drv_proc_buf_malloc(drv_stat_buf *buf)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 buf_len = sizeof(td_char) * EXT_STAT_PROC_BUF_LEN;
|
|
|
|
if (buf == TD_NULL) {
|
|
soc_log_err("input params is null.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
buf->buffer = osal_kmalloc(buf_len, OSAL_GFP_KERNEL);
|
|
if (buf->buffer == TD_NULL) {
|
|
soc_log_err("malloc for mod details failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = drv_proc_buf_reset(buf);
|
|
if (ret != TD_SUCCESS) {
|
|
osal_kfree(buf->buffer);
|
|
buf->buffer = TD_NULL;
|
|
return TD_FAILURE;
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void drv_proc_buf_release(drv_stat_buf *buf)
|
|
{
|
|
if (buf == TD_NULL || buf->buffer == TD_NULL) {
|
|
return;
|
|
}
|
|
|
|
osal_kfree(buf->buffer);
|
|
buf->buffer = TD_NULL;
|
|
buf->len = 0;
|
|
buf->write_len = 0;
|
|
}
|
|
static td_void drv_stat_proc_print_module(td_void *s)
|
|
{
|
|
td_ulong flags;
|
|
ext_drv_stat_cfg_node *module_node = TD_NULL;
|
|
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
osal_list_for_each_entry(module_node, &mod_cfg_list, node) {
|
|
osal_seq_printf(s, "module_name:\t%-16s\tcost_avg:\t%-16llu\tcost_min:\t%-16llu\tcost_max:\t%-16llu\n",
|
|
module_node->module_name,
|
|
DIV_ROUND_CLOSEST_ULL(module_node->mod_total_cost_avg, 1000000), /* 1000000, ns to ms */
|
|
DIV_ROUND_CLOSEST_ULL(module_node->mod_total_cost_min, 1000000), /* 1000000, ns to ms */
|
|
DIV_ROUND_CLOSEST_ULL(module_node->mod_total_cost_max, 1000000)); /* 1000000, ns to ms */
|
|
}
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
}
|
|
|
|
static td_s32 drv_stat_cmp_info(const td_void *a, const td_void *b)
|
|
{
|
|
const ext_drv_stat_mod_info *tmp0 = (const ext_drv_stat_mod_info *)a;
|
|
const ext_drv_stat_mod_info *tmp1 = (const ext_drv_stat_mod_info *)b;
|
|
|
|
if ((tmp0->stat_index.instance_id != tmp1->stat_index.instance_id)) {
|
|
return tmp0->stat_index.instance_id - tmp1->stat_index.instance_id;
|
|
}
|
|
|
|
return (tmp0->in_mark - tmp1->in_mark);
|
|
}
|
|
|
|
static td_s32 drv_stat_module_info_sort(ext_drv_stat_mod_info *mod_info, td_u32 len)
|
|
{
|
|
if (mod_info == TD_NULL || len == 0) {
|
|
soc_log_err("input params are invalid.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
sort(mod_info, len, sizeof(ext_drv_stat_mod_info), drv_stat_cmp_info, TD_NULL);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 drv_stat_get_module_info_data(const ext_drv_stat_frame *stat_frame, ext_drv_stat_mod_info *mod_info)
|
|
{
|
|
td_u32 i = 0;
|
|
td_u32 j;
|
|
struct osal_list_head *pos = TD_NULL;
|
|
struct osal_list_head *nex = TD_NULL;
|
|
ext_drv_stat_module *stat_module = TD_NULL;
|
|
|
|
if (stat_frame == TD_NULL || mod_info == TD_NULL || stat_frame->module_list.next == TD_NULL) {
|
|
soc_log_err("input params is null.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
osal_list_for_each_safe(pos, nex, &stat_frame->module_list) {
|
|
stat_module = osal_list_entry(pos, ext_drv_stat_module, node);
|
|
/* find the first valid step, and this step is the minimum step for sort before */
|
|
for (j = 0; j < stat_module->step_max; j++) {
|
|
if (stat_module->step_info[j].value_invald == TD_TRUE) {
|
|
break;
|
|
}
|
|
}
|
|
mod_info[i].in_mark = stat_module->step_info[j].us_time;
|
|
mod_info[i].path_index = 0xFF;
|
|
mod_info[i].mod_id = stat_module->mod_id;
|
|
mod_info[i].stat_index.frame_index = stat_module->stat_index.frame_index;
|
|
mod_info[i].stat_index.instance_id = stat_module->stat_index.instance_id;
|
|
mod_info[i].stat_index.mod_id = stat_module->stat_index.mod_id;
|
|
mod_info[i].stat_index.one2multi_id = stat_module->stat_index.one2multi_id;
|
|
mod_info[i].stat_index.reserved = stat_module->stat_index.reserved;
|
|
i++;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static ext_drv_stat_mod_info *drv_stat_proc_modinfo_malloc(td_u32 modinfo_size)
|
|
{
|
|
ext_drv_stat_mod_info *mod_info = TD_NULL;
|
|
|
|
mod_info = osal_kmalloc(sizeof(ext_drv_stat_mod_info) * modinfo_size, OSAL_GFP_KERNEL);
|
|
if (mod_info == TD_NULL) {
|
|
soc_log_err("malloc failed.\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
if (memset_s(mod_info, sizeof(ext_drv_stat_mod_info) * modinfo_size, 0x0,
|
|
sizeof(ext_drv_stat_mod_info) * modinfo_size) != EOK) {
|
|
soc_log_err("memset_s failed.\n");
|
|
osal_kfree(mod_info);
|
|
mod_info = TD_NULL;
|
|
return TD_NULL;
|
|
}
|
|
|
|
return mod_info;
|
|
}
|
|
|
|
static td_void drv_stat_proc_modinfo_release(const ext_drv_stat_mod_info *mod_info)
|
|
{
|
|
if (mod_info == TD_NULL) {
|
|
soc_log_err("mod_info is null.\n");
|
|
return;
|
|
}
|
|
|
|
osal_kfree(mod_info);
|
|
mod_info = TD_NULL;
|
|
}
|
|
|
|
static td_s32 drv_stat_calc_path_count(ext_drv_stat_mod_info *mod_info, td_u32 len, td_u32 *path_count)
|
|
{
|
|
td_u32 i;
|
|
td_u8 path_index = 0;
|
|
ext_drv_stat_mod_info *tmp = TD_NULL;
|
|
td_u8 instance_id = 0xFF;
|
|
|
|
if (mod_info == TD_NULL || len == 0 || path_count == TD_NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
tmp = &mod_info[i];
|
|
if (tmp->stat_index.instance_id == 0xFF) {
|
|
break;
|
|
}
|
|
|
|
if (instance_id != tmp->stat_index.instance_id) {
|
|
instance_id = tmp->stat_index.instance_id;
|
|
path_index++;
|
|
}
|
|
tmp->path_index = path_index;
|
|
}
|
|
*path_count = path_index;
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 drv_stat_proc_modinfo_data_process(
|
|
const ext_drv_stat_frame *stat_frame, ext_drv_stat_mod_info *mod_info, td_u32 *path_count)
|
|
{
|
|
td_s32 ret;
|
|
|
|
if (stat_frame == TD_NULL || mod_info == TD_NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
/* sort by instance one2mutil and mark time */
|
|
ret = drv_stat_module_info_sort(mod_info, stat_frame->module_count);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("module info sort failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = drv_stat_calc_path_count(mod_info, stat_frame->module_count, path_count);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("calc path count failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static ext_drv_stat_mod_info *drv_stat_path(ext_drv_stat_frame *stat_frame, td_u32 *path_count)
|
|
{
|
|
td_s32 ret;
|
|
ext_drv_stat_mod_info *mod_info = TD_NULL;
|
|
|
|
if (stat_frame == TD_NULL) {
|
|
soc_log_err("input params is null\n");
|
|
return NULL;
|
|
}
|
|
|
|
osal_spin_lock(&stat_frame->frame_lock);
|
|
|
|
mod_info = drv_stat_proc_modinfo_malloc(stat_frame->module_count);
|
|
if (mod_info == TD_NULL) {
|
|
soc_log_err("mod info malloc failed.\n");
|
|
goto out0;
|
|
}
|
|
|
|
ret = drv_stat_get_module_info_data(stat_frame, mod_info);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("get module info data failed.\n");
|
|
goto out1;
|
|
}
|
|
|
|
ret = drv_stat_proc_modinfo_data_process(stat_frame, mod_info, path_count);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("process module info data failed.\n");
|
|
goto out1;
|
|
}
|
|
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
return mod_info;
|
|
|
|
out1:
|
|
drv_stat_proc_modinfo_release(mod_info);
|
|
mod_info = TD_NULL;
|
|
out0:
|
|
osal_spin_unlock(&stat_frame->frame_lock);
|
|
return mod_info;
|
|
}
|
|
|
|
|
|
static td_void drv_stat_show_frame_index(td_void *s)
|
|
{
|
|
td_u32 i;
|
|
td_s32 ret;
|
|
td_char tmp[0x20] = {0};
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
td_u32 count = 0;
|
|
|
|
osal_seq_printf(s, "%-16s\t", " ");
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
if (stat_frame->data_vaild == TD_FALSE) {
|
|
continue;
|
|
}
|
|
if (count >= g_stat_control.stat_count) {
|
|
break;
|
|
}
|
|
count++;
|
|
ret = sprintf_s(tmp, sizeof(tmp) - 1, "%s%03u", "mod(in-out)index", stat_frame->frame_index);
|
|
if (ret < 0) {
|
|
soc_log_err("frame sprintf_s failed.\n");
|
|
return;
|
|
}
|
|
osal_seq_printf(s, "%-24s\t", tmp);
|
|
if ((count % EXT_STAT_PRINT_NUM_OF_LINE) == 0) {
|
|
osal_seq_printf(s, "\n%-16s\t", " ");
|
|
}
|
|
}
|
|
osal_seq_printf(s, "\n");
|
|
}
|
|
|
|
static td_void drv_stat_show_path_index(td_void *s, td_u32 path_index)
|
|
{
|
|
osal_seq_printf(s,
|
|
"------------------------------- the entire path %d take time ------------------------------------\n",
|
|
path_index);
|
|
}
|
|
static td_s32 drv_stat_show_module_data_inter(td_void *s, td_char *tmp, td_u32 tmp_len,
|
|
ext_drv_stat_module *stat_module)
|
|
{
|
|
td_s32 ret;
|
|
td_bool name_show = TD_FALSE;
|
|
/* show this mod info */
|
|
if (name_show == TD_FALSE) {
|
|
ret = sprintf_s(tmp, tmp_len - 1, "%s%s", stat_module->name, "(ns)");
|
|
if (ret < 0) {
|
|
soc_log_err("frame sprintf_s failed!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
osal_seq_printf(s, "%-16s\t", tmp);
|
|
name_show = TD_TRUE;
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void drv_stat_show_module_data(td_void *s, td_u32 mod_id)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 j, i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
ext_drv_stat_module *stat_module = TD_NULL;
|
|
td_char tmp[0x20] = {0};
|
|
ext_drv_stat_step *step_in = TD_NULL;
|
|
ext_drv_stat_step *step_out = TD_NULL;
|
|
td_u32 count = 0;
|
|
|
|
for (j = 0; j < g_stat_control.sampling_count; j++) {
|
|
stat_frame = &g_stat_control.stat_frame[j];
|
|
if (stat_frame->data_vaild == TD_FALSE) {
|
|
continue;
|
|
}
|
|
if (count >= g_stat_control.stat_count) {
|
|
break;
|
|
}
|
|
count++;
|
|
stat_module = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, mod_id);
|
|
stat_para_equel_null_return(stat_module, "not find mod_id", mod_id);
|
|
|
|
/* show this mod info */
|
|
ret = drv_stat_show_module_data_inter(s, tmp, sizeof(tmp), stat_module);
|
|
if (ret != TD_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < stat_module->step_max; i++) {
|
|
if (stat_module->step_info[i].value_invald == TD_TRUE) {
|
|
step_in = &stat_module->step_info[i];
|
|
break;
|
|
}
|
|
}
|
|
step_out = &stat_module->step_info[stat_module->step_max - 1];
|
|
stat_para_equel_null_return(step_in, "step_in is NULL", 0);
|
|
|
|
ret = sprintf_s(tmp, sizeof(tmp) - 1, "0x%llx-0x%llx", step_in->us_time, step_out->us_time);
|
|
if (ret < 0) {
|
|
soc_log_err("frame sprintf_s failed .\n");
|
|
return;
|
|
}
|
|
osal_seq_printf(s, "%-24s\t", tmp);
|
|
if ((count % EXT_STAT_PRINT_NUM_OF_LINE) == 0) {
|
|
osal_seq_printf(s, "\n%-16s\t", " ");
|
|
}
|
|
}
|
|
osal_seq_printf(s, "\n");
|
|
}
|
|
|
|
static td_void drv_stat_show_path_cost(td_void *s, td_u32 stat_id, td_u32 end_id)
|
|
{
|
|
td_u32 j, i;
|
|
td_bool name_show = TD_FALSE;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
ext_drv_stat_module *module_in = TD_NULL;
|
|
ext_drv_stat_module *module_out = TD_NULL;
|
|
td_char tmp[0x20] = {0};
|
|
ext_drv_stat_step *step_in = TD_NULL;
|
|
ext_drv_stat_step *step_out = TD_NULL;
|
|
td_u32 count = 0;
|
|
td_u64 cut_time;
|
|
|
|
for (j = 0; j < g_stat_control.sampling_count; j++) {
|
|
stat_frame = &g_stat_control.stat_frame[j];
|
|
if (stat_frame->data_vaild == TD_FALSE) {
|
|
continue;
|
|
}
|
|
|
|
if (count >= g_stat_control.stat_count) {
|
|
break;
|
|
}
|
|
module_in = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, stat_id);
|
|
stat_para_equel_null_return(module_in, "not find start mod_id", stat_id);
|
|
|
|
module_out = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, end_id);
|
|
stat_para_equel_null_return(module_out, "not find end mod_id", end_id);
|
|
|
|
/* show this mod info */
|
|
if (name_show == TD_FALSE) {
|
|
osal_seq_printf(s, "%-16s\t", "path_cost_time(ms)");
|
|
name_show = TD_TRUE;
|
|
}
|
|
|
|
for (i = 0; i < module_in->step_max; i++) {
|
|
if (module_in->step_info[i].value_invald == TD_TRUE) {
|
|
step_in = &module_in->step_info[i];
|
|
break;
|
|
}
|
|
}
|
|
step_out = &module_out->step_info[module_out->step_max - 1];
|
|
stat_para_equel_null_return(step_in, "step_in is NULL", 0);
|
|
|
|
cut_time = DIV_ROUND_CLOSEST_ULL(step_out->us_time - step_in->us_time, 1000000); /* 1000000, ns to ms */
|
|
if (sprintf_s(tmp, sizeof(tmp) - 1, "%llu", cut_time) < 0) {
|
|
soc_log_err("sprintf_s failed...\n");
|
|
return;
|
|
}
|
|
osal_seq_printf(s, "%-24s\t", tmp);
|
|
count++;
|
|
if ((count % EXT_STAT_PRINT_NUM_OF_LINE) == 0) {
|
|
osal_seq_printf(s, "\n%-16s\t", " ");
|
|
}
|
|
}
|
|
osal_seq_printf(s, "\n");
|
|
}
|
|
|
|
static td_void drv_stat_proc_print_path(td_void *s)
|
|
{
|
|
td_u32 i, j;
|
|
td_u32 path_count = 0;
|
|
ext_drv_stat_mod_info *mod_info = TD_NULL;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
td_u32 start_mod_id;
|
|
td_u32 end_mod_id = 0;
|
|
|
|
/* find a valid frame */
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
if (stat_frame->data_vaild == TD_TRUE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* calc the path info */
|
|
mod_info = drv_stat_path(stat_frame, &path_count);
|
|
if (mod_info == TD_NULL) {
|
|
soc_log_err("stat_path failed.\n");
|
|
return;
|
|
}
|
|
|
|
/* show all path data */
|
|
j = 0;
|
|
for (i = 0; i < path_count; i++) {
|
|
/* show path index */
|
|
drv_stat_show_path_index(s, i);
|
|
drv_stat_show_frame_index(s);
|
|
start_mod_id = mod_info[j].mod_id;
|
|
while (j < stat_frame->module_count) {
|
|
if (mod_info[j].path_index != i + 1) {
|
|
break;
|
|
}
|
|
drv_stat_show_module_data(s, mod_info[j].mod_id);
|
|
end_mod_id = mod_info[j].mod_id;
|
|
j++;
|
|
}
|
|
/* show entir path cost time */
|
|
drv_stat_show_path_cost(s, start_mod_id, end_mod_id);
|
|
}
|
|
/* release module info */
|
|
drv_stat_proc_modinfo_release(mod_info);
|
|
mod_info = TD_NULL;
|
|
}
|
|
|
|
static td_s32 drv_stat_init(td_void)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
|
|
if (g_stat_control.stat_count > EXT_STAT_FRAME_COUNT_MAX) {
|
|
soc_log_err(" g_stat_count %d > Count_MAX %d \n", g_stat_control.stat_count, EXT_STAT_FRAME_COUNT_MAX);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
g_stat_control.stat_frame = osal_kmalloc(
|
|
sizeof(ext_drv_stat_frame) * g_stat_control.sampling_count, OSAL_GFP_KERNEL);
|
|
if (g_stat_control.stat_frame == TD_NULL) {
|
|
soc_log_err("kmalloc stat_fram failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
stat_frame->frame_index = 0xffffffff;
|
|
stat_frame->is_vaild = TD_TRUE;
|
|
stat_frame->data_vaild = TD_TRUE;
|
|
stat_frame->module_count = 0;
|
|
OSAL_INIT_LIST_HEAD(&stat_frame->module_list);
|
|
ret = osal_spin_lock_init(&stat_frame->frame_lock);
|
|
if (ret != 0) {
|
|
soc_log_err("spin lock init failed .\n");
|
|
goto out0;
|
|
}
|
|
}
|
|
|
|
ret = kfifo_alloc(&g_stat_control.stat_fifo, EXT_STAT_FIFO_SIZE, GFP_KERNEL);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("kfifo init failed.\n");
|
|
goto out0;
|
|
}
|
|
return TD_SUCCESS;
|
|
|
|
out0:
|
|
osal_kfree(g_stat_control.stat_frame);
|
|
g_stat_control.stat_frame = TD_NULL;
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
static td_void drv_stat_deinit(td_void)
|
|
{
|
|
td_u32 i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
|
|
if (g_stat_control.stat_frame == TD_NULL) {
|
|
soc_log_info("stat feature is not enable .\n");
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
drv_stat_module_release(stat_frame);
|
|
osal_spin_lock_destroy(&stat_frame->frame_lock);
|
|
}
|
|
|
|
drv_stat_reset_module_calc_flag();
|
|
|
|
osal_kfree(g_stat_control.stat_frame);
|
|
g_stat_control.stat_frame = TD_NULL;
|
|
|
|
kfifo_free(&g_stat_control.stat_fifo);
|
|
}
|
|
|
|
static td_void drv_stat_reset_calc(td_void)
|
|
{
|
|
td_u32 i;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
|
|
if (g_stat_control.stat_frame == TD_NULL) {
|
|
soc_log_info("stat feature is not enable .\n");
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
drv_stat_frame_calc_release(stat_frame);
|
|
}
|
|
|
|
drv_stat_reset_module_calc_flag();
|
|
}
|
|
|
|
static td_s32 drv_stat_proc_read(td_void *s, td_void *arg)
|
|
{
|
|
osal_spin_lock(&g_stat_control.stat_control);
|
|
|
|
osal_seq_printf(s,
|
|
"=============================== common stat ===============================\n");
|
|
osal_seq_printf(s, "%-10s:\t%s\n", "g_stat_enable", (g_stat_control.stat_enable == TD_TRUE ? "true" : "false"));
|
|
if (g_stat_control.stat_enable != TD_TRUE) {
|
|
osal_seq_printf(s, "stat feature is not enable!\n");
|
|
goto out;
|
|
}
|
|
if (g_stat_control.finish != TD_TRUE || g_stat_control.calc != TD_TRUE) {
|
|
osal_seq_printf(s, "Data sampling or calc is not complete, please wait....\n");
|
|
goto out;
|
|
}
|
|
|
|
osal_seq_printf(s, "%-10s:\t%d\n", "g_stat_count", g_stat_control.stat_count);
|
|
|
|
drv_stat_proc_print_path(s);
|
|
osal_seq_printf(s,
|
|
"------------------------------- the module statistics take time (ms) -------------------------------\n");
|
|
drv_stat_proc_print_module(s);
|
|
|
|
out:
|
|
osal_seq_printf(s,
|
|
"================================ stat info end ================================\n");
|
|
osal_spin_unlock(&g_stat_control.stat_control);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static int stat_proc_cmd_help(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
|
|
{
|
|
td_u32 i;
|
|
td_u32 count = 0;
|
|
const td_char *format = "%-4s %-8s %-12s %-12s %-16s %s\n";
|
|
const drv_stat_proc_help_info help_info[] = {
|
|
{"echo", "command", "para1", "para2", "path", "explanation"},
|
|
{"echo", "help", "", "", "> /proc/msp/stat", "show help information"},
|
|
{"echo", "start", "20~100", "", "> /proc/msp/stat", "enable the stat feature"},
|
|
{"echo", "stop", "", "", "> /proc/msp/stat", "disable the stat feature"},
|
|
{"echo", "select", "instance_id", "", "> /proc/msp/stat", "show the specified entire path"},
|
|
{"echo", "details", "mod_name", "instance_id", "> /proc/msp/stat", "show one module details"},
|
|
};
|
|
|
|
ext_drv_proc_echo_helper("==============================common stat====================================\n");
|
|
|
|
for (i = 0; i < sizeof(help_info) / sizeof(drv_stat_proc_help_info); i++) {
|
|
ext_drv_proc_echo_helper(format,
|
|
help_info[i].echo, help_info[i].command, help_info[i].para1,
|
|
help_info[i].para2, help_info[i].path, help_info[i].explanation);
|
|
}
|
|
|
|
ext_drv_proc_echo_helper("\nmod_name -->\n");
|
|
for (i = 0; i < SOC_ID_TSFW + 1; i++) {
|
|
if (strcmp(g_mod_name[i], "unknown") == 0 || g_mod_name[i] == TD_NULL) {
|
|
continue;
|
|
}
|
|
ext_drv_proc_echo_helper("%-12s", g_mod_name[i]);
|
|
if (((++count) % 0x8) == 0) { /* 8 each line */
|
|
ext_drv_proc_echo_helper("\n");
|
|
}
|
|
}
|
|
|
|
ext_drv_proc_echo_helper("\n===========================================================================\n");
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static int stat_proc_cmd_sampling(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
|
|
{
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 drv_stat_get_mod_instance_id(
|
|
unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_u8 *mod_id, td_u8 *instance_id)
|
|
{
|
|
td_s32 ret = TD_FAILURE;
|
|
td_u32 i;
|
|
|
|
if (argv == TD_NULL || mod_id == TD_NULL || instance_id == TD_NULL) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (argc == 0x2 || argc == 0x3) {
|
|
for (i = 0; i < SOC_ID_TSFW + 1; i++) {
|
|
if (strcmp(argv[1], g_mod_name[i]) == 0) {
|
|
*mod_id = i;
|
|
ret = TD_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (argc == 0x2) {
|
|
if (strstr(argv[0x2], "0x") || strstr(argv[0x2], "0X")) {
|
|
*instance_id = simple_strtoul(argv[0x2], TD_NULL, 0x10);
|
|
} else {
|
|
*instance_id = simple_strtoul(argv[0x2], TD_NULL, 0xa);
|
|
}
|
|
} else {
|
|
*instance_id = 0;
|
|
}
|
|
} else {
|
|
soc_log_err("param is wrong!");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static td_void drv_stat_show_module_name(drv_stat_buf *buf, td_u8 mod_id)
|
|
{
|
|
td_ulong flags;
|
|
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
|
|
td_u32 write_len = 0;
|
|
td_s32 tmp_len;
|
|
td_char *s = TD_NULL;
|
|
const td_char *tmp1 = "---------------------------------- details module ";
|
|
const td_char *tmp2 = "------------------------------------";
|
|
const td_char *tmp3 = "================================== common stat ";
|
|
const td_char *tmp4 = "==========================================";
|
|
if (buf == TD_NULL) {
|
|
return;
|
|
}
|
|
spin_lock_irqsave(&mod_cfg_lock, flags);
|
|
cfg_node = drv_stat_module_find_node(&mod_cfg_list, mod_id);
|
|
if (cfg_node == TD_NULL) {
|
|
soc_log_err("can not find mod_id:0x%x\n", mod_id);
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
return;
|
|
}
|
|
|
|
s = buf->buffer + buf->write_len;
|
|
|
|
tmp_len = sprintf_s(s, buf->len, "\n%s%s\n", tmp3, tmp4);
|
|
if (tmp_len < 0) {
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return;
|
|
}
|
|
write_len += (td_u32)tmp_len;
|
|
|
|
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%s%s%s\n", tmp1, cfg_node->module_name, tmp2);
|
|
if (tmp_len < 0) {
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return;
|
|
}
|
|
write_len += (td_u32)tmp_len;
|
|
|
|
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "module name:%-16s module id:0x%-4x\n",
|
|
cfg_node->module_name, cfg_node->mod_id);
|
|
if (tmp_len < 0) {
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return;
|
|
}
|
|
write_len += (td_u32)tmp_len;
|
|
|
|
/* process s offset */
|
|
buf->len -= write_len;
|
|
buf->write_len += write_len;
|
|
spin_unlock_irqrestore(&mod_cfg_lock, flags);
|
|
}
|
|
static td_s32 drv_stat_proc_module_details_inter(drv_stat_buf *buf, td_char *s, const ext_drv_stat_module *mod,
|
|
td_u32 *write_len)
|
|
{
|
|
td_u32 i;
|
|
td_s32 tmp_len;
|
|
td_u32 tmp_write_len = *write_len;
|
|
td_bool title = TD_FALSE;
|
|
for (i = 1; i < mod->step_max; i++) {
|
|
if (mod->step_info[i].value_invald != TD_TRUE) {
|
|
continue;
|
|
}
|
|
if (title == TD_FALSE) {
|
|
tmp_len = sprintf_s(s + tmp_write_len, buf->len - tmp_write_len, "%-16u %-16llu %-16s 0x%-14llx %-16llu\n",
|
|
mod->stat_index.frame_index, mod->calc_result->mod_total_cost,
|
|
mod->step_info[i].step_name, mod->step_info[i].us_time, 0);
|
|
if (tmp_len < 0) {
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
tmp_write_len += (td_u32)tmp_len;
|
|
title = TD_TRUE;
|
|
} else {
|
|
tmp_len = sprintf_s(s + tmp_write_len, buf->len - tmp_write_len, "%-16s %-16s %-16s 0x%-14llx %-16llu\n",
|
|
"", "", mod->step_info[i].step_name, mod->step_info[i].us_time, mod->calc_result->step_cost[i - 1]);
|
|
if (tmp_len < 0) {
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return TD_FAILURE;
|
|
}
|
|
tmp_write_len += (td_u32)tmp_len;
|
|
}
|
|
}
|
|
*write_len = tmp_write_len;
|
|
return TD_SUCCESS;
|
|
}
|
|
static td_void drv_stat_proc_module_details(drv_stat_buf *buf, const ext_drv_stat_module *mod)
|
|
{
|
|
td_char *s = TD_NULL;
|
|
td_u32 write_len = 0;
|
|
td_s32 tmp_len;
|
|
td_s32 ret;
|
|
const td_char *frame_index = "frame index";
|
|
const td_char *total_time = "total time(ns)";
|
|
const td_char *step_action = "step action";
|
|
const td_char *step_value = "step value(ns)";
|
|
const td_char *step_cost = "step cost(ns)";
|
|
|
|
if (mod == TD_NULL || buf == TD_NULL || mod->calc_result == TD_NULL) {
|
|
soc_log_err("input params is null.\n");
|
|
return;
|
|
}
|
|
|
|
s = buf->buffer + buf->write_len;
|
|
|
|
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%s\n",
|
|
"-----------------------------------------------------------------------------------------");
|
|
if (tmp_len < 0) {
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return;
|
|
}
|
|
write_len += (td_u32)tmp_len;
|
|
|
|
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%-16s %-16s %-16s %-16s %-16s\n",
|
|
frame_index, total_time, step_action, step_value, step_cost);
|
|
if (tmp_len < 0) {
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return;
|
|
}
|
|
write_len += (td_u32)tmp_len;
|
|
|
|
ret = drv_stat_proc_module_details_inter(buf, s, mod, &write_len);
|
|
if (ret != TD_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%s\n",
|
|
"-----------------------------------------------------------------------------------------");
|
|
if (tmp_len < 0) {
|
|
soc_log_err("sprintf_s failed!\n");
|
|
return;
|
|
}
|
|
write_len += (td_u32)tmp_len;
|
|
|
|
/* process s offset */
|
|
buf->len -= write_len;
|
|
buf->write_len += write_len;
|
|
}
|
|
static td_s32 drv_proc_module_details_process_inter(const ext_drv_stat_index *stat_index, drv_stat_buf *mod_details_buf)
|
|
{
|
|
td_u32 i;
|
|
td_s32 ret;
|
|
td_u32 count = 0;
|
|
ext_drv_stat_frame *stat_frame = TD_NULL;
|
|
ext_drv_stat_module *mod_node = TD_NULL;
|
|
|
|
for (i = 0; i < g_stat_control.sampling_count; i++) {
|
|
stat_frame = &g_stat_control.stat_frame[i];
|
|
if (stat_frame->data_vaild != TD_TRUE) {
|
|
continue;
|
|
}
|
|
if (count >= g_stat_control.stat_count) {
|
|
break;
|
|
}
|
|
count++;
|
|
mod_node = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, stat_index->mod_id);
|
|
if (mod_node == TD_NULL) {
|
|
soc_log_err("stat frame list can not find 0x%x\n", stat_index->mod_id);
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
drv_stat_proc_module_details(mod_details_buf, mod_node);
|
|
/* Prevents buf overflow */
|
|
if (mod_details_buf->len - EXT_STAT_PROC_BUF_RESERVED < mod_details_buf->write_len) {
|
|
/* show proc info */
|
|
ext_drv_proc_echo_helper("%s", mod_details_buf->buffer);
|
|
/* reset buf */
|
|
if ((ret = drv_proc_buf_reset(mod_details_buf)) != TD_SUCCESS) {
|
|
soc_log_err("drv_proc_buf_reset failed, ret=%d\n", ret);
|
|
return TD_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
return TD_SUCCESS;
|
|
}
|
|
static td_s32 drv_proc_module_details_process(const ext_drv_stat_index *stat_index)
|
|
{
|
|
td_s32 ret;
|
|
td_s32 tmp_len;
|
|
drv_stat_buf mod_details_buf;
|
|
const td_char *tmp1 = "=============================================";
|
|
|
|
if (stat_index == TD_NULL) {
|
|
soc_log_err("input params is null.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
ret = drv_proc_buf_malloc(&mod_details_buf);
|
|
if (ret != TD_SUCCESS) {
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
drv_stat_show_module_name(&mod_details_buf, stat_index->mod_id);
|
|
|
|
ret = drv_proc_module_details_process_inter(stat_index, &mod_details_buf);
|
|
if (ret != TD_SUCCESS) {
|
|
goto out;
|
|
}
|
|
|
|
tmp_len = sprintf_s(mod_details_buf.buffer + mod_details_buf.write_len,
|
|
mod_details_buf.len - mod_details_buf.write_len, "%s%s\n", tmp1, tmp1);
|
|
if (tmp_len < 0) {
|
|
soc_log_err("sprintf_s failed!\n");
|
|
ret = TD_FAILURE;
|
|
goto out;
|
|
}
|
|
mod_details_buf.write_len += (td_u32)tmp_len;
|
|
|
|
ext_drv_proc_echo_helper("%s", mod_details_buf.buffer);
|
|
ret = TD_SUCCESS;
|
|
|
|
out:
|
|
drv_proc_buf_release(&mod_details_buf);
|
|
return ret;
|
|
}
|
|
|
|
static int stat_proc_cmd_module_details(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
|
|
{
|
|
td_s32 ret;
|
|
td_u8 mod_id;
|
|
td_u8 instance_id;
|
|
ext_drv_stat_index stat_index;
|
|
|
|
if (g_stat_control.stat_enable != TD_TRUE) {
|
|
soc_log_err("the stat feature is not enable.\n");
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
ret = drv_stat_get_mod_instance_id(argc, argv, &mod_id, &instance_id);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("get module & instance id failed. \n");
|
|
return ret;
|
|
}
|
|
|
|
stat_index.mod_id = mod_id;
|
|
stat_index.instance_id = instance_id;
|
|
if (g_stat_control.finish != TD_TRUE || g_stat_control.calc != TD_TRUE) {
|
|
ext_drv_proc_echo_helper("Data sampling or calculation is not completed, please wait....\n");
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
ret = drv_proc_module_details_process(&stat_index);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_log_err("proc module details process failed. 0x%x\n", mod_id);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int stat_proc_cmd_clean(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
|
|
{
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static int stat_proc_cmd_select(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
|
|
{
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static int stat_proc_cmd_start(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 stat_count;
|
|
|
|
if (argv == TD_NULL) {
|
|
soc_log_err(" input is null \n");
|
|
return TD_FAILURE;
|
|
}
|
|
/* should add lock to protect global member */
|
|
osal_spin_lock(&g_stat_control.stat_control);
|
|
if (g_stat_control.stat_enable == TD_TRUE) {
|
|
soc_log_info("stat feature is enable.\n");
|
|
ret = TD_SUCCESS;
|
|
goto out;
|
|
}
|
|
|
|
g_stat_control.stat_enable = TD_TRUE;
|
|
g_stat_control.finish = TD_FALSE;
|
|
g_stat_control.calc = TD_FALSE;
|
|
if (argc == 0x2) {
|
|
/* the second params is stat count */
|
|
if (strstr(argv[1], "0x") || strstr(argv[1], "0X")) {
|
|
stat_count = simple_strtoul(argv[1], TD_NULL, 0x10);
|
|
} else {
|
|
stat_count = simple_strtoul(argv[1], TD_NULL, 0xa);
|
|
}
|
|
if (stat_count >= EXT_STAT_FRAME_COUNT_MAX) {
|
|
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_MAX;
|
|
} else if (stat_count <= EXT_STAT_FRAME_COUNT_DEFAULT) {
|
|
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_DEFAULT;
|
|
} else {
|
|
g_stat_control.stat_count = stat_count;
|
|
}
|
|
} else {
|
|
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_DEFAULT;
|
|
}
|
|
g_stat_control.sampling_count = 0x6 * g_stat_control.stat_count;
|
|
ret = drv_stat_init();
|
|
if (ret != TD_SUCCESS) {
|
|
g_stat_control.stat_enable = TD_FALSE;
|
|
soc_log_err("stat init failed .\n");
|
|
ret = TD_FAILURE;
|
|
}
|
|
|
|
out:
|
|
osal_spin_unlock(&g_stat_control.stat_control);
|
|
return ret;
|
|
}
|
|
|
|
static int stat_proc_cmd_stop(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
|
|
{
|
|
if (argv == TD_NULL) {
|
|
soc_log_err(" input is null \n");
|
|
return TD_FAILURE;
|
|
}
|
|
osal_spin_lock(&g_stat_control.stat_control);
|
|
if (g_stat_control.stat_enable == TD_TRUE) {
|
|
drv_stat_remove_all_module();
|
|
drv_stat_deinit();
|
|
g_stat_control.stat_enable = TD_FALSE;
|
|
g_stat_control.finish = TD_FALSE;
|
|
g_stat_control.calc = TD_FALSE;
|
|
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_DEFAULT;
|
|
g_stat_control.sampling_count = 0;
|
|
}
|
|
osal_spin_unlock(&g_stat_control.stat_control);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 drv_stat_task(td_void *data)
|
|
{
|
|
td_s32 ret;
|
|
ext_drv_stat_info tmp_info;
|
|
|
|
while (!osal_kthread_should_stop()) {
|
|
if (g_stat_control.stat_enable == TD_TRUE && g_stat_control.calc == TD_TRUE) {
|
|
/* Waiting for the data to be updated */
|
|
osal_msleep(EXT_STAT_TASK_DELAY * 0x3);
|
|
continue;
|
|
}
|
|
/* make kfifo data can be readed by task. */
|
|
if (kfifo_is_empty(&g_stat_control.stat_fifo) == TD_TRUE) {
|
|
osal_msleep(EXT_STAT_TASK_DELAY * 0x3);
|
|
continue;
|
|
}
|
|
|
|
/* get stat_info data */
|
|
ret = (td_s32)kfifo_out_spinlocked(&g_stat_control.stat_fifo, &tmp_info, 1, &fifo_lock);
|
|
if (ret != 0x1) {
|
|
soc_log_err("got stat data error..%d -- %d\n", ret, sizeof(ext_drv_stat_info));
|
|
continue;
|
|
}
|
|
osal_spin_lock(&g_stat_control.stat_control);
|
|
ret = drv_stat_info_notify(&tmp_info);
|
|
if (ret != TD_SUCCESS) {
|
|
osal_spin_unlock(&g_stat_control.stat_control);
|
|
soc_log_err("stat info notify task process failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
/* calc data */
|
|
if (g_stat_control.finish == TD_TRUE && g_stat_control.calc == TD_FALSE) {
|
|
drv_stat_mark_invalid_samping();
|
|
drv_stat_reset_calc();
|
|
/* calc the stat data */
|
|
ret = drv_stat_calc_all_module();
|
|
if (ret != TD_SUCCESS) {
|
|
osal_spin_unlock(&g_stat_control.stat_control);
|
|
soc_log_err("calc all module failed.\n");
|
|
return ret;
|
|
}
|
|
g_stat_control.calc = TD_TRUE;
|
|
soc_log_err("calc all modules finished!\n");
|
|
}
|
|
|
|
osal_spin_unlock(&g_stat_control.stat_control);
|
|
|
|
osal_msleep(EXT_STAT_TASK_DELAY);
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
static osal_proc_cmd g_stat_proc_cmd[] = {
|
|
{ "help", stat_proc_cmd_help },
|
|
{ "sampling", stat_proc_cmd_sampling },
|
|
{ "details", stat_proc_cmd_module_details },
|
|
{ "select", stat_proc_cmd_select },
|
|
{ "start", stat_proc_cmd_start },
|
|
{ "stop", stat_proc_cmd_stop },
|
|
{ "clean", stat_proc_cmd_clean }
|
|
};
|
|
|
|
td_s32 drv_stat_add_proc(td_void)
|
|
{
|
|
td_s32 ret;
|
|
osal_proc_entry *item = TD_NULL;
|
|
|
|
ret = osal_spin_lock_init(&g_stat_control.stat_control);
|
|
if (ret != 0) {
|
|
soc_log_err("spin lock init failed .\n");
|
|
return TD_FAILURE;
|
|
}
|
|
g_stat_control.stat_enable = TD_FALSE;
|
|
|
|
item = osal_proc_add(EXT_STAT_PROC_NAME, strlen(EXT_STAT_PROC_NAME));
|
|
if (item == TD_NULL) {
|
|
soc_log_err("can't add moudle for stat.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
item->read = drv_stat_proc_read;
|
|
item->cmd_cnt = sizeof(g_stat_proc_cmd) / sizeof(osal_proc_cmd);
|
|
item->cmd_list = g_stat_proc_cmd;
|
|
|
|
g_stat_control.stat_task = osal_kthread_create(drv_stat_task, TD_NULL, "Stat_Task", 0);
|
|
if (g_stat_control.stat_task == TD_NULL) {
|
|
soc_log_err("stat task creat failed.\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_void drv_stat_remove_proc(td_void)
|
|
{
|
|
osal_kthread_destroy(g_stat_control.stat_task, TD_TRUE);
|
|
g_stat_control.stat_task = TD_NULL;
|
|
|
|
if (g_stat_control.stat_enable == TD_TRUE) {
|
|
drv_stat_remove_all_module();
|
|
drv_stat_deinit();
|
|
}
|
|
osal_proc_remove(EXT_STAT_PROC_NAME, strlen(EXT_STAT_PROC_NAME));
|
|
osal_spin_lock_destroy(&g_stat_control.stat_control);
|
|
return;
|
|
}
|
|
|
|
td_void ext_drv_stat_event(ext_stat_event event, td_u32 value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
td_void ext_drv_stat_ld_notify_event(const ext_stat_ld_event_info *event_info)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EXPORT_SYMBOL(ext_drv_stat_event);
|
|
EXPORT_SYMBOL(ext_drv_stat_ld_notify_event);
|
|
EXPORT_SYMBOL(ext_drv_stat_info_notify);
|