Skip to content

Commit

Permalink
BACKPORT: accel/ivpu: Share NPU busy time in sysfs
Browse files Browse the repository at this point in the history
The driver tracks the time spent by NPU executing jobs
and shares it through sysfs `npu_busy_time_us` file.
It can be then used by user space applications to monitor device
utilization.

NPU is considered 'busy' starting with a first job submitted
to firmware and ending when there is no more jobs pending/executing.

Tracked-On: OAM-128674
Signed-off-by: Tomasz Rusinowicz <[email protected]>
Signed-off-by: Jacek Lawrynowicz <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/drivers/accel/ivpu?id=0adff3b0ef12483a79dc8415b94547853d26d1f3
Signed-off-by: Zhao, Shirley <[email protected]>
  • Loading branch information
xyzhao2018 committed Dec 20, 2024
1 parent 7735521 commit d8cf81e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 2 deletions.
3 changes: 2 additions & 1 deletion drivers/accel/ivpu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ intel_vpu-y := \
ivpu_jsm_msg.o \
ivpu_mmu.o \
ivpu_mmu_context.o \
ivpu_pm.o
ivpu_pm.o \
ivpu_sysfs.o

obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o
3 changes: 3 additions & 0 deletions drivers/accel/ivpu/ivpu_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "ivpu_mmu.h"
#include "ivpu_mmu_context.h"
#include "ivpu_pm.h"
#include "ivpu_sysfs.h"

#ifndef DRIVER_VERSION_STR
#define DRIVER_VERSION_STR __stringify(DRM_IVPU_DRIVER_MAJOR) "." \
Expand Down Expand Up @@ -661,6 +662,8 @@ static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return ret;
}

ivpu_sysfs_init(vdev);

ret = drm_dev_register(&vdev->drm, 0);
if (ret) {
dev_err(&pdev->dev, "Failed to register DRM device: %d\n", ret);
Expand Down
3 changes: 3 additions & 0 deletions drivers/accel/ivpu/ivpu_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ struct ivpu_device {

atomic64_t unique_id_counter;

ktime_t busy_start_ts;
ktime_t busy_time;

struct {
int boot;
int jsm;
Expand Down
23 changes: 22 additions & 1 deletion drivers/accel/ivpu/ivpu_job.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,28 @@ ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
return NULL;
}

static struct ivpu_job *ivpu_job_remove_from_submitted_jobs(struct ivpu_device *vdev, u32 job_id)
{
struct ivpu_job *job;

xa_lock(&vdev->submitted_jobs_xa);
job = __xa_erase(&vdev->submitted_jobs_xa, job_id);

if (xa_empty(&vdev->submitted_jobs_xa) && job) {
vdev->busy_time = ktime_add(ktime_sub(ktime_get(), vdev->busy_start_ts),
vdev->busy_time);
}

xa_unlock(&vdev->submitted_jobs_xa);

return job;
}

static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)
{
struct ivpu_job *job;

job = xa_erase(&vdev->submitted_jobs_xa, job_id);
job = ivpu_job_remove_from_submitted_jobs(vdev, job_id);
if (!job)
return -ENOENT;

Expand Down Expand Up @@ -372,6 +389,7 @@ static int ivpu_direct_job_submission(struct ivpu_job *job)
struct ivpu_device *vdev = job->vdev;
struct xa_limit job_id_range;
struct ivpu_cmdq *cmdq;
bool is_first_job;
int ret;

mutex_lock(&file_priv->lock);
Expand All @@ -388,6 +406,7 @@ static int ivpu_direct_job_submission(struct ivpu_job *job)
job_id_range.max = job_id_range.min | JOB_ID_JOB_MASK;

job_get(job, &job);
is_first_job = xa_empty(&vdev->submitted_jobs_xa);
ret = xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL);
if (ret) {
ivpu_warn_ratelimited(vdev, "Failed to allocate job id: %d\n", ret);
Expand All @@ -408,6 +427,8 @@ static int ivpu_direct_job_submission(struct ivpu_job *job)
wmb(); /* Flush WC buffer for jobq header */
} else {
ivpu_cmdq_ring_db(vdev, cmdq);
if (is_first_job)
vdev->busy_start_ts = ktime_get();
}

mutex_unlock(&file_priv->lock);
Expand Down
58 changes: 58 additions & 0 deletions drivers/accel/ivpu/ivpu_sysfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2024 Intel Corporation
*/

#include <linux/device.h>
#include <linux/err.h>

#include "ivpu_hw.h"
#include "ivpu_sysfs.h"

/*
* npu_busy_time_us is the time that the device spent executing jobs.
* The time is counted when and only when there are jobs submitted to firmware.
*
* This time can be used to measure the utilization of NPU, either by calculating
* npu_busy_time_us difference between two timepoints (i.e. measuring the time
* that the NPU was active during some workload) or monitoring utilization percentage
* by reading npu_busy_time_us periodically.
*
* When reading the value periodically, it shouldn't be read too often as it may have
* an impact on job submission performance. Recommended period is 1 second.
*/
static ssize_t
npu_busy_time_us_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
ktime_t total, now = 0;

xa_lock(&vdev->submitted_jobs_xa);
total = vdev->busy_time;
if (!xa_empty(&vdev->submitted_jobs_xa))
now = ktime_sub(ktime_get(), vdev->busy_start_ts);
xa_unlock(&vdev->submitted_jobs_xa);

return sysfs_emit(buf, "%lld\n", ktime_to_us(ktime_add(total, now)));
}

static DEVICE_ATTR_RO(npu_busy_time_us);

static struct attribute *ivpu_dev_attrs[] = {
&dev_attr_npu_busy_time_us.attr,
NULL,
};

static struct attribute_group ivpu_dev_attr_group = {
.attrs = ivpu_dev_attrs,
};

void ivpu_sysfs_init(struct ivpu_device *vdev)
{
int ret;

ret = devm_device_add_group(vdev->drm.dev, &ivpu_dev_attr_group);
if (ret)
ivpu_warn(vdev, "Failed to add group to device, ret %d", ret);
}
13 changes: 13 additions & 0 deletions drivers/accel/ivpu/ivpu_sysfs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2024 Intel Corporation
*/

#ifndef __IVPU_SYSFS_H__
#define __IVPU_SYSFS_H__

#include "ivpu_drv.h"

void ivpu_sysfs_init(struct ivpu_device *vdev);

#endif /* __IVPU_SYSFS_H__ */

0 comments on commit d8cf81e

Please sign in to comment.