From patchwork Mon Dec 16 12:07:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tvrtko Ursulin X-Patchwork-Id: 11293985 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E5520930 for ; Mon, 16 Dec 2019 12:07:17 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CC5F0206D3 for ; Mon, 16 Dec 2019 12:07:17 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CC5F0206D3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9F86989EAE; Mon, 16 Dec 2019 12:07:16 +0000 (UTC) X-Original-To: Intel-gfx@lists.freedesktop.org Delivered-To: Intel-gfx@lists.freedesktop.org Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id 35C4689F2E for ; Mon, 16 Dec 2019 12:07:14 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Dec 2019 04:07:14 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,321,1571727600"; d="scan'208";a="416413997" Received: from dtriolet-mobl1.ger.corp.intel.com (HELO localhost.localdomain) ([10.251.84.191]) by fmsmga006.fm.intel.com with ESMTP; 16 Dec 2019 04:07:12 -0800 From: Tvrtko Ursulin To: Intel-gfx@lists.freedesktop.org Date: Mon, 16 Dec 2019 12:07:00 +0000 Message-Id: <20191216120704.958-2-tvrtko.ursulin@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> References: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 1/5] drm/i915: Track per-context engine busyness X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Tvrtko Ursulin Some customers want to know how much of the GPU time are their clients using in order to make dynamic load balancing decisions. With the hooks already in place which track the overall engine busyness, we can extend that slightly to split that time between contexts. v2: Fix accounting for tail updates. v3: Rebase. v4: Mark currently running contexts as active on stats enable. v5: Include some headers to fix the build. v6: Added fine grained lock. v7: Convert to seqlock. (Chris Wilson) v8: Rebase and tidy with helpers. v9: Refactor. Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gt/intel_context.c | 20 ++++++++ drivers/gpu/drm/i915/gt/intel_context.h | 11 +++++ drivers/gpu/drm/i915/gt/intel_context_types.h | 9 ++++ drivers/gpu/drm/i915/gt/intel_engine_cs.c | 16 ++++++- drivers/gpu/drm/i915/gt/intel_lrc.c | 47 ++++++++++++++++--- 5 files changed, 95 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index b1e346d2d35f..b211b48d6cae 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -243,6 +243,7 @@ intel_context_init(struct intel_context *ce, INIT_LIST_HEAD(&ce->signals); mutex_init(&ce->pin_mutex); + seqlock_init(&ce->stats.lock); i915_active_init(&ce->active, __intel_context_active, __intel_context_retire); @@ -337,6 +338,25 @@ struct i915_request *intel_context_create_request(struct intel_context *ce) return rq; } +ktime_t intel_context_get_busy_time(struct intel_context *ce) +{ + unsigned int seq; + ktime_t total; + + do { + seq = read_seqbegin(&ce->stats.lock); + + total = ce->stats.total; + + if (ce->stats.active) + total = ktime_add(total, + ktime_sub(ktime_get(), + ce->stats.start)); + } while (read_seqretry(&ce->stats.lock, seq)); + + return total; +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftest_context.c" #endif diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index b39eb1fcfbca..3a15cf32f0a3 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -160,4 +160,15 @@ static inline struct intel_ring *__intel_context_ring_size(u64 sz) return u64_to_ptr(struct intel_ring, sz); } +static inline void +__intel_context_stats_start(struct intel_context_stats *stats, ktime_t now) +{ + if (!stats->active) { + stats->start = now; + stats->active = true; + } +} + +ktime_t intel_context_get_busy_time(struct intel_context *ce); + #endif /* __INTEL_CONTEXT_H__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index d1204cc899a3..12cbad0798cb 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "i915_active_types.h" #include "i915_utils.h" @@ -76,6 +77,14 @@ struct intel_context { /** sseu: Control eu/slice partitioning */ struct intel_sseu sseu; + + /** stats: Context GPU engine busyness tracking. */ + struct intel_context_stats { + seqlock_t lock; + bool active; + ktime_t start; + ktime_t total; + } stats; }; #endif /* __INTEL_CONTEXT_TYPES__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 3d1d48bf90cf..ac08781c8b24 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1577,8 +1577,20 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine) engine->stats.enabled_at = ktime_get(); - /* XXX submission method oblivious? */ - for (port = execlists->active; (rq = *port); port++) + /* + * Mark currently running context as active. + * XXX submission method oblivious? + */ + + rq = NULL; + port = execlists->active; + if (port) + rq = *port; + if (rq) + __intel_context_stats_start(&rq->hw_context->stats, + engine->stats.enabled_at); + + for (; (rq = *port); port++) engine->stats.active++; for (port = execlists->pending; (rq = *port); port++) { diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 4ebfecd95032..1f158cb439bc 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -940,6 +940,7 @@ static void intel_engine_context_in(struct intel_engine_cs *engine) if (engine->stats.enabled > 0) { if (engine->stats.active++ == 0) engine->stats.start = ktime_get(); + GEM_BUG_ON(engine->stats.active == 0); } @@ -1088,6 +1089,30 @@ static void reset_active(struct i915_request *rq, ce->lrc_desc |= CTX_DESC_FORCE_RESTORE; } +static void +intel_context_stats_start(struct intel_context_stats *stats) +{ + write_seqlock(&stats->lock); + __intel_context_stats_start(stats, ktime_get()); + write_sequnlock(&stats->lock); +} + +static void +intel_context_stats_stop(struct intel_context_stats *stats) +{ + unsigned long flags; + + if (!READ_ONCE(stats->active)) + return; + + write_seqlock_irqsave(&stats->lock, flags); + GEM_BUG_ON(!READ_ONCE(stats->active)); + stats->total = ktime_add(stats->total, + ktime_sub(ktime_get(), stats->start)); + stats->active = false; + write_sequnlock_irqrestore(&stats->lock, flags); +} + static inline struct intel_engine_cs * __execlists_schedule_in(struct i915_request *rq) { @@ -1155,7 +1180,7 @@ static inline void __execlists_schedule_out(struct i915_request *rq, struct intel_engine_cs * const engine) { - struct intel_context * const ce = rq->hw_context; + struct intel_context *ce = rq->hw_context; /* * NB process_csb() is not under the engine->active.lock and hence @@ -1172,6 +1197,7 @@ __execlists_schedule_out(struct i915_request *rq, intel_engine_add_retire(engine, ce->timeline); intel_engine_context_out(engine); + intel_context_stats_stop(&ce->stats); execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT); intel_gt_pm_put_async(engine->gt); @@ -1389,6 +1415,9 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) write_desc(execlists, rq ? execlists_update_context(rq) : 0, n); + + if (n == 0) + intel_context_stats_start(&rq->hw_context->stats); } /* we need to manually load the submit queue */ @@ -2197,7 +2226,11 @@ static void process_csb(struct intel_engine_cs *engine) WRITE_ONCE(execlists->pending[0], NULL); } else { - GEM_BUG_ON(!*execlists->active); + struct i915_request *rq = *execlists->active++; + + GEM_BUG_ON(!rq); + GEM_BUG_ON(execlists->active - execlists->inflight > + execlists_num_ports(execlists)); /* port0 completed, advanced to port1 */ trace_ports(execlists, "completed", execlists->active); @@ -2208,12 +2241,14 @@ static void process_csb(struct intel_engine_cs *engine) * coherent (visible from the CPU) before the * user interrupt and CSB is processed. */ - GEM_BUG_ON(!i915_request_completed(*execlists->active) && + GEM_BUG_ON(!i915_request_completed(rq) && !reset_in_progress(execlists)); - execlists_schedule_out(*execlists->active++); - GEM_BUG_ON(execlists->active - execlists->inflight > - execlists_num_ports(execlists)); + execlists_schedule_out(rq); + rq = *execlists->active; + if (rq) + intel_context_stats_start(&rq->hw_context->stats); + } } while (head != tail); From patchwork Mon Dec 16 12:07:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tvrtko Ursulin X-Patchwork-Id: 11293987 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6DA6E930 for ; Mon, 16 Dec 2019 12:07:19 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5477E206D3 for ; Mon, 16 Dec 2019 12:07:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5477E206D3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id EE6C589F2A; Mon, 16 Dec 2019 12:07:16 +0000 (UTC) X-Original-To: Intel-gfx@lists.freedesktop.org Delivered-To: Intel-gfx@lists.freedesktop.org Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id A1AE289EAE for ; Mon, 16 Dec 2019 12:07:15 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Dec 2019 04:07:15 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,321,1571727600"; d="scan'208";a="416414002" Received: from dtriolet-mobl1.ger.corp.intel.com (HELO localhost.localdomain) ([10.251.84.191]) by fmsmga006.fm.intel.com with ESMTP; 16 Dec 2019 04:07:14 -0800 From: Tvrtko Ursulin To: Intel-gfx@lists.freedesktop.org Date: Mon, 16 Dec 2019 12:07:01 +0000 Message-Id: <20191216120704.958-3-tvrtko.ursulin@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> References: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 2/5] drm/i915: Expose list of clients in sysfs X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Tvrtko Ursulin 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. Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_drv.h | 21 +++++ drivers/gpu/drm/i915/i915_gem.c | 148 ++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_sysfs.c | 8 ++ 3 files changed, 167 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0781b6326b8c..9fcbcb6d6f76 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -224,6 +224,20 @@ 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 { + unsigned int id; + + struct pid *pid; + char *name; + + struct kobject *root; + + struct { + struct device_attribute pid; + struct device_attribute name; + } attr; + } client; }; /* Interface history: @@ -1278,6 +1292,13 @@ struct drm_i915_private { struct i915_pmu pmu; + struct i915_drm_clients { + spinlock_t idr_lock; + struct idr idr; + + struct kobject *root; + } 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 5eeef1ef7448..a65cd7e1ce7b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1457,11 +1457,14 @@ static void i915_gem_init__mm(struct drm_i915_private *i915) i915_gem_init__objects(i915); } -void i915_gem_init_early(struct drm_i915_private *dev_priv) +void i915_gem_init_early(struct drm_i915_private *i915) { - i915_gem_init__mm(dev_priv); + i915_gem_init__mm(i915); - spin_lock_init(&dev_priv->fb_tracking.lock); + spin_lock_init(&i915->fb_tracking.lock); + + spin_lock_init(&i915->clients.idr_lock); + idr_init(&i915->clients.idr); } void i915_gem_cleanup_early(struct drm_i915_private *dev_priv) @@ -1518,6 +1521,106 @@ int i915_gem_freeze_late(struct drm_i915_private *i915) return 0; } +static ssize_t +show_client_name(struct device *kdev, struct device_attribute *attr, char *buf) +{ + struct drm_i915_file_private *file_priv = + container_of(attr, struct drm_i915_file_private, + client.attr.name); + + return snprintf(buf, PAGE_SIZE, "%s", file_priv->client.name); +} + +static ssize_t +show_client_pid(struct device *kdev, struct device_attribute *attr, char *buf) +{ + struct drm_i915_file_private *file_priv = + container_of(attr, struct drm_i915_file_private, + client.attr.pid); + + return snprintf(buf, PAGE_SIZE, "%u", pid_nr(file_priv->client.pid)); +} + +static int +i915_gem_add_client(struct drm_i915_private *i915, + struct drm_i915_file_private *file_priv, + struct task_struct *task, + unsigned int serial) +{ + struct i915_drm_client *client = &file_priv->client; + struct i915_drm_clients *clients = &i915->clients; + struct device_attribute *attr; + int ret = -ENOMEM; + char id[32]; + + if (!clients->root) + return 0; /* intel_fbdev_init registers a client before sysfs */ + + client->name = kstrdup(task->comm, GFP_KERNEL); + if (!client->name) + goto err_name; + + snprintf(id, sizeof(id), "%u", serial); + client->root = kobject_create_and_add(id, clients->root); + if (!client->root) + goto err_client; + + attr = &client->attr.name; + sysfs_attr_init(&attr->attr); + attr->attr.name = "name"; + attr->attr.mode = 0444; + attr->show = show_client_name; + + ret = sysfs_create_file(client->root, (struct attribute *)attr); + if (ret) + goto err_attr_name; + + attr = &client->attr.pid; + sysfs_attr_init(&attr->attr); + attr->attr.name = "pid"; + attr->attr.mode = 0444; + attr->show = show_client_pid; + + ret = sysfs_create_file(client->root, (struct attribute *)attr); + if (ret) + goto err_attr_pid; + + client->id = serial; + client->pid = get_task_pid(task, PIDTYPE_PID); + + return 0; + +err_attr_pid: + sysfs_remove_file(client->root, (struct attribute *)&client->attr.name); +err_attr_name: + kobject_put(client->root); +err_client: + kfree(client->name); +err_name: + return ret; +} + +static void i915_gem_remove_client(struct drm_i915_file_private *file_priv) +{ + struct i915_drm_clients *clients = &file_priv->dev_priv->clients; + struct i915_drm_client *client = &file_priv->client; + + if (!client->name) + return; /* intel_fbdev_init registers a client before sysfs */ + + sysfs_remove_file(client->root, (struct attribute *)&client->attr.pid); + sysfs_remove_file(client->root, (struct attribute *)&client->attr.name); + kobject_put(client->root); + + spin_lock(&clients->idr_lock); + idr_remove(&clients->idr, client->id); + spin_unlock(&clients->idr_lock); + + put_pid(client->pid); + + kfree(client->name); +} + void i915_gem_release(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; @@ -1531,33 +1634,58 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file) list_for_each_entry(request, &file_priv->mm.request_list, client_link) request->file_priv = NULL; spin_unlock(&file_priv->mm.lock); + + i915_gem_remove_client(file_priv); } int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file) { + struct i915_drm_clients *clients = &i915->clients; struct drm_i915_file_private *file_priv; - int ret; + int ret = -ENOMEM; + int id; DRM_DEBUG("\n"); file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); if (!file_priv) - return -ENOMEM; + goto err_alloc; + + spin_lock(&clients->idr_lock); + id = idr_alloc_cyclic(&clients->idr, file_priv, 0, -1, GFP_KERNEL); + spin_unlock(&clients->idr_lock); + if (id < 0) + goto err_alloc; + + ret = i915_gem_add_client(i915, file_priv, current, id); + if (ret) + goto err_client; file->driver_priv = file_priv; + ret = i915_gem_context_open(i915, file); + if (ret) + goto err_context; + file_priv->dev_priv = i915; file_priv->file = file; + file_priv->bsd_engine = -1; + file_priv->hang_timestamp = jiffies; spin_lock_init(&file_priv->mm.lock); INIT_LIST_HEAD(&file_priv->mm.request_list); - file_priv->bsd_engine = -1; - file_priv->hang_timestamp = jiffies; + return 0; - ret = i915_gem_context_open(i915, file); - if (ret) - kfree(file_priv); +err_context: + i915_gem_remove_client(file_priv); + +err_client: + spin_lock(&clients->idr_lock); + idr_remove(&clients->idr, id); + spin_unlock(&clients->idr_lock); + 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 ad2b1b833d7b..3ab50e29fddf 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -559,6 +559,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, @@ -619,4 +624,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); } From patchwork Mon Dec 16 12:07:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tvrtko Ursulin X-Patchwork-Id: 11293993 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 42959930 for ; Mon, 16 Dec 2019 12:07:25 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 29A2B206D3 for ; Mon, 16 Dec 2019 12:07:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 29A2B206D3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 465FD89F45; Mon, 16 Dec 2019 12:07:23 +0000 (UTC) X-Original-To: Intel-gfx@lists.freedesktop.org Delivered-To: Intel-gfx@lists.freedesktop.org Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id EF36389F2E for ; Mon, 16 Dec 2019 12:07:16 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Dec 2019 04:07:16 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,321,1571727600"; d="scan'208";a="416414011" Received: from dtriolet-mobl1.ger.corp.intel.com (HELO localhost.localdomain) ([10.251.84.191]) by fmsmga006.fm.intel.com with ESMTP; 16 Dec 2019 04:07:15 -0800 From: Tvrtko Ursulin To: Intel-gfx@lists.freedesktop.org Date: Mon, 16 Dec 2019 12:07:02 +0000 Message-Id: <20191216120704.958-4-tvrtko.ursulin@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> References: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 3/5] drm/i915: Update client name on context create X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Tvrtko Ursulin Some clients have the DRM fd passed to them over a socket by the X server. Grab the real client and pid when they create their first context and update the exposed data for more useful enumeration. v2: * Do not leak the pid reference and borrow context idr_lock. (Chris) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 24 ++++++++++++++++++--- drivers/gpu/drm/i915/i915_drv.h | 7 ++++++ drivers/gpu/drm/i915/i915_gem.c | 4 ++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 46b4d1d643f8..cd4ba6486f35 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -2178,7 +2178,9 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, { struct drm_i915_private *i915 = to_i915(dev); struct drm_i915_gem_context_create_ext *args = data; + struct drm_i915_file_private *file_priv = file->driver_priv; struct create_ext ext_data; + struct pid *pid; int ret; if (!DRIVER_CAPS(i915)->has_logical_contexts) @@ -2191,14 +2193,30 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - ext_data.fpriv = file->driver_priv; + ext_data.fpriv = file_priv; + pid = get_task_pid(current, PIDTYPE_PID); if (client_is_banned(ext_data.fpriv)) { DRM_DEBUG("client %s[%d] banned from creating ctx\n", - current->comm, - pid_nr(get_task_pid(current, PIDTYPE_PID))); + current->comm, pid_nr(pid)); + put_pid(pid); return -EIO; } + /* + * Borrow the context idr_lock to protect the client remove-add cycle. + */ + if (mutex_lock_interruptible(&file_priv->context_idr_lock)) + return -EINTR; + if (pid_nr(file_priv->client.pid) != pid_nr(pid)) { + i915_gem_remove_client(file_priv); + ret = i915_gem_add_client(i915, file_priv, current, + file_priv->client.id); + } + mutex_unlock(&file_priv->context_idr_lock); + put_pid(pid); + if (ret) + return ret; + ext_data.ctx = i915_gem_create_context(i915, args->flags); if (IS_ERR(ext_data.ctx)) return PTR_ERR(ext_data.ctx); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9fcbcb6d6f76..1740ce54cb48 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1899,6 +1899,13 @@ void i915_gem_suspend(struct drm_i915_private *dev_priv); void i915_gem_suspend_late(struct drm_i915_private *dev_priv); void i915_gem_resume(struct drm_i915_private *dev_priv); +int +i915_gem_add_client(struct drm_i915_private *i915, + struct drm_i915_file_private *file_priv, + struct task_struct *task, + unsigned int serial); +void i915_gem_remove_client(struct drm_i915_file_private *file_priv); + int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file); void i915_gem_release(struct drm_device *dev, struct drm_file *file); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a65cd7e1ce7b..59c160534838 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1541,7 +1541,7 @@ show_client_pid(struct device *kdev, struct device_attribute *attr, char *buf) return snprintf(buf, PAGE_SIZE, "%u", pid_nr(file_priv->client.pid)); } -static int +int i915_gem_add_client(struct drm_i915_private *i915, struct drm_i915_file_private *file_priv, struct task_struct *task, @@ -1600,7 +1600,7 @@ i915_gem_add_client(struct drm_i915_private *i915, return ret; } -static void i915_gem_remove_client(struct drm_i915_file_private *file_priv) +void i915_gem_remove_client(struct drm_i915_file_private *file_priv) { struct i915_drm_clients *clients = &file_priv->dev_priv->clients; struct i915_drm_client *client = &file_priv->client; From patchwork Mon Dec 16 12:07:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tvrtko Ursulin X-Patchwork-Id: 11293991 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D0FC81593 for ; Mon, 16 Dec 2019 12:07:23 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B8194206D3 for ; Mon, 16 Dec 2019 12:07:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B8194206D3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4DBF589F55; Mon, 16 Dec 2019 12:07:23 +0000 (UTC) X-Original-To: Intel-gfx@lists.freedesktop.org Delivered-To: Intel-gfx@lists.freedesktop.org Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id 536AD89EA3 for ; Mon, 16 Dec 2019 12:07:18 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Dec 2019 04:07:18 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,321,1571727600"; d="scan'208";a="416414015" Received: from dtriolet-mobl1.ger.corp.intel.com (HELO localhost.localdomain) ([10.251.84.191]) by fmsmga006.fm.intel.com with ESMTP; 16 Dec 2019 04:07:17 -0800 From: Tvrtko Ursulin To: Intel-gfx@lists.freedesktop.org Date: Mon, 16 Dec 2019 12:07:03 +0000 Message-Id: <20191216120704.958-5-tvrtko.ursulin@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> References: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 4/5] drm/i915: Expose per-engine client busyness X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Tvrtko Ursulin Expose per-client and per-engine busyness under the previously added sysfs client root. The new files are one per-engine instance and located under the 'busy' directory. Each contains a monotonically increasing nano-second resolution times each client's jobs were executing on the GPU. This enables userspace to create a top-like tool for GPU utilization: ========================================================================== intel-gpu-top - 935/ 935 MHz; 0% RC6; 14.73 Watts; 1097 irqs/s IMC reads: 1401 MiB/s IMC writes: 4 MiB/s ENGINE BUSY MI_SEMA MI_WAIT Render/3D/0 63.73% |███████████████████ | 3% 0% Blitter/0 9.53% |██▊ | 6% 0% Video/0 39.32% |███████████▊ | 16% 0% Video/1 15.62% |████▋ | 0% 0% VideoEnhance/0 0.00% | | 0% 0% PID NAME RCS BCS VCS VECS 4084 gem_wsim |█████▌ ||█ || || | 4086 gem_wsim |█▌ || ||███ || | ========================================================================== v2: Use intel_context_engine_get_busy_time. v3: New directory structure. v4: Rebase. v5: sysfs_attr_init. v6: Small tidy in i915_gem_add_client. v7: Rebase to be engine class based. v8: Use rcu_read_lock instead of struct_mutext when iterating contexts. (Chris) Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_drv.h | 8 +++ drivers/gpu/drm/i915/i915_gem.c | 94 +++++++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1740ce54cb48..e9cefd9b55b5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -188,6 +188,12 @@ struct drm_i915_private; struct i915_mm_struct; struct i915_mmu_object; +struct i915_engine_busy_attribute { + struct device_attribute attr; + struct drm_i915_file_private *file_priv; + unsigned int engine_class; +}; + struct drm_i915_file_private { struct drm_i915_private *dev_priv; @@ -232,10 +238,12 @@ struct drm_i915_file_private { char *name; struct kobject *root; + struct kobject *busy_root; struct { struct device_attribute pid; struct device_attribute name; + struct i915_engine_busy_attribute busy[MAX_ENGINE_CLASS]; } attr; } client; }; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 59c160534838..2337c4d82ad4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1541,6 +1541,53 @@ show_client_pid(struct device *kdev, struct device_attribute *attr, char *buf) return snprintf(buf, PAGE_SIZE, "%u", pid_nr(file_priv->client.pid)); } +struct busy_ctx { + unsigned int engine_class; + u64 total; +}; + +static int busy_add(int id, void *p, void *data) +{ + struct busy_ctx *bc = data; + struct i915_gem_context *ctx = p; + struct i915_gem_engines *engines = rcu_dereference(ctx->engines); + unsigned int engine_class = bc->engine_class; + struct i915_gem_engines_iter it; + struct intel_context *ce; + uint64_t total = bc->total; + + for_each_gem_engine(ce, engines, it) { + if (ce->engine->uabi_class == engine_class) + total += ktime_to_ns(intel_context_get_busy_time(ce)); + } + + bc->total = total; + + return 0; +} + +static ssize_t +show_client_busy(struct device *kdev, struct device_attribute *attr, char *buf) +{ + struct i915_engine_busy_attribute *i915_attr = + container_of(attr, typeof(*i915_attr), attr); + struct drm_i915_file_private *file_priv = i915_attr->file_priv; + struct busy_ctx bc = { .engine_class = i915_attr->engine_class }; + + rcu_read_lock(); + idr_for_each(&file_priv->context_idr, busy_add, &bc); + rcu_read_unlock(); + + return snprintf(buf, PAGE_SIZE, "%llu\n", bc.total); +} + +static const char *uabi_class_names[] = { + [I915_ENGINE_CLASS_RENDER] = "0", + [I915_ENGINE_CLASS_COPY] = "1", + [I915_ENGINE_CLASS_VIDEO] = "2", + [I915_ENGINE_CLASS_VIDEO_ENHANCE] = "3", +}; + int i915_gem_add_client(struct drm_i915_private *i915, struct drm_i915_file_private *file_priv, @@ -1550,8 +1597,8 @@ i915_gem_add_client(struct drm_i915_private *i915, struct i915_drm_client *client = &file_priv->client; struct i915_drm_clients *clients = &i915->clients; struct device_attribute *attr; - int ret = -ENOMEM; - char id[32]; + int i, ret = -ENOMEM; + char idstr[32]; if (!clients->root) return 0; /* intel_fbdev_init registers a client before sysfs */ @@ -1560,8 +1607,8 @@ i915_gem_add_client(struct drm_i915_private *i915, if (!client->name) goto err_name; - snprintf(id, sizeof(id), "%u", serial); - client->root = kobject_create_and_add(id, clients->root); + snprintf(idstr, sizeof(idstr), "%u", serial); + client->root = kobject_create_and_add(idstr, clients->root); if (!client->root) goto err_client; @@ -1585,11 +1632,43 @@ i915_gem_add_client(struct drm_i915_private *i915, if (ret) goto err_attr_pid; + client->busy_root = kobject_create_and_add("busy", client->root); + if (!client->busy_root) + goto err_busy_root; + + for (i = 0; i < ARRAY_SIZE(uabi_class_names); i++) { + struct i915_engine_busy_attribute *i915_attr = + &client->attr.busy[i]; + + i915_attr->file_priv = file_priv; + i915_attr->engine_class = i; + + attr = &i915_attr->attr; + + sysfs_attr_init(&attr->attr); + + attr->attr.name = uabi_class_names[i]; + attr->attr.mode = 0444; + attr->show = show_client_busy; + + ret = sysfs_create_file(client->busy_root, + (struct attribute *)attr); + if (ret) + goto err_attr_busy; + } + client->id = serial; client->pid = get_task_pid(task, PIDTYPE_PID); return 0; +err_attr_busy: + for (--i; i >= 0; i--) + sysfs_remove_file(client->busy_root, + (struct attribute *)&client->attr.busy[i]); + kobject_put(client->busy_root); +err_busy_root: + sysfs_remove_file(client->root, (struct attribute *)&client->attr.pid); err_attr_pid: sysfs_remove_file(client->root, (struct attribute *)&client->attr.name); err_attr_name: @@ -1604,10 +1683,17 @@ void i915_gem_remove_client(struct drm_i915_file_private *file_priv) { struct i915_drm_clients *clients = &file_priv->dev_priv->clients; struct i915_drm_client *client = &file_priv->client; + unsigned int i; if (!client->name) return; /* intel_fbdev_init registers a client before sysfs */ + for (i = 0; i < ARRAY_SIZE(uabi_class_names); i++) + sysfs_remove_file(client->busy_root, + (struct attribute *)&client->attr.busy[i]); + + kobject_put(client->busy_root); + sysfs_remove_file(client->root, (struct attribute *)&client->attr.pid); sysfs_remove_file(client->root, (struct attribute *)&client->attr.name); kobject_put(client->root); From patchwork Mon Dec 16 12:07:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tvrtko Ursulin X-Patchwork-Id: 11293989 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 870C1930 for ; Mon, 16 Dec 2019 12:07:21 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6E65D206D3 for ; Mon, 16 Dec 2019 12:07:21 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6E65D206D3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A8F4089F2E; Mon, 16 Dec 2019 12:07:20 +0000 (UTC) X-Original-To: Intel-gfx@lists.freedesktop.org Delivered-To: Intel-gfx@lists.freedesktop.org Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by gabe.freedesktop.org (Postfix) with ESMTPS id A6B5E89EA3 for ; Mon, 16 Dec 2019 12:07:19 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Dec 2019 04:07:19 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,321,1571727600"; d="scan'208";a="416414021" Received: from dtriolet-mobl1.ger.corp.intel.com (HELO localhost.localdomain) ([10.251.84.191]) by fmsmga006.fm.intel.com with ESMTP; 16 Dec 2019 04:07:18 -0800 From: Tvrtko Ursulin To: Intel-gfx@lists.freedesktop.org Date: Mon, 16 Dec 2019 12:07:04 +0000 Message-Id: <20191216120704.958-6-tvrtko.ursulin@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> References: <20191216120704.958-1-tvrtko.ursulin@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 5/5] drm/i915: Add sysfs toggle to enable per-client engine stats X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" From: Tvrtko Ursulin By default we are not collecting any per-engine and per-context statistcs. Add a new sysfs toggle to enable this facility: $ echo 1 >/sys/class/drm/card0/clients/enable_stats v2: Rebase. v3: sysfs_attr_init. v4: Scheduler caps. v5: for_each_uabi_engine Signed-off-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_drv.h | 5 ++ drivers/gpu/drm/i915/i915_sysfs.c | 76 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e9cefd9b55b5..e795e6fea6d3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1305,6 +1305,11 @@ struct drm_i915_private { struct idr idr; struct kobject *root; + + struct { + bool enabled; + struct device_attribute attr; + } stats; } clients; struct i915_hdcp_comp_master *hdcp_master; diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 3ab50e29fddf..3443ff37b17a 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -554,9 +554,70 @@ static void i915_setup_error_capture(struct device *kdev) {} static void i915_teardown_error_capture(struct device *kdev) {} #endif +static ssize_t +show_client_stats(struct device *kdev, struct device_attribute *attr, char *buf) +{ + struct drm_i915_private *i915 = + container_of(attr, struct drm_i915_private, clients.stats.attr); + + return snprintf(buf, PAGE_SIZE, "%u\n", i915->clients.stats.enabled); +} + +static ssize_t +store_client_stats(struct device *kdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct drm_i915_private *i915 = + container_of(attr, struct drm_i915_private, clients.stats.attr); + struct i915_drm_clients *clients = &i915->clients; + struct intel_engine_cs *engine; + bool disable = false; + bool enable = false; + bool val = false; + int ret; + + /* Use RCS as proxy for all engines. */ + if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_ENGINE_BUSY_STATS)) + return -EINVAL; + + ret = kstrtobool(buf, &val); + if (ret) + return ret; + + /* + * We use struct_mutex to allow one client at the time toggle the state. + */ + ret = i915_mutex_lock_interruptible(&i915->drm); + if (ret) + return ret; + + if (val && !clients->stats.enabled) + enable = true; + else if (!val && clients->stats.enabled) + disable = true; + + if (!enable && !disable) + goto out; + + for_each_uabi_engine(engine, i915) { + if (enable) + WARN_ON_ONCE(intel_enable_engine_stats(engine)); + else if (disable) + intel_disable_engine_stats(engine); + } + + clients->stats.enabled = val; + +out: + mutex_unlock(&i915->drm.struct_mutex); + + return count; +} + void i915_setup_sysfs(struct drm_i915_private *dev_priv) { struct device *kdev = dev_priv->drm.primary->kdev; + struct device_attribute *attr; int ret; dev_priv->clients.root = @@ -564,6 +625,18 @@ void i915_setup_sysfs(struct drm_i915_private *dev_priv) if (!dev_priv->clients.root) DRM_ERROR("Per-client sysfs setup failed\n"); + attr = &dev_priv->clients.stats.attr; + sysfs_attr_init(&attr->attr); + attr->attr.name = "enable_stats"; + attr->attr.mode = 0664; + attr->show = show_client_stats; + attr->store = store_client_stats; + + ret = sysfs_create_file(dev_priv->clients.root, + (struct attribute *)attr); + if (ret) + DRM_ERROR("Per-client sysfs setup failed! (%d)\n", ret); + #ifdef CONFIG_PM if (HAS_RC6(dev_priv)) { ret = sysfs_merge_group(&kdev->kobj, @@ -625,6 +698,9 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv) sysfs_unmerge_group(&kdev->kobj, &rc6p_attr_group); #endif + sysfs_remove_file(dev_priv->clients.root, + (struct attribute *)&dev_priv->clients.stats.attr); + if (dev_priv->clients.root) kobject_put(dev_priv->clients.root); }