From: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
To: Intel-gfx@lists.freedesktop.org
Subject: [Intel-gfx] [PATCH 1/9] drm/i915: Expose list of clients in sysfs
Date: Mon, 14 Sep 2020 14:12:48 +0100 [thread overview]
Message-ID: <20200914131256.89465-2-tvrtko.ursulin@linux.intel.com> (raw)
In-Reply-To: <20200914131256.89465-1-tvrtko.ursulin@linux.intel.com>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Expose a list of clients with open file handles in sysfs.
This will be a basis for a top-like utility showing per-client and per-
engine GPU load.
Currently we only expose each client's pid and name under opaque numbered
directories in /sys/class/drm/card0/clients/.
For instance:
/sys/class/drm/card0/clients/3/name: Xorg
/sys/class/drm/card0/clients/3/pid: 5664
v2:
Chris Wilson:
* Enclose new members into dedicated structs.
* Protect against failed sysfs registration.
v3:
* sysfs_attr_init.
v4:
* Fix for internal clients.
v5:
* Use cyclic ida for client id. (Chris)
* Do not leak pid reference. (Chris)
* Tidy code with some locals.
v6:
* Use xa_alloc_cyclic to simplify locking. (Chris)
* No need to unregister individial sysfs files. (Chris)
* Rebase on top of fpriv kref.
* Track client closed status and reflect in sysfs.
v7:
* Make drm_client more standalone concept.
v8:
* Simplify sysfs show. (Chris)
* Always track name and pid.
v9:
* Fix cyclic id assignment.
v10:
* No need for a mutex around xa_alloc_cyclic.
* Refactor sysfs into own function.
* Unregister sysfs before freeing pid and name.
* Move clients setup into own function.
v11:
* Call clients init directly from driver init. (Chris)
v12:
* Rebased after i915_gem_release removal.
* Do not fail client add on id wrap. (Maciej)
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> # v11
---
drivers/gpu/drm/i915/Makefile | 5 +-
drivers/gpu/drm/i915/i915_drm_client.c | 179 +++++++++++++++++++++++++
drivers/gpu/drm/i915/i915_drm_client.h | 64 +++++++++
drivers/gpu/drm/i915/i915_drv.c | 4 +
drivers/gpu/drm/i915/i915_drv.h | 5 +
drivers/gpu/drm/i915/i915_gem.c | 23 +++-
drivers/gpu/drm/i915/i915_sysfs.c | 8 ++
7 files changed, 283 insertions(+), 5 deletions(-)
create mode 100644 drivers/gpu/drm/i915/i915_drm_client.c
create mode 100644 drivers/gpu/drm/i915/i915_drm_client.h
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index e5574e506a5c..250f004d92bb 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -34,8 +34,9 @@ subdir-ccflags-y += -I$(srctree)/$(src)
# Please keep these build lists sorted!
# core driver code
-i915-y += i915_drv.o \
- i915_config.o \
+i915-y += i915_config.o \
+ i915_drm_client.o \
+ i915_drv.o \
i915_irq.o \
i915_getparam.o \
i915_params.o \
diff --git a/drivers/gpu/drm/i915/i915_drm_client.c b/drivers/gpu/drm/i915/i915_drm_client.c
new file mode 100644
index 000000000000..137a5744f9c6
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_drm_client.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "i915_drm_client.h"
+#include "i915_gem.h"
+#include "i915_utils.h"
+
+void i915_drm_clients_init(struct i915_drm_clients *clients)
+{
+ clients->next_id = 0;
+ xa_init_flags(&clients->xarray, XA_FLAGS_ALLOC);
+}
+
+static ssize_t
+show_client_name(struct device *kdev, struct device_attribute *attr, char *buf)
+{
+ struct i915_drm_client *client =
+ container_of(attr, typeof(*client), attr.name);
+
+ return snprintf(buf, PAGE_SIZE,
+ READ_ONCE(client->closed) ? "<%s>" : "%s",
+ client->name);
+}
+
+static ssize_t
+show_client_pid(struct device *kdev, struct device_attribute *attr, char *buf)
+{
+ struct i915_drm_client *client =
+ container_of(attr, typeof(*client), attr.pid);
+
+ return snprintf(buf, PAGE_SIZE,
+ READ_ONCE(client->closed) ? "<%u>" : "%u",
+ pid_nr(client->pid));
+}
+
+static int
+__client_register_sysfs(struct i915_drm_client *client)
+{
+ const struct {
+ const char *name;
+ struct device_attribute *attr;
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+ } files[] = {
+ { "name", &client->attr.name, show_client_name },
+ { "pid", &client->attr.pid, show_client_pid },
+ };
+ unsigned int i;
+ char buf[16];
+ int ret;
+
+ ret = scnprintf(buf, sizeof(buf), "%u", client->id);
+ if (ret == sizeof(buf))
+ return -EINVAL;
+
+ client->root = kobject_create_and_add(buf, client->clients->root);
+ if (!client->root)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(files); i++) {
+ struct device_attribute *attr = files[i].attr;
+
+ sysfs_attr_init(&attr->attr);
+
+ attr->attr.name = files[i].name;
+ attr->attr.mode = 0444;
+ attr->show = files[i].show;
+
+ ret = sysfs_create_file(client->root, (struct attribute *)attr);
+ if (ret)
+ break;
+ }
+
+ if (ret)
+ kobject_put(client->root);
+
+ return ret;
+}
+
+static void __client_unregister_sysfs(struct i915_drm_client *client)
+{
+ kobject_put(fetch_and_zero(&client->root));
+}
+
+static int
+__i915_drm_client_register(struct i915_drm_client *client,
+ struct task_struct *task)
+{
+ struct i915_drm_clients *clients = client->clients;
+ char *name;
+ int ret;
+
+ name = kstrdup(task->comm, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ client->pid = get_task_pid(task, PIDTYPE_PID);
+ client->name = name;
+
+ if (!clients->root)
+ return 0; /* intel_fbdev_init registers a client before sysfs */
+
+ ret = __client_register_sysfs(client);
+ if (ret)
+ goto err_sysfs;
+
+ return 0;
+
+err_sysfs:
+ put_pid(client->pid);
+ kfree(client->name);
+
+ return ret;
+}
+
+static void
+__i915_drm_client_unregister(struct i915_drm_client *client)
+{
+ __client_unregister_sysfs(client);
+
+ put_pid(fetch_and_zero(&client->pid));
+ kfree(fetch_and_zero(&client->name));
+}
+
+struct i915_drm_client *
+i915_drm_client_add(struct i915_drm_clients *clients, struct task_struct *task)
+{
+ struct i915_drm_client *client;
+ int ret;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&client->kref);
+ client->clients = clients;
+
+ ret = xa_alloc_cyclic(&clients->xarray, &client->id, client,
+ xa_limit_32b, &clients->next_id, GFP_KERNEL);
+ if (ret < 0)
+ goto err_id;
+
+ ret = __i915_drm_client_register(client, task);
+ if (ret)
+ goto err_register;
+
+ return client;
+
+err_register:
+ xa_erase(&clients->xarray, client->id);
+err_id:
+ kfree(client);
+
+ return ERR_PTR(ret);
+}
+
+void __i915_drm_client_free(struct kref *kref)
+{
+ struct i915_drm_client *client =
+ container_of(kref, typeof(*client), kref);
+
+ __i915_drm_client_unregister(client);
+ xa_erase(&client->clients->xarray, client->id);
+ kfree_rcu(client, rcu);
+}
+
+void i915_drm_client_close(struct i915_drm_client *client)
+{
+ GEM_BUG_ON(READ_ONCE(client->closed));
+ WRITE_ONCE(client->closed, true);
+ i915_drm_client_put(client);
+}
diff --git a/drivers/gpu/drm/i915/i915_drm_client.h b/drivers/gpu/drm/i915/i915_drm_client.h
new file mode 100644
index 000000000000..af6998c74d4c
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_drm_client.h
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+
+#ifndef __I915_DRM_CLIENT_H__
+#define __I915_DRM_CLIENT_H__
+
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/kref.h>
+#include <linux/pid.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/xarray.h>
+
+struct i915_drm_clients {
+ struct xarray xarray;
+ u32 next_id;
+
+ struct kobject *root;
+};
+
+struct i915_drm_client {
+ struct kref kref;
+
+ struct rcu_head rcu;
+
+ unsigned int id;
+ struct pid *pid;
+ char *name;
+ bool closed;
+
+ struct i915_drm_clients *clients;
+
+ struct kobject *root;
+ struct {
+ struct device_attribute pid;
+ struct device_attribute name;
+ } attr;
+};
+
+void i915_drm_clients_init(struct i915_drm_clients *clients);
+
+static inline struct i915_drm_client *
+i915_drm_client_get(struct i915_drm_client *client)
+{
+ kref_get(&client->kref);
+ return client;
+}
+
+void __i915_drm_client_free(struct kref *kref);
+
+static inline void i915_drm_client_put(struct i915_drm_client *client)
+{
+ kref_put(&client->kref, __i915_drm_client_free);
+}
+
+void i915_drm_client_close(struct i915_drm_client *client);
+
+struct i915_drm_client *i915_drm_client_add(struct i915_drm_clients *clients,
+ struct task_struct *task);
+
+#endif /* !__I915_DRM_CLIENT_H__ */
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 94e00e450683..4a16edfe5b6b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -69,6 +69,7 @@
#include "gt/intel_rc6.h"
#include "i915_debugfs.h"
+#include "i915_drm_client.h"
#include "i915_drv.h"
#include "i915_ioc32.h"
#include "i915_irq.h"
@@ -339,6 +340,8 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
i915_gem_init_early(dev_priv);
+ i915_drm_clients_init(&dev_priv->clients);
+
/* This must be called before any calls to HAS_PCH_* */
intel_detect_pch(dev_priv);
@@ -1017,6 +1020,7 @@ static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
struct drm_i915_file_private *file_priv = file->driver_priv;
i915_gem_context_close(file);
+ i915_drm_client_close(file_priv->client);
kfree_rcu(file_priv, rcu);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index ef75acda9bff..e548ff3b85f9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -91,6 +91,7 @@
#include "intel_wakeref.h"
#include "intel_wopcm.h"
+#include "i915_drm_client.h"
#include "i915_gem.h"
#include "i915_gem_gtt.h"
#include "i915_gpu_error.h"
@@ -223,6 +224,8 @@ struct drm_i915_file_private {
/** ban_score: Accumulated score of all ctx bans and fast hangs. */
atomic_t ban_score;
unsigned long hang_timestamp;
+
+ struct i915_drm_client *client;
};
/* Interface history:
@@ -1217,6 +1220,8 @@ struct drm_i915_private {
struct i915_pmu pmu;
+ struct i915_drm_clients clients;
+
struct i915_hdcp_comp_master *hdcp_master;
bool hdcp_comp_added;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index bb0c12975f38..39182c85c5b7 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1267,6 +1267,8 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list));
GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count));
drm_WARN_ON(&dev_priv->drm, dev_priv->mm.shrink_count);
+ drm_WARN_ON(&dev_priv->drm, !xa_empty(&dev_priv->clients.xarray));
+ xa_destroy(&dev_priv->clients.xarray);
}
int i915_gem_freeze(struct drm_i915_private *dev_priv)
@@ -1319,25 +1321,40 @@ int i915_gem_freeze_late(struct drm_i915_private *i915)
int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file)
{
struct drm_i915_file_private *file_priv;
- int ret;
+ struct i915_drm_client *client;
+ int ret = -ENOMEM;
DRM_DEBUG("\n");
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
- return -ENOMEM;
+ goto err_alloc;
+
+ client = i915_drm_client_add(&i915->clients, current);
+ if (IS_ERR(client)) {
+ ret = PTR_ERR(client);
+ goto err_client;
+ }
file->driver_priv = file_priv;
file_priv->dev_priv = i915;
file_priv->file = file;
+ file_priv->client = client;
file_priv->bsd_engine = -1;
file_priv->hang_timestamp = jiffies;
ret = i915_gem_context_open(i915, file);
if (ret)
- kfree(file_priv);
+ goto err_context;
+
+ return 0;
+err_context:
+ i915_drm_client_close(client);
+err_client:
+ kfree(file_priv);
+err_alloc:
return ret;
}
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 45d32ef42787..b7d4a6d2dd5c 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -560,6 +560,11 @@ void i915_setup_sysfs(struct drm_i915_private *dev_priv)
struct device *kdev = dev_priv->drm.primary->kdev;
int ret;
+ dev_priv->clients.root =
+ kobject_create_and_add("clients", &kdev->kobj);
+ if (!dev_priv->clients.root)
+ DRM_ERROR("Per-client sysfs setup failed\n");
+
#ifdef CONFIG_PM
if (HAS_RC6(dev_priv)) {
ret = sysfs_merge_group(&kdev->kobj,
@@ -627,4 +632,7 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
sysfs_unmerge_group(&kdev->kobj, &rc6_attr_group);
sysfs_unmerge_group(&kdev->kobj, &rc6p_attr_group);
#endif
+
+ if (dev_priv->clients.root)
+ kobject_put(dev_priv->clients.root);
}
--
2.25.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
next prev parent reply other threads:[~2020-09-14 13:13 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-14 13:12 [Intel-gfx] [PATCH 0/9] Per client engine busyness Tvrtko Ursulin
2020-09-14 13:12 ` Tvrtko Ursulin [this message]
2020-09-14 13:12 ` [Intel-gfx] [PATCH 2/9] drm/i915: Update client name on context create Tvrtko Ursulin
2020-09-14 13:12 ` [Intel-gfx] [PATCH 3/9] drm/i915: Make GEM contexts track DRM clients Tvrtko Ursulin
2020-09-14 13:12 ` [Intel-gfx] [PATCH 4/9] drm/i915: Track runtime spent in unreachable intel_contexts Tvrtko Ursulin
2020-09-14 15:04 ` Mika Kuoppala
2020-09-14 13:12 ` [Intel-gfx] [PATCH 5/9] drm/i915: Track runtime spent in closed GEM contexts Tvrtko Ursulin
2020-09-14 15:05 ` Mika Kuoppala
2020-09-14 13:12 ` [Intel-gfx] [PATCH 6/9] drm/i915: Track all user contexts per client Tvrtko Ursulin
2020-09-14 13:12 ` [Intel-gfx] [PATCH 7/9] drm/i915: Expose per-engine client busyness Tvrtko Ursulin
2020-09-14 13:12 ` [Intel-gfx] [PATCH 8/9] drm/i915: Track context current active time Tvrtko Ursulin
2020-09-14 13:12 ` [Intel-gfx] [PATCH 9/9] drm/i915: Prefer software tracked context busyness Tvrtko Ursulin
2020-09-14 17:47 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for Per client engine busyness Patchwork
2020-09-14 17:48 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2020-09-14 18:10 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2020-09-15 0:39 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork
-- strict thread matches above, loose matches on Subject: below --
2020-09-04 12:59 [Intel-gfx] [PATCH 0/9] " Tvrtko Ursulin
2020-09-04 12:59 ` [Intel-gfx] [PATCH 1/9] drm/i915: Expose list of clients in sysfs Tvrtko Ursulin
2020-04-15 10:11 [Intel-gfx] [PATCH 0/9] Per client engine busyness Tvrtko Ursulin
2020-04-15 10:11 ` [Intel-gfx] [PATCH 1/9] drm/i915: Expose list of clients in sysfs Tvrtko Ursulin
2020-08-26 1:11 ` Lucas De Marchi
2020-09-01 15:09 ` Tvrtko Ursulin
2020-09-01 15:25 ` Tvrtko Ursulin
2020-09-04 6:26 ` Lucas De Marchi
2020-09-04 13:03 ` Tvrtko Ursulin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200914131256.89465-2-tvrtko.ursulin@linux.intel.com \
--to=tvrtko.ursulin@linux.intel.com \
--cc=Intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.