mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
platform: dce: Add Debugfs support for Perf
Add debugfs nodes - start/stop perf stats. - read perf stat stats - set the format type as csv or xml Add debugfs to capture perf events - Can enable specific perf events through debugfs node. Signed-off-by: Mahesh Kumar <mahkumar@nvidia.com> Change-Id: I0a7833d7a8f04296ba3806f4f2a218175080d2e2 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2765513 Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com> Reviewed-by: Arun Swain <arswain@nvidia.com> Reviewed-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com> Tested-by: Vinod Gopalakrishnakurup <vinodg@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
Laxman Dewangan
parent
b25786578c
commit
873e421d95
@@ -5,6 +5,7 @@
|
||||
#
|
||||
GCOV_PROFILE := y
|
||||
|
||||
ccflags-y += -I$(srctree.nvidia)/drivers/platform/tegra/dce/include
|
||||
ccflags-y += -Wno-multichar
|
||||
ccflags-y += -Werror
|
||||
ccflags-y += -Wno-error=cpp
|
||||
@@ -39,7 +40,7 @@ tegra-dce-$(CONFIG_TEGRA_DCE) += \
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_FS),y)
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += \
|
||||
dce-debug.o
|
||||
dce-debug.o \
|
||||
dce-admin-debug.o \
|
||||
dce-debug-perf.o
|
||||
endif
|
||||
|
||||
ccflags-y += -I$(srctree.nvidia-t23x)/drivers/platform/tegra/dce/include
|
||||
|
||||
164
drivers/platform/tegra/dce/dce-admin-debug.c
Normal file
164
drivers/platform/tegra/dce/dce-admin-debug.c
Normal file
@@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
|
||||
#include <dce.h>
|
||||
#include <dce-mailbox.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <dce-client-ipc-internal.h>
|
||||
#include <interface/dce-core-interface-errors.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
|
||||
/**
|
||||
* dce_admin_send_cmd_set_perf_stat - Start/stop DCE perf data collection.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @msg - Pointer to dce_ipc_msg struct.
|
||||
* @start_perf - Bool to indicate start/stop of perf data collection
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_send_cmd_set_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg,
|
||||
bool start_perf)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
|
||||
if (!msg || !msg->tx.data || !msg->rx.data)
|
||||
goto out;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
|
||||
if (start_perf == true)
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_START;
|
||||
else
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_STOP;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending set perf msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* dce_admin_send_cmd_get_perf_stat - Get DCE perf data.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @msg - Pointer to dce_ipc_msg struct.
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_send_cmd_get_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
|
||||
if (!msg || !msg->tx.data || !msg->rx.data)
|
||||
goto out;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_RESULTS;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending get perf msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dce_admin_send_cmd_get_perf_events(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
|
||||
if (!msg || !msg->tx.data || !msg->rx.data)
|
||||
goto out;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_GET_EVENTS;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending get perf events msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dce_admin_send_cmd_clear_perf_events(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
|
||||
if (!msg || !msg->tx.data || !msg->rx.data)
|
||||
goto out;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_CLEAR_EVENTS;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending clear perf events msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
||||
549
drivers/platform/tegra/dce/dce-debug-perf.c
Normal file
549
drivers/platform/tegra/dce/dce-debug-perf.c
Normal file
@@ -0,0 +1,549 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <dce.h>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
|
||||
#define DCE_PERF_OUTPUT_FORMAT_CSV ((uint32_t)(0U))
|
||||
#define DCE_PERF_OUTPUT_FORMAT_XML ((uint32_t)(1U))
|
||||
|
||||
static uint32_t perf_output_format = DCE_PERF_OUTPUT_FORMAT_CSV;
|
||||
|
||||
ssize_t dbg_dce_perf_stats_stats_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
bool start_perf;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct tegra_dce *d = ((struct seq_file *)file->private_data)->private;
|
||||
|
||||
ret = kstrtobool_from_user(user_buf, 3ULL, &start_perf);
|
||||
if (ret) {
|
||||
dce_err(d, "Unable to parse start/stop for dce perf stats");
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
|
||||
/*
|
||||
* Collect All Perfs
|
||||
* Clear previous data and start collecting new perf data
|
||||
*
|
||||
* TODO: Add support to collect specific perf data
|
||||
*/
|
||||
req_msg->args.perf.perf_cmd.enable = DCE_ADMIN_PERF_STATS_ALL;
|
||||
req_msg->args.perf.perf_cmd.clear = DCE_ADMIN_PERF_CLEAR_CLEAR;
|
||||
|
||||
/*
|
||||
* echo "1/y" (kstrtobool true) to start perf data collection
|
||||
* echo "0/n" (kstrtobool false) to stop perf data collection
|
||||
*/
|
||||
ret = dce_admin_send_cmd_set_perf_stat(d, msg, start_perf);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Set perf stat\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dce_debug(d, "DCE perf stats collection %s", start_perf ? "started" : "stopped");
|
||||
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_sched_task_xml(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_task_stats *task_stat)
|
||||
{
|
||||
/* Don't print task stats if task name is not set */
|
||||
if (task_stat->name == NULL)
|
||||
return;
|
||||
|
||||
seq_printf(s, "<task><name>%s</name>", task_stat->name);
|
||||
seq_printf(s, "<init>%llu</init><ready>%llu</ready>",
|
||||
task_stat->init, task_stat->ready);
|
||||
seq_printf(s, "<ready_time>%llu</ready_time>",
|
||||
task_stat->ready_time);
|
||||
seq_printf(s, "<dcache_misses>%llu</dcache_misses><instr_exec_count>%llu</instr_exec_count>",
|
||||
task_stat->dcache_misses, task_stat->inst_exec);
|
||||
seq_printf(s, "<mmio_req_count>%llu</mmio_req_count>",
|
||||
task_stat->mmio_req);
|
||||
seq_printf(s, "<stat><name>sleep</name><accumulate>%llu</accumulate>",
|
||||
task_stat->sleep.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations><min>%llu</min><max>%llu</max></stat>",
|
||||
task_stat->sleep.iterations,
|
||||
task_stat->sleep.min,
|
||||
task_stat->sleep.max);
|
||||
seq_printf(s, "<stat><name>run</name><accumulate>%llu</accumulate>",
|
||||
task_stat->run.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations><min>%llu</min><max>%llu</max></stat>",
|
||||
task_stat->run.iterations,
|
||||
task_stat->run.min,
|
||||
task_stat->run.max);
|
||||
seq_printf(s, "<stat><name>run-context</name><accumulate>%llu</accumulate>",
|
||||
task_stat->run_context.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations><min>%llu</min><max>%llu</max></stat>",
|
||||
task_stat->run_context.iterations,
|
||||
task_stat->run_context.min,
|
||||
task_stat->run_context.max);
|
||||
seq_puts(s, "</task>\n");
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_pm_event_xml(struct seq_file *s,
|
||||
const struct dce_admin_pm_event_stats *pm_evt)
|
||||
{
|
||||
seq_printf(s, "<start>%llu</start><end>%llu</end>\n", pm_evt->start, pm_evt->end);
|
||||
seq_printf(s, "<count>%llu</count>\n", pm_evt->count);
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_show_xml(struct seq_file *s, struct tegra_dce *d,
|
||||
struct dce_admin_perf_info *perf)
|
||||
{
|
||||
|
||||
const struct dce_admin_pm_event_stats *pm_evt;
|
||||
const struct dce_admin_sched_stats *sched = &perf->sched;
|
||||
uint32_t i;
|
||||
|
||||
seq_puts(s, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||
seq_puts(s, "<PerfData>");
|
||||
seq_printf(s, "<tcm_ready>%llu</tcm_ready>\n", perf->tcm_ready);
|
||||
seq_printf(s, "<sched_start>%llu</sched_start>\n", perf->sched_start);
|
||||
seq_printf(s, "<signaled_ready>%llu</signaled_ready>\n", perf->ready_time);
|
||||
|
||||
/*
|
||||
* dCache-misses Perf Data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_DCACHE_MISSES];
|
||||
seq_puts(s, "<dcache-misses>\n");
|
||||
dbg_dce_perf_stats_pm_event_xml(s, pm_evt);
|
||||
seq_puts(s, "</dcache-misses>\n");
|
||||
|
||||
/*
|
||||
* instruction execution Perf Data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_INSTR_EXEC];
|
||||
seq_puts(s, "<instr-execution>\n");
|
||||
dbg_dce_perf_stats_pm_event_xml(s, pm_evt);
|
||||
seq_puts(s, "</instr-execution>\n");
|
||||
|
||||
/*
|
||||
* instruction execution Perf Data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_MEM_REQ];
|
||||
seq_puts(s, "<mmio-request>\n");
|
||||
dbg_dce_perf_stats_pm_event_xml(s, pm_evt);
|
||||
seq_puts(s, "</mmio-request>\n");
|
||||
|
||||
/*
|
||||
* Print Scheduler Perf data and Per task data
|
||||
*/
|
||||
seq_puts(s, "<sched>\n");
|
||||
seq_printf(s, "<start>%llu</start><end>%llu</end>", sched->start, sched->end);
|
||||
seq_printf(s, "<context_switches>%llu</context_switches>\n", sched->context_switches);
|
||||
|
||||
for (i = 0U; i < DCE_ADMIN_PERF_ACTIVE_TASKS_NUM; i += 1U) {
|
||||
dbg_dce_perf_stats_sched_task_xml(s, d,
|
||||
&sched->tasks[i]);
|
||||
}
|
||||
|
||||
seq_puts(s, "</sched>"); //sched perf data done
|
||||
seq_puts(s, "</PerfData>\n");
|
||||
}
|
||||
|
||||
|
||||
static void dbg_dce_perf_stats_sched_task_csv(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_task_stats *task_stat)
|
||||
{
|
||||
/* Don't print if task_name is not set */
|
||||
if (task_stat->name == NULL)
|
||||
return;
|
||||
|
||||
seq_printf(s, "\"%s\",\"%llu\",\"%llu\",\"%llu\",\"%llu\",\"%llu\",\"%llu\",\"sleep\",\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
task_stat->name, task_stat->init, task_stat->ready,
|
||||
task_stat->ready_time, task_stat->dcache_misses,
|
||||
task_stat->inst_exec, task_stat->mmio_req,
|
||||
task_stat->sleep.accumulate,
|
||||
task_stat->sleep.iterations, task_stat->sleep.min,
|
||||
task_stat->sleep.max);
|
||||
seq_puts(s, "\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"run\",");
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
task_stat->run.accumulate, task_stat->run.iterations,
|
||||
task_stat->run.min, task_stat->run.max);
|
||||
seq_puts(s, "\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"run-context\",");
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
task_stat->run_context.accumulate,
|
||||
task_stat->run_context.iterations,
|
||||
task_stat->run_context.min,
|
||||
task_stat->run_context.max);
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_show_csv(struct seq_file *s, struct tegra_dce *d,
|
||||
struct dce_admin_perf_info *perf)
|
||||
{
|
||||
const struct dce_admin_pm_event_stats *pm_evt;
|
||||
const struct dce_admin_sched_stats *sched = &perf->sched;
|
||||
uint32_t i;
|
||||
|
||||
seq_puts(s, "\"tcm-ready\",\"sched-start\",\"signaled-ready\",");
|
||||
seq_puts(s, "\"dcache:start-time\",\"dcache:end-time\",\"dcache:miss_cnt\",");
|
||||
seq_puts(s, "\"inst_exec:start-time\",\"inst_exec:end-time\",\"inst_exec:count\",");
|
||||
seq_puts(s, "\"mmio_req:start-time\",\"mmio_req:end-time\",\"mmio_req:count\",");
|
||||
seq_puts(s, "\"sched:start-time\",\"sched:end-time\",\"sched:context_switches\"\n");
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",", perf->tcm_ready,
|
||||
perf->sched_start, perf->ready_time);
|
||||
|
||||
/*
|
||||
* Print Cache Perf data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_DCACHE_MISSES];
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",",
|
||||
pm_evt->start, pm_evt->end, pm_evt->count);
|
||||
|
||||
/*
|
||||
* Print Instruction exec Perf data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_INSTR_EXEC];
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",",
|
||||
pm_evt->start, pm_evt->end, pm_evt->count);
|
||||
|
||||
/*
|
||||
* Print Instruction exec Perf data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_MEM_REQ];
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",",
|
||||
pm_evt->start, pm_evt->end, pm_evt->count);
|
||||
/*
|
||||
* Print Scheduler Perf data and Per task data
|
||||
*/
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
sched->start, sched->end,
|
||||
sched->context_switches);
|
||||
|
||||
seq_puts(s, "\"sched:task_name\",\"sched:task-init\",\"sched:task-ready\",");
|
||||
seq_puts(s, "\"sched:task-ready-time\",\"sched:task-stat:dcache-misses\",");
|
||||
seq_puts(s, "\"sched:task-stat:instr_exec\",\"sched:task-stat:mem_req\",");
|
||||
seq_puts(s, "\"sched:task-stat:name\",");
|
||||
seq_puts(s, "\"sched:task-stat:accumulate\",\"sched:task-stat:iterations\",");
|
||||
seq_puts(s, "\"sched:task-stat:min\",\"sched:task-stat:max\"\n");
|
||||
for (i = 0U; i < DCE_ADMIN_PERF_ACTIVE_TASKS_NUM; i += 1U) {
|
||||
dbg_dce_perf_stats_sched_task_csv(s, d,
|
||||
&sched->tasks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int dbg_dce_perf_stats_stats_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct dce_admin_perf_info *perf;
|
||||
struct tegra_dce *d = (struct tegra_dce *)s->private;
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_cmd_get_perf_stat(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Get perf stat\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
perf = &resp_msg->args.perf.info.sched_stats;
|
||||
|
||||
if (perf_output_format == DCE_PERF_OUTPUT_FORMAT_CSV)
|
||||
dbg_dce_perf_stats_show_csv(s, d, perf);
|
||||
else
|
||||
dbg_dce_perf_stats_show_xml(s, d, perf);
|
||||
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_stats_stats_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_stats_stats_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugfs nodes for displaying a help message about perf stats capture
|
||||
*/
|
||||
static int dbg_dce_perf_stats_help_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
/**
|
||||
* Writing
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/stats/stats
|
||||
* - Clear the Perf stats data
|
||||
* '1' to /sys/kernel/debug/tegra_dce/perf/stats/stats
|
||||
* - Start the Perf stats data
|
||||
* To capture fresh Perf stats, first clear and Start.
|
||||
*
|
||||
* The result can be printed in csv or xml format
|
||||
*
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in CSV format
|
||||
* '1' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in XML format
|
||||
* Default is set for CSV
|
||||
*
|
||||
* cat /sys/kernel/debug/tegra_dce/perf/stats/stats
|
||||
* - get the perf data in selected format
|
||||
*
|
||||
*/
|
||||
seq_printf(s, "DCE Perf Capture\n"
|
||||
"----------------------\n"
|
||||
" echo '0' > perf/stats/stats : Clear perf data\n"
|
||||
" cat perf/stats/stats : get perf data in selected format\n"
|
||||
" echo <0/1> > perf/format : get data in CSV/XML format\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_stats_help_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_stats_help_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
ssize_t dbg_dce_perf_format_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 format;
|
||||
struct tegra_dce *d = ((struct seq_file *)file->private_data)->private;
|
||||
|
||||
ret = kstrtou32_from_user(user_buf, count, 10, &format);
|
||||
if (ret) {
|
||||
dce_err(d, "Invalid format!");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (format == DCE_PERF_OUTPUT_FORMAT_CSV)
|
||||
perf_output_format = DCE_PERF_OUTPUT_FORMAT_CSV;
|
||||
else if (format == DCE_PERF_OUTPUT_FORMAT_XML)
|
||||
perf_output_format = DCE_PERF_OUTPUT_FORMAT_XML;
|
||||
else
|
||||
dce_err(d, "Invalid format [%u]!", format);
|
||||
|
||||
done:
|
||||
return count;
|
||||
}
|
||||
|
||||
static int dbg_dce_perf_format_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
seq_printf(s, "Supported Formats\n"
|
||||
"----------------------\n"
|
||||
"CSV:0 XML:1\n"
|
||||
"Current format:%s\n",
|
||||
(perf_output_format == DCE_PERF_OUTPUT_FORMAT_CSV) ? "CSV" : "XML");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_format_fops_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_format_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugfs nodes for displaying a help message about perf stats capture
|
||||
*/
|
||||
static int dbg_dce_perf_events_help_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
/**
|
||||
* Writing
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/events/events
|
||||
* - Clear the Perf Events data
|
||||
* 'Bit masked value' to /kernel/debug/tegra_dce/perf/events/events
|
||||
* - Enable an event for the Perf Events data capture.
|
||||
* Clear bit mask if the event perf is not needed to be captured.
|
||||
*
|
||||
* The result can be printed in csv or xml format
|
||||
*
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in CSV format
|
||||
* '1' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in XML format
|
||||
* Default is set for CSV
|
||||
*
|
||||
* cat /sys/kernel/debug/tegra_dce/perf/events/events
|
||||
* - get the perf event data in selected format
|
||||
* - shows event name/ accumulated time/ iterations happened
|
||||
* - min and max time taken to run an event iteration
|
||||
*/
|
||||
seq_printf(s, "DCE Perf Events Capture\n"
|
||||
"----------------------\n"
|
||||
" echo '0' > perf/events/events: Clear perf events data\n"
|
||||
" echo 'bit masked value' > perf/events/events: Enable perf event capture\n"
|
||||
" cat perf/events/events: get perf events data in selected format\n"
|
||||
" echo <0/1> > perf/format: get data in CSV/XML format\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_events_help_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_events_help_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
ssize_t dbg_dce_perf_events_events_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t events;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct tegra_dce *d = ((struct seq_file *)file->private_data)->private;
|
||||
|
||||
/*
|
||||
* Writing "0/n" will clear the events
|
||||
* Write Bit Masked value to enable events
|
||||
*/
|
||||
ret = kstrtou32_from_user(user_buf, count, 0, &events);
|
||||
if (ret) {
|
||||
dce_err(d, "Unable to parse for event perf stats");
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
|
||||
if (events == 0x0U) {
|
||||
// Clear event
|
||||
req_msg->args.perf.event_cmd.clear = DCE_ADMIN_EVENT_CLEAR_CLEAR;
|
||||
} else {
|
||||
// Disable all Events if enable : 0x80000000
|
||||
// Elase enable only Bit masked events
|
||||
req_msg->args.perf.event_cmd.clear = DCE_ADMIN_EVENT_CLEAR_RETAIN;
|
||||
req_msg->args.perf.event_cmd.enable = events;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_cmd_clear_perf_events(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Clear perf events\n");
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_events_show_csv(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_event_info *events)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
seq_puts(s, "\"Evt Name\",\"accumulate\",\"iterations\",\"min\",\"max\"\n");
|
||||
|
||||
for (i = 0; i < DCE_ADMIN_NUM_EVENTS; i++) {
|
||||
if (events->events[i].name == NULL)
|
||||
continue;
|
||||
|
||||
seq_printf(s, "\"%s\",\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
events->events[i].name, events->events[i].event.accumulate,
|
||||
events->events[i].event.iterations, events->events[i].event.min,
|
||||
events->events[i].event.max);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_events_show_xml(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_event_info *events)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
seq_puts(s, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||
seq_puts(s, "<EventsPerfData>");
|
||||
|
||||
for (i = 0; i < DCE_ADMIN_NUM_EVENTS; i++) {
|
||||
if (events->events[i].name == NULL)
|
||||
continue;
|
||||
|
||||
seq_printf(s, "<name>%s</name>\n", events->events[i].name);
|
||||
seq_printf(s, "<accumulate>%llu</accumulate>\n",
|
||||
events->events[i].event.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations>\n",
|
||||
events->events[i].event.iterations);
|
||||
seq_printf(s, "<min>%llu</min>\n", events->events[i].event.min);
|
||||
seq_printf(s, "<max>%llu</max>\n", events->events[i].event.max);
|
||||
}
|
||||
|
||||
seq_puts(s, "</EventsPerfData>\n");
|
||||
}
|
||||
|
||||
static int dbg_dce_perf_events_events_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct dce_admin_event_info *events;
|
||||
struct tegra_dce *d = (struct tegra_dce *)s->private;
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_cmd_get_perf_events(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Get perf stat\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
events = &resp_msg->args.perf.info.events_stats;
|
||||
|
||||
if (perf_output_format == DCE_PERF_OUTPUT_FORMAT_CSV)
|
||||
dbg_dce_perf_events_show_csv(s, d, events);
|
||||
else
|
||||
dbg_dce_perf_events_show_xml(s, d, events);
|
||||
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_events_events_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_events_events_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <dce.h>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <dce-debug-perf.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-core-interface-errors.h>
|
||||
|
||||
@@ -612,6 +614,44 @@ static const struct file_operations boot_status_fops = {
|
||||
.read = dbg_dce_boot_status_fops_read,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_format_fops = {
|
||||
.open = dbg_dce_perf_format_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.write = dbg_dce_perf_format_fops_write,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_stats_stats_fops = {
|
||||
.open = dbg_dce_perf_stats_stats_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.write = dbg_dce_perf_stats_stats_fops_write,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_stats_help_fops = {
|
||||
.open = dbg_dce_perf_stats_help_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_events_events_fops = {
|
||||
.open = dbg_dce_perf_events_events_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.write = dbg_dce_perf_events_events_fops_write,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_events_help_fops = {
|
||||
.open = dbg_dce_perf_events_help_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void dce_remove_debug(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
@@ -699,6 +739,7 @@ void dce_init_debug(struct tegra_dce *d)
|
||||
struct device *dev = dev_from_dce(d);
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
struct dentry *debugfs_dir = NULL;
|
||||
struct dentry *perf_debugfs_dir = NULL;
|
||||
|
||||
d_dev->debugfs = debugfs_create_dir("tegra_dce", NULL);
|
||||
if (!d_dev->debugfs)
|
||||
@@ -734,6 +775,43 @@ void dce_init_debug(struct tegra_dce *d)
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
perf_debugfs_dir = debugfs_create_dir("perf", d_dev->debugfs);
|
||||
if (!perf_debugfs_dir)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("format", 0644,
|
||||
perf_debugfs_dir, d, &perf_format_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
debugfs_dir = debugfs_create_dir("stats", perf_debugfs_dir);
|
||||
if (!debugfs_dir)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("stats", 0644,
|
||||
debugfs_dir, d, &perf_stats_stats_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("help", 0444,
|
||||
debugfs_dir, d, &perf_stats_help_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
debugfs_dir = debugfs_create_dir("events", perf_debugfs_dir);
|
||||
if (!debugfs_dir)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("events", 0644,
|
||||
debugfs_dir, d, &perf_events_events_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("help", 0444,
|
||||
debugfs_dir, d, &perf_events_help_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("dump_hsp_regs", 0444,
|
||||
d_dev->debugfs, d, &dump_hsp_regs_fops);
|
||||
if (!retval)
|
||||
|
||||
42
drivers/platform/tegra/dce/include/dce-debug-perf.h
Normal file
42
drivers/platform/tegra/dce/include/dce-debug-perf.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef DCE_DEBUG_PERF_H
|
||||
#define DCE_DEBUG_PERF_H
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
int dbg_dce_perf_stats_stats_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
ssize_t dbg_dce_perf_stats_stats_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
|
||||
int dbg_dce_perf_stats_help_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
|
||||
ssize_t dbg_dce_perf_format_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
int dbg_dce_perf_format_fops_open(struct inode *inode, struct file *file);
|
||||
|
||||
int dbg_dce_perf_events_events_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
ssize_t dbg_dce_perf_events_events_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
int dbg_dce_perf_events_help_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -34,7 +35,7 @@
|
||||
#define DCE_DISPRM_CMD_MAX_FSIZE 4096U
|
||||
#define DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_NFRAMES 4U
|
||||
#define DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_FSIZE 4096U
|
||||
#define DCE_ADMIN_CMD_MAX_FSIZE 1024U
|
||||
#define DCE_ADMIN_CMD_MAX_FSIZE 2048U
|
||||
|
||||
#define DCE_IPC_WAIT_TYPE_INVALID 0U
|
||||
#define DCE_IPC_WAIT_TYPE_RPC 1U
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -425,6 +426,17 @@ int dce_admin_send_enter_sc7(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_handle_ipc_requested_event(struct tegra_dce *d, void *params);
|
||||
int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params);
|
||||
int dce_admin_send_cmd_get_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_cmd_set_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg,
|
||||
bool start_perf);
|
||||
int dce_admin_send_cmd_stop_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_cmd_get_perf_events(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_cmd_clear_perf_events(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type);
|
||||
void dce_admin_ipc_handle_signal(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2018-2023 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
@@ -24,6 +25,7 @@
|
||||
#define DCE_ADMIN_CMDS_H
|
||||
|
||||
#include <interface/dce-types.h>
|
||||
#include <interface/dce-admin-perf-stats.h>
|
||||
|
||||
/*
|
||||
* Version of the ADMIN command interface.
|
||||
@@ -34,7 +36,7 @@
|
||||
* To keep things simple, this value should be incremented by 1 each
|
||||
* time changes are made.
|
||||
*/
|
||||
#define DCE_ADMIN_VERSION 2
|
||||
#define DCE_ADMIN_VERSION 3
|
||||
|
||||
#define DCE_ADMIN_CMD_SIZE sizeof(struct dce_admin_ipc_cmd)
|
||||
#define DCE_ADMIN_RESP_SIZE sizeof(struct dce_admin_ipc_resp)
|
||||
@@ -58,20 +60,22 @@
|
||||
#define DCE_ADMIN_CMD_GET_LOG_INFO 0x0BU // get current log info
|
||||
#define DCE_ADMIN_CMD_LOCK_CHANGES 0x0CU // lock creating new channels
|
||||
// and changing memory areas
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_START 0x0DU // start collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_STOP 0x0EU // stop collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_START 0x0DU // start collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_STOP 0x0EU // stop collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_PERF_START 0x0FU // start collecting perf data
|
||||
#define DCE_ADMIN_CMD_PERF_STOP 0x10U // stop collecting perf data
|
||||
#define DCE_ADMIN_CMD_INT_TEST_START 0x11U // start internal tests
|
||||
#define DCE_ADMIN_CMD_INT_TEST_STOP 0x12U // stop internal tests and return status
|
||||
#define DCE_ADMIN_CMD_EXT_TEST 0x13U // run external test (blocking call)
|
||||
#define DCE_ADMIN_CMD_INT_TEST_START 0x11U // start internal tests
|
||||
#define DCE_ADMIN_CMD_INT_TEST_STOP 0x12U // stop internal tests and return status
|
||||
#define DCE_ADMIN_CMD_EXT_TEST 0x13U // run external test (blocking call)
|
||||
#define DCE_ADMIN_CMD_DEBUG 0x14U // debug command
|
||||
|
||||
#define DCE_ADMIN_CMD_RM_BOOTSTRAP 0x15U // tell RM to "bootstrap"
|
||||
#define DCE_ADMIN_CMD_PERF_RESULTS 0x16U // copy out the perf results
|
||||
#define DCE_ADMIN_CMD_PERF_GET_EVENTS 0x17U // get perf events
|
||||
#define DCE_ADMIN_CMD_PERF_CLEAR_EVENTS 0x18U // clear perf events
|
||||
|
||||
#define DCE_ADMIN_CMD_NEXT 0x16U // must be last command ID + 1
|
||||
#define DCE_ADMIN_CMD_NEXT 0x19U // must be last command ID + 1
|
||||
|
||||
struct dce_admin_version_info {
|
||||
uint32_t version;
|
||||
@@ -159,6 +163,7 @@ struct dce_admin_ipc_cmd {
|
||||
struct dce_admin_ipc_info_args ipc_info;
|
||||
struct dce_admin_mem_args mem_map;
|
||||
struct dce_admin_ipc_create_args ipc_create;
|
||||
struct dce_admin_perf_args perf;
|
||||
} args;
|
||||
};
|
||||
|
||||
@@ -166,11 +171,12 @@ struct dce_admin_ipc_resp {
|
||||
uint32_t error;
|
||||
union {
|
||||
struct dce_admin_version_info version;
|
||||
struct dce_admin_echo echo;
|
||||
struct dce_admin_log_args log;
|
||||
struct dce_admin_ipc_info ipc;
|
||||
struct dce_admin_mem_args mem_info;
|
||||
struct dce_admin_echo echo;
|
||||
struct dce_admin_log_args log;
|
||||
struct dce_admin_ipc_info ipc;
|
||||
struct dce_admin_mem_args mem_info;
|
||||
struct dce_admin_fw_version_info fw_version;
|
||||
struct dce_admin_perf_stats_info perf;
|
||||
} args;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_ADMIN_PERF_STATS_H
|
||||
#define DCE_ADMIN_PERF_STATS_H
|
||||
|
||||
/*
|
||||
* Values for stats field
|
||||
*/
|
||||
#define DCE_ADMIN_PERF_STATS_SCHED 0x0001
|
||||
#define DCE_ADMIN_PERF_STATS_CACHE 0x0002
|
||||
#define DCE_ADMIN_PERF_STATS_IEXEC 0x0003
|
||||
#define DCE_ADMIN_PERF_STATS_MMIO 0x0004
|
||||
#define DCE_ADMIN_PERF_STATS_ALL 0xFFFF
|
||||
|
||||
/*
|
||||
* Values for clear field
|
||||
*/
|
||||
#define DCE_ADMIN_PERF_CLEAR_RETAIN 0U
|
||||
#define DCE_ADMIN_PERF_CLEAR_CLEAR 1U
|
||||
|
||||
#define DCE_ADMIN_EVENT_CLEAR_RETAIN 0U
|
||||
#define DCE_ADMIN_EVENT_CLEAR_CLEAR 1U
|
||||
|
||||
struct dce_admin_perf_cmd_args {
|
||||
uint32_t enable; // Enable stats capture through Bit-Mask
|
||||
uint32_t clear; // Clear all event stats
|
||||
};
|
||||
|
||||
struct dce_admin_perf_args {
|
||||
struct dce_admin_perf_cmd_args perf_cmd;
|
||||
struct dce_admin_perf_cmd_args event_cmd;
|
||||
};
|
||||
|
||||
/*
|
||||
* Task related defines for perf stats
|
||||
*/
|
||||
#define DCE_ADMIN_PERF_ADMIN_TASK 0U
|
||||
#define DCE_ADMIN_PERF_RM_TASK 1U
|
||||
#define DCE_ADMIN_PERF_PRINT_TASK 2U
|
||||
#define DCE_ADMIN_PERF_TCU_TASK 3U
|
||||
#define DCE_ADMIN_PERF_IDLE_TASK 4U
|
||||
// Change the active task number on adding more tasks
|
||||
#define DCE_ADMIN_PERF_ACTIVE_TASKS_NUM 5U
|
||||
// Max number of tasks in perf stats capture
|
||||
#define DCE_ADMIN_PERF_NUM_TASKS 10U
|
||||
// Task name length
|
||||
#define DCE_ADMIN_TASK_NAME_LEN 16U
|
||||
|
||||
struct dce_admin_stat_avg {
|
||||
uint64_t accumulate; // accumulated delta times
|
||||
uint64_t iterations;
|
||||
uint64_t min;
|
||||
uint64_t max;
|
||||
};
|
||||
|
||||
struct dce_admin_task_stats {
|
||||
const char name[DCE_ADMIN_TASK_NAME_LEN]; // task name
|
||||
uint64_t init; // how long to run init code
|
||||
uint64_t ready; // how long for task to be ready
|
||||
uint64_t ready_time; // time when task became ready
|
||||
uint64_t dcache_misses; // dcaches missed count accumulated within this task
|
||||
uint64_t inst_exec; // instruction execution accumulated
|
||||
uint64_t mmio_req; // memory request accumulated
|
||||
struct dce_admin_stat_avg sleep;
|
||||
struct dce_admin_stat_avg run;
|
||||
struct dce_admin_stat_avg run_context; // running context
|
||||
};
|
||||
|
||||
struct dce_admin_sched_stats {
|
||||
uint64_t start; // time collection started
|
||||
uint64_t end; // time collection stopped
|
||||
uint64_t context_switches; // overall context switches
|
||||
struct dce_admin_task_stats tasks[DCE_ADMIN_PERF_NUM_TASKS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Performance monitor events and counters
|
||||
*/
|
||||
#define DCE_ADMIN_PM_EVT_DCACHE_MISSES 0U
|
||||
#define DCE_ADMIN_PM_EVT_INSTR_EXEC 1U
|
||||
#define DCE_ADMIN_PM_EVT_MEM_REQ 2U
|
||||
#define DCE_ADMIN_PM_EVT_COUNTERS 3U
|
||||
|
||||
struct dce_admin_pm_event_stats {
|
||||
uint64_t start; // time collection started
|
||||
uint64_t end; // time collection stopped
|
||||
uint64_t count; // Event counter accumulated
|
||||
};
|
||||
|
||||
struct dce_admin_perf_info {
|
||||
uint64_t tcm_ready; // tcm is ready/copied
|
||||
uint64_t sched_start; // scheduler started
|
||||
uint64_t ready_time; // signaled ready
|
||||
struct dce_admin_pm_event_stats pm_events[DCE_ADMIN_PM_EVT_COUNTERS];
|
||||
struct dce_admin_sched_stats sched;
|
||||
};
|
||||
|
||||
#define DCE_ADMIN_EVENT_NAME_LEN 32U // max length of an event name
|
||||
#define DCE_ADMIN_NUM_EVENTS 20U // s.b. same as DCE_NUM_EVENTS
|
||||
|
||||
struct dce_admin_event {
|
||||
char name[DCE_ADMIN_EVENT_NAME_LEN];
|
||||
struct dce_admin_stat_avg event;
|
||||
};
|
||||
|
||||
struct dce_admin_event_info {
|
||||
struct dce_admin_event events[DCE_ADMIN_NUM_EVENTS];
|
||||
};
|
||||
|
||||
|
||||
struct dce_admin_perf_stats_info {
|
||||
union {
|
||||
struct dce_admin_perf_info sched_stats;
|
||||
struct dce_admin_event_info events_stats;
|
||||
} info;
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user