Commit 74664981 authored by Lucas Stach's avatar Lucas Stach Committed by Ezequiel Garcia
Browse files

drm/sched: add sysfs stats output



This adds a sysfs entry for the drm scheduler and exports the active times
of all scheduler instances.
Signed-off-by: Lucas Stach's avatarLucas Stach <l.stach@pengutronix.de>
parent dcaac549
......@@ -20,6 +20,6 @@
# OTHER DEALINGS IN THE SOFTWARE.
#
#
gpu-sched-y := sched_main.o sched_fence.o sched_entity.o
gpu-sched-y := sched_main.o sched_fence.o sched_entity.o sched_stats.o
obj-$(CONFIG_DRM_SCHED) += gpu-sched.o
......@@ -29,6 +29,8 @@
#include <drm/gpu_scheduler.h>
#include "sched_stats.h"
static struct kmem_cache *sched_fence_slab;
static int __init drm_sched_fence_slab_init(void)
......@@ -42,7 +44,7 @@ static int __init drm_sched_fence_slab_init(void)
return 0;
}
static void __exit drm_sched_fence_slab_fini(void)
static void drm_sched_fence_slab_fini(void)
{
rcu_barrier();
kmem_cache_destroy(sched_fence_slab);
......@@ -175,8 +177,29 @@ struct drm_sched_fence *drm_sched_fence_create(struct drm_sched_entity *entity,
return fence;
}
module_init(drm_sched_fence_slab_init);
module_exit(drm_sched_fence_slab_fini);
static int __init drm_sched_modinit(void)
{
int ret;
ret = drm_sched_fence_slab_init();
if (ret)
return ret;
ret = drm_sched_stats_class_init();
if (ret)
drm_sched_fence_slab_fini();
return ret;
}
static void __exit drm_sched_modexit(void)
{
drm_sched_stats_class_fini();
drm_sched_fence_slab_fini();
}
module_init(drm_sched_modinit);
module_exit(drm_sched_modexit);
MODULE_DESCRIPTION("DRM GPU scheduler");
MODULE_LICENSE("GPL and additional rights");
......@@ -57,6 +57,8 @@
#define CREATE_TRACE_POINTS
#include "gpu_scheduler_trace.h"
#include "sched_stats.h"
#define to_drm_sched_job(sched_job) \
container_of((sched_job), struct drm_sched_job, queue_node)
......@@ -819,12 +821,17 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
atomic_set(&sched->num_jobs, 0);
atomic64_set(&sched->job_id_count, 0);
ret = drm_sched_stats_init(sched);
if (ret)
return ret;
/* Each scheduler will run on a seperate kernel thread */
sched->thread = kthread_run(drm_sched_main, sched, sched->name);
if (IS_ERR(sched->thread)) {
ret = PTR_ERR(sched->thread);
sched->thread = NULL;
DRM_ERROR("Failed to create scheduler for %s.\n", name);
drm_sched_stats_fini(sched);
return ret;
}
......@@ -842,6 +849,8 @@ EXPORT_SYMBOL(drm_sched_init);
*/
void drm_sched_fini(struct drm_gpu_scheduler *sched)
{
drm_sched_stats_fini(sched);
if (sched->thread)
kthread_stop(sched->thread);
......
/*
* Copyright 2018 Pengutronix
*
* 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
*
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <drm/drm_sysfs.h>
#include <drm/gpu_scheduler.h>
#include "sched_stats.h"
struct drm_sched_stats_engines {
struct kobject kobj;
};
static struct device_type drm_sched_class_type = {
.name = "scheduler",
};
static struct device drm_sched_class_device = {
.type = &drm_sched_class_type,
};
static void drm_sched_stats_rings_kobj_release(struct kobject *kobj)
{
struct drm_sched_stats_engines *engines =
container_of(kobj, struct drm_sched_stats_engines, kobj);
kfree(engines);
}
static struct kobj_type drm_sched_rings_class_type = {
.release = &drm_sched_stats_rings_kobj_release,
};
static struct drm_sched_stats_engines *rings;
static struct attribute drm_sched_stats_active = {
.name = "active_us",
.mode = S_IRUGO
};
static void drm_sched_stats_kobj_release(struct kobject *kobj)
{
struct drm_gpu_scheduler_stats *stats =
container_of(kobj, struct drm_gpu_scheduler_stats, kobj);
kfree(stats);
}
static ssize_t drm_sched_stats_show(struct kobject *kobj,
struct attribute *attr,
char *buffer)
{
struct drm_gpu_scheduler_stats *stats =
container_of(kobj, struct drm_gpu_scheduler_stats, kobj);
uint64_t val = 0;
spin_lock_irq(&stats->lock);
val = stats->active_time_us;
if (stats->active)
val += ktime_to_us(ktime_sub(ktime_get(), stats->active_ts));
spin_unlock_irq(&stats->lock);
return snprintf(buffer, PAGE_SIZE, "%llu\n", val);
}
static struct attribute *drm_sched_stats_attrs[] = {
&drm_sched_stats_active,
NULL
};
static const struct sysfs_ops drm_sched_stats_ops = {
.show = &drm_sched_stats_show,
};
static struct kobj_type drm_sched_stats_kobj_type = {
.release = drm_sched_stats_kobj_release,
.sysfs_ops = &drm_sched_stats_ops,
.default_attrs = drm_sched_stats_attrs,
};
int drm_sched_stats_init(struct drm_gpu_scheduler *sched)
{
int ret;
sched->stats = kzalloc(sizeof(*sched->stats), GFP_KERNEL);
if (!sched->stats)
return -ENOMEM;
spin_lock_init(&sched->stats->lock);
ret = kobject_init_and_add(&sched->stats->kobj,
&drm_sched_stats_kobj_type,
&rings->kobj, "%s", sched->name);
if (ret) {
pr_warn("could not inititialize stats for drm scheduler %s\n",
sched->name);
kfree(sched->stats);
sched->stats = NULL;
}
return 0;
}
void drm_sched_stats_fini(struct drm_gpu_scheduler *sched)
{
if (!sched->stats)
return;
kobject_put(&sched->stats->kobj);
sched->stats = NULL;
}
int __init drm_sched_stats_class_init(void)
{
int ret;
ret = dev_set_name(&drm_sched_class_device, "scheduler");
if (ret)
return ret;
ret = drm_class_device_register(&drm_sched_class_device);
if (ret)
return ret;
rings = kzalloc(sizeof(*rings), GFP_KERNEL);
if (!rings) {
ret = -ENOMEM;
goto unregister_device;
}
ret = kobject_init_and_add(&rings->kobj,
&drm_sched_rings_class_type,
&drm_sched_class_device.kobj,
"%s", "rings");
if (ret) {
kobject_put(&rings->kobj);
goto unregister_device;
}
return 0;
unregister_device:
drm_class_device_unregister(&drm_sched_class_device);
return ret;
}
void __exit drm_sched_stats_class_fini(void)
{
drm_class_device_unregister(&drm_sched_class_device);
}
/*
* Copyright 2018 Pengutronix
*
* 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _DRM_SCHED_STATS_H_
#define _DRM_SCHED_STATS_H_
#include <linux/init.h>
#include <drm/gpu_scheduler.h>
int drm_sched_stats_init(struct drm_gpu_scheduler *sched);
void drm_sched_stats_fini(struct drm_gpu_scheduler *sched);
int __init drm_sched_stats_class_init(void);
void __exit drm_sched_stats_class_fini(void);
#endif
......@@ -26,6 +26,7 @@
#include <drm/spsc_queue.h>
#include <linux/dma-fence.h>
#include <linux/kobject.h>
#define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000)
......@@ -237,6 +238,16 @@ struct drm_sched_backend_ops {
void (*free_job)(struct drm_sched_job *sched_job);
};
struct drm_gpu_scheduler;
struct drm_gpu_scheduler_stats {
struct kobject kobj;
spinlock_t lock;
uint64_t active_time_us;
ktime_t active_ts;
bool active;
};
/**
* struct drm_gpu_scheduler
*
......@@ -283,6 +294,7 @@ struct drm_gpu_scheduler {
atomic_t num_jobs;
bool ready;
bool free_guilty;
struct drm_gpu_scheduler_stats *stats;
};
int drm_sched_init(struct drm_gpu_scheduler *sched,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment