* [RFC 1/8] drm/i915: Introduce global id for contexts
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
2015-08-05 5:52 ` [RFC 2/8] drm/i915: Introduce mode for capture of multi ctx OA reports synchronized with RCS sourab.gupta
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
The current context user handles are specific to drm file instance.
There are some usecases, which may require a global id for the contexts.
For e.g. a system level GPU profiler tool may lean upon the global context
ids to associate the performance snapshots with individual contexts.
This global id may also be used further in order to provide a unique
context id to hw.
In this patch, the global ids are allocated from a separate cyclic idr and
can be further utilized for any usecase described above.
v2: According to Chris' suggestion, implemented a separate idr for holding
global ids for contexts, as opposed to overloading the file specific
ctx->user_handle for this purpose. This global id can also further be used
wherever hw has to be programmed with ctx unique id, though this patch just
introduces the hw global id as such.
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 3 +++
drivers/gpu/drm/i915/i915_gem_context.c | 19 +++++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 50977f0..3436f3b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -861,6 +861,7 @@ struct i915_ctx_hang_stats {
struct intel_context {
struct kref ref;
int user_handle;
+ int global_id;
uint8_t remap_slice;
int flags;
struct drm_i915_file_private *file_priv;
@@ -1756,6 +1757,8 @@ struct drm_i915_private {
bool preserve_bios_swizzle;
+ struct idr global_ctx_idr;
+
/* overlay */
struct intel_overlay *overlay;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index d9ccad5..51ec420 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -246,6 +246,18 @@ __create_hw_context(struct drm_device *dev,
ctx->file_priv = file_priv;
ctx->user_handle = ret;
+
+ /* TODO: If required, this global id can be used for programming the hw
+ * fields too. In that case, we'll have take care of hw restrictions
+ * while allocating idr. e.g. for some hw, we may not have full 32 bits
+ * available.
+ */
+ ret = idr_alloc_cyclic(&dev_priv->global_ctx_idr,
+ ctx, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto err_out;
+
+ ctx->global_id = ret;
/* NB: Mark all slices as needing a remap so that when the context first
* loads it will restore whatever remap state already exists. If there
* is no remap info, it will be a NOP. */
@@ -270,6 +282,7 @@ i915_gem_create_context(struct drm_device *dev,
struct drm_i915_file_private *file_priv)
{
const bool is_global_default_ctx = file_priv == NULL;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_context *ctx;
int ret = 0;
@@ -315,6 +328,7 @@ err_unpin:
if (is_global_default_ctx && ctx->legacy_hw_ctx.rcs_state)
i915_gem_context_unpin_state(dev, ctx);
err_destroy:
+ idr_remove(&dev_priv->global_ctx_idr, ctx->global_id);
i915_gem_context_unreference(ctx);
return ERR_PTR(ret);
}
@@ -371,6 +385,7 @@ int i915_gem_context_init(struct drm_device *dev)
dev_priv->hw_context_size = 0;
}
}
+ idr_init(&dev_priv->global_ctx_idr);
ctx = i915_gem_create_context(dev, NULL);
if (IS_ERR(ctx)) {
@@ -398,6 +413,8 @@ void i915_gem_context_fini(struct drm_device *dev)
struct intel_context *dctx = dev_priv->ring[RCS].default_context;
int i;
+ idr_destroy(&dev_priv->global_ctx_idr);
+
if (dctx->legacy_hw_ctx.rcs_state) {
/* The only known way to stop the gpu from accessing the hw context is
* to reset it. Do this as the very last operation to avoid confusing
@@ -878,6 +895,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
{
struct drm_i915_gem_context_destroy *args = data;
struct drm_i915_file_private *file_priv = file->driver_priv;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_context *ctx;
int ret;
@@ -895,6 +913,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
}
idr_remove(&ctx->file_priv->context_idr, ctx->user_handle);
+ idr_remove(&dev_priv->global_ctx_idr, ctx->global_id);
i915_gem_context_unreference(ctx);
mutex_unlock(&dev->struct_mutex);
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 2/8] drm/i915: Introduce mode for capture of multi ctx OA reports synchronized with RCS
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
2015-08-05 5:52 ` [RFC 1/8] drm/i915: Introduce global id for contexts sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
2015-08-05 5:52 ` [RFC 3/8] drm/i915: Add mechanism for forwarding CS based OA counter snapshots through perf sourab.gupta
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
This patch introduces a mode of capturing OA counter reports belonging to
multiple contexts, which can be mapped back to individual contexts. The OA
reports captured in this way are synchronized with Render command stream.
There may be usecases wherein we need more than periodic OA capture mode
which is supported by perf_event currently. We may need to insert RCS
synchronized commands to capture the OA counter snapshots.
This mode is primarily used for two usecases:
- Ability to capture system wide metrics, alongwith the ability to map
the reports back to individual contexts.
- Ability to inject tags for work, into the reports. This provides
visibility into the multiple stages of work within single context.
The OA reports generated in this way will be forwarded to userspace after
appending a footer, which will have this metadata information. This will
enable the usecases mentioned above.
This patch introduces an additional field in the oa attr structure for
supporting this capture mode. The data thus captured needs to be stored in
a separate buffer, which will be different from the buffer used otherwise
for periodic OA capture mode. Again this buffer address will not need to be
mapped to OA unit register addresses such as OASTATUS1, OASTATUS2 and
OABUFFER.
The subsequent patches introduce the mechanism for forwarding reports to
userspace, handling the command synchronization and mechanism for
inserting corresponding commands into the ringbuffer.
v2: Following changes:
- Save the gtt offset while pinning the buffer, to be retrieved when
required.
- Use spin_lock instead of spin_lock_irqsave
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 10 +++
drivers/gpu/drm/i915/i915_oa_perf.c | 170 +++++++++++++++++++++++++++---------
include/uapi/drm/i915_drm.h | 3 +-
3 files changed, 141 insertions(+), 42 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 3436f3b..050bdda 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1931,6 +1931,7 @@ struct drm_i915_private {
bool event_active;
bool periodic;
+ bool multiple_ctx_mode;
u32 period_exponent;
u32 metrics_set;
@@ -1945,6 +1946,15 @@ struct drm_i915_private {
int format_size;
spinlock_t flush_lock;
} oa_buffer;
+
+ /* Fields for multiple context capture mode */
+ struct {
+ struct drm_i915_gem_object *obj;
+ u32 gtt_offset;
+ u8 *addr;
+ int format;
+ int format_size;
+ } oa_rcs_buffer;
} oa_pmu;
#endif
diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c
index e7e0b2b..fd0c3a0 100644
--- a/drivers/gpu/drm/i915/i915_oa_perf.c
+++ b/drivers/gpu/drm/i915/i915_oa_perf.c
@@ -166,19 +166,36 @@ static void flush_oa_snapshots(struct drm_i915_private *dev_priv,
}
static void
-oa_buffer_destroy(struct drm_i915_private *i915)
+oa_rcs_buffer_destroy(struct drm_i915_private *i915)
{
mutex_lock(&i915->dev->struct_mutex);
+ vunmap(i915->oa_pmu.oa_rcs_buffer.addr);
+ i915_gem_object_ggtt_unpin(i915->oa_pmu.oa_rcs_buffer.obj);
+ drm_gem_object_unreference(&i915->oa_pmu.oa_rcs_buffer.obj->base);
+ mutex_unlock(&i915->dev->struct_mutex);
+
+ spin_lock(&i915->oa_pmu.lock);
+ i915->oa_pmu.oa_rcs_buffer.obj = NULL;
+ i915->oa_pmu.oa_rcs_buffer.gtt_offset = 0;
+ i915->oa_pmu.oa_rcs_buffer.addr = NULL;
+ spin_unlock(&i915->oa_pmu.lock);
+}
+static void
+oa_buffer_destroy(struct drm_i915_private *i915)
+{
+ mutex_lock(&i915->dev->struct_mutex);
vunmap(i915->oa_pmu.oa_buffer.addr);
i915_gem_object_ggtt_unpin(i915->oa_pmu.oa_buffer.obj);
drm_gem_object_unreference(&i915->oa_pmu.oa_buffer.obj->base);
+ mutex_unlock(&i915->dev->struct_mutex);
+ spin_lock(&i915->oa_pmu.lock);
i915->oa_pmu.oa_buffer.obj = NULL;
i915->oa_pmu.oa_buffer.gtt_offset = 0;
i915->oa_pmu.oa_buffer.addr = NULL;
+ spin_unlock(&i915->oa_pmu.lock);
- mutex_unlock(&i915->dev->struct_mutex);
}
static void i915_oa_event_destroy(struct perf_event *event)
@@ -207,6 +224,9 @@ static void i915_oa_event_destroy(struct perf_event *event)
I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) &
~GT_NOA_ENABLE));
+ if (dev_priv->oa_pmu.multiple_ctx_mode)
+ oa_rcs_buffer_destroy(dev_priv);
+
oa_buffer_destroy(dev_priv);
BUG_ON(dev_priv->oa_pmu.exclusive_event != event);
@@ -216,6 +236,59 @@ static void i915_oa_event_destroy(struct perf_event *event)
intel_runtime_pm_put(dev_priv);
}
+static int alloc_obj(struct drm_i915_private *dev_priv,
+ struct drm_i915_gem_object **obj)
+{
+ struct drm_i915_gem_object *bo;
+ int ret;
+
+ /* NB: We over allocate the OA buffer due to the way raw sample data
+ * gets copied from the gpu mapped circular buffer into the perf
+ * circular buffer so that only one copy is required.
+ *
+ * For each perf sample (raw->size + 4) needs to be 8 byte aligned,
+ * where the 4 corresponds to the 32bit raw->size member that's
+ * added to the sample header that userspace sees.
+ *
+ * Due to the + 4 for the size member: when we copy a report to the
+ * userspace facing perf buffer we always copy an additional 4 bytes
+ * from the subsequent report to make up for the miss alignment, but
+ * when a report is at the end of the gpu mapped buffer we need to
+ * read 4 bytes past the end of the buffer.
+ */
+ intel_runtime_pm_get(dev_priv);
+
+ ret = i915_mutex_lock_interruptible(dev_priv->dev);
+ if (ret)
+ goto out;
+
+ bo = i915_gem_alloc_object(dev_priv->dev, OA_BUFFER_SIZE + PAGE_SIZE);
+ if (bo == NULL) {
+ DRM_ERROR("Failed to allocate OA buffer\n");
+ ret = -ENOMEM;
+ goto unlock;
+ }
+ ret = i915_gem_object_set_cache_level(bo, I915_CACHE_LLC);
+ if (ret)
+ goto err_unref;
+
+ /* PreHSW required 512K alignment, HSW requires 16M */
+ ret = i915_gem_obj_ggtt_pin(bo, SZ_16M, 0);
+ if (ret)
+ goto err_unref;
+
+ *obj = bo;
+ goto unlock;
+
+err_unref:
+ drm_gem_object_unreference(&bo->base);
+unlock:
+ mutex_unlock(&dev_priv->dev->struct_mutex);
+out:
+ intel_runtime_pm_put(dev_priv);
+ return ret;
+}
+
static void *vmap_oa_buffer(struct drm_i915_gem_object *obj)
{
int i;
@@ -257,42 +330,13 @@ static int init_oa_buffer(struct perf_event *event)
BUG_ON(!IS_HASWELL(dev_priv->dev));
BUG_ON(dev_priv->oa_pmu.oa_buffer.obj);
- ret = i915_mutex_lock_interruptible(dev_priv->dev);
- if (ret)
- return ret;
-
spin_lock_init(&dev_priv->oa_pmu.oa_buffer.flush_lock);
- /* NB: We over allocate the OA buffer due to the way raw sample data
- * gets copied from the gpu mapped circular buffer into the perf
- * circular buffer so that only one copy is required.
- *
- * For each perf sample (raw->size + 4) needs to be 8 byte aligned,
- * where the 4 corresponds to the 32bit raw->size member that's
- * added to the sample header that userspace sees.
- *
- * Due to the + 4 for the size member: when we copy a report to the
- * userspace facing perf buffer we always copy an additional 4 bytes
- * from the subsequent report to make up for the miss alignment, but
- * when a report is at the end of the gpu mapped buffer we need to
- * read 4 bytes past the end of the buffer.
- */
- bo = i915_gem_alloc_object(dev_priv->dev, OA_BUFFER_SIZE + PAGE_SIZE);
- if (bo == NULL) {
- DRM_ERROR("Failed to allocate OA buffer\n");
- ret = -ENOMEM;
- goto unlock;
- }
- dev_priv->oa_pmu.oa_buffer.obj = bo;
-
- ret = i915_gem_object_set_cache_level(bo, I915_CACHE_LLC);
+ ret = alloc_obj(dev_priv, &bo);
if (ret)
- goto err_unref;
+ return ret;
- /* PreHSW required 512K alignment, HSW requires 16M */
- ret = i915_gem_obj_ggtt_pin(bo, SZ_16M, 0);
- if (ret)
- goto err_unref;
+ dev_priv->oa_pmu.oa_buffer.obj = bo;
dev_priv->oa_pmu.oa_buffer.gtt_offset = i915_gem_obj_ggtt_offset(bo);
dev_priv->oa_pmu.oa_buffer.addr = vmap_oa_buffer(bo);
@@ -309,14 +353,31 @@ static int init_oa_buffer(struct perf_event *event)
dev_priv->oa_pmu.oa_buffer.gtt_offset,
dev_priv->oa_pmu.oa_buffer.addr);
- goto unlock;
+ return 0;
+}
-err_unref:
- drm_gem_object_unreference(&bo->base);
+static int init_oa_rcs_buffer(struct perf_event *event)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(event->pmu, typeof(*dev_priv), oa_pmu.pmu);
+ struct drm_i915_gem_object *bo;
+ int ret;
-unlock:
- mutex_unlock(&dev_priv->dev->struct_mutex);
- return ret;
+ BUG_ON(dev_priv->oa_pmu.oa_rcs_buffer.obj);
+
+ ret = alloc_obj(dev_priv, &bo);
+ if (ret)
+ return ret;
+
+ dev_priv->oa_pmu.oa_rcs_buffer.obj = bo;
+ dev_priv->oa_pmu.oa_rcs_buffer.gtt_offset =
+ i915_gem_obj_ggtt_offset(bo);
+ dev_priv->oa_pmu.oa_rcs_buffer.addr = vmap_oa_buffer(bo);
+
+ DRM_DEBUG_DRIVER("OA RCS Buffer initialized, vaddr = %p",
+ dev_priv->oa_pmu.oa_rcs_buffer.addr);
+
+ return 0;
}
static enum hrtimer_restart hrtimer_sample(struct hrtimer *hrtimer)
@@ -439,11 +500,28 @@ static int i915_oa_event_init(struct perf_event *event)
/* To avoid the complexity of having to accurately filter
* counter snapshots and marshal to the appropriate client
* we currently only allow exclusive access */
- if (dev_priv->oa_pmu.oa_buffer.obj)
+ spin_lock(&dev_priv->oa_pmu.lock);
+ if (dev_priv->oa_pmu.oa_buffer.obj) {
+ spin_unlock(&dev_priv->oa_pmu.lock);
return -EBUSY;
+ }
+ spin_unlock(&dev_priv->oa_pmu.lock);
+
+ /*
+ * In case of multiple context mode, we need to check for
+ * CAP_SYS_ADMIN capability as we need to profile all the running
+ * contexts
+ */
+ if (oa_attr.multiple_context_mode) {
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ dev_priv->oa_pmu.multiple_ctx_mode = true;
+ }
report_format = oa_attr.format;
dev_priv->oa_pmu.oa_buffer.format = report_format;
+ if (oa_attr.multiple_context_mode)
+ dev_priv->oa_pmu.oa_rcs_buffer.format = report_format;
dev_priv->oa_pmu.metrics_set = oa_attr.metrics_set;
if (IS_HASWELL(dev_priv->dev)) {
@@ -457,6 +535,9 @@ static int i915_oa_event_init(struct perf_event *event)
return -EINVAL;
dev_priv->oa_pmu.oa_buffer.format_size = snapshot_size;
+ if (oa_attr.multiple_context_mode)
+ dev_priv->oa_pmu.oa_rcs_buffer.format_size =
+ snapshot_size;
if (oa_attr.metrics_set > I915_OA_METRICS_SET_MAX)
return -EINVAL;
@@ -465,6 +546,7 @@ static int i915_oa_event_init(struct perf_event *event)
return -ENODEV;
}
+
/* Since we are limited to an exponential scale for
* programming the OA sampling period we don't allow userspace
* to pass a precise attr.sample_period. */
@@ -528,6 +610,12 @@ static int i915_oa_event_init(struct perf_event *event)
if (ret)
return ret;
+ if (oa_attr.multiple_context_mode) {
+ ret = init_oa_rcs_buffer(event);
+ if (ret)
+ return ret;
+ }
+
BUG_ON(dev_priv->oa_pmu.exclusive_event);
dev_priv->oa_pmu.exclusive_event = event;
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 9d866e8..dcf7c87 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -92,7 +92,8 @@ typedef struct _drm_i915_oa_attr {
__u32 ctx_id;
__u64 single_context : 1,
- __reserved_1 : 63;
+ multiple_context_mode:1,
+ __reserved_1:62;
} drm_i915_oa_attr_t;
/* Header for PERF_RECORD_DEVICE type events */
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 3/8] drm/i915: Add mechanism for forwarding CS based OA counter snapshots through perf
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
2015-08-05 5:52 ` [RFC 1/8] drm/i915: Introduce global id for contexts sourab.gupta
2015-08-05 5:52 ` [RFC 2/8] drm/i915: Introduce mode for capture of multi ctx OA reports synchronized with RCS sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
2015-08-05 5:52 ` [RFC 4/8] drm/i915: Forward periodic and CS based OA reports sorted acc to timestamps sourab.gupta
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
This patch adds the mechanism for forwarding the CS based OA snapshots
through the perf event interface.
The OA snapshots will be captured in a gem buffer object. The metadata
information (ctx global id, as of now) pertaining to snapshot is maintained
in a list, which has offsets into the gem buffer object for each snapshot
captured.
Each snapshot collected is forwarded as a separate perf sample. The perf
sample will have raw OA report followed by metadata information pertaining
to that sample. The size of the OA report is the one specified during
event init.
In order to track whether the gpu has completed processing the node, a
field pertaining to corresponding gem request is added. The request is
expected to be referenced whenever the gpu command is submitted.
While forwarding the samples, we check whether the gem request is completed
and dereference the corresponding request. The need to dereference the
request necessitates a worker here, which will be scheduled when the
hrtimer triggers.
While flushing the samples, we have to wait for the requests already
scheduled, before forwarding the samples. This wait is in a lockless
fashion.
v2: Changes here pertaining to (as suggested by Chris):
- Forwarding functionality implemented in a separate fn. The work item
(scheduled from hrtimer/event stop) would be calling that function.
The event flush would directly call this forwarding fn. This meets
the flush semantics.
- use spin_lock instead of spin_lock_irqsave
- Code restructuring & better nomenclature
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 11 +++
drivers/gpu/drm/i915/i915_oa_perf.c | 145 +++++++++++++++++++++++++++++++++++-
include/uapi/drm/i915_drm.h | 5 ++
3 files changed, 160 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 050bdda..87e7cf0 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1654,6 +1654,13 @@ struct i915_oa_reg {
u32 value;
};
+struct i915_oa_rcs_node {
+ struct list_head head;
+ struct drm_i915_gem_request *req;
+ u32 offset;
+ u32 ctx_id;
+};
+
extern const struct i915_oa_reg i915_oa_3d_mux_config_hsw[];
extern const int i915_oa_3d_mux_config_hsw_len;
extern const struct i915_oa_reg i915_oa_3d_b_counter_config_hsw[];
@@ -1954,7 +1961,11 @@ struct drm_i915_private {
u8 *addr;
int format;
int format_size;
+ u32 node_size;
+ u32 node_count;
} oa_rcs_buffer;
+ struct list_head node_list;
+ struct work_struct forward_work;
} oa_pmu;
#endif
diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c
index fd0c3a0..3948b45 100644
--- a/drivers/gpu/drm/i915/i915_oa_perf.c
+++ b/drivers/gpu/drm/i915/i915_oa_perf.c
@@ -58,6 +58,14 @@ static u32 forward_oa_snapshots(struct drm_i915_private *dev_priv,
u8 *snapshot;
u32 taken;
+ /*
+ * Schedule a worker to forward the RCS based OA reports collected.
+ * A worker is needed since it requires device mutex to be taken
+ * which can't be done here because of atomic context
+ */
+ if (dev_priv->oa_pmu.multiple_ctx_mode)
+ schedule_work(&dev_priv->oa_pmu.forward_work);
+
head -= dev_priv->oa_pmu.oa_buffer.gtt_offset;
tail -= dev_priv->oa_pmu.oa_buffer.gtt_offset;
@@ -165,6 +173,119 @@ static void flush_oa_snapshots(struct drm_i915_private *dev_priv,
spin_unlock_irqrestore(&dev_priv->oa_pmu.oa_buffer.flush_lock, flags);
}
+static int i915_oa_rcs_wait_gpu(struct drm_i915_private *dev_priv)
+{
+ struct i915_oa_rcs_node *last_entry = NULL;
+ int ret = 0;
+
+ /*
+ * Wait for the last scheduled request to complete. This would
+ * implicitly wait for the prior submitted requests. The refcount
+ * of the requests is not decremented here.
+ */
+ spin_lock(&dev_priv->oa_pmu.lock);
+
+ if (!list_empty(&dev_priv->oa_pmu.node_list)) {
+ last_entry = list_last_entry(&dev_priv->oa_pmu.node_list,
+ struct i915_oa_rcs_node, head);
+ }
+ spin_unlock(&dev_priv->oa_pmu.lock);
+
+ if (!last_entry)
+ return 0;
+
+ ret = __i915_wait_request(last_entry->req, atomic_read(
+ &dev_priv->gpu_error.reset_counter),
+ true, NULL, NULL);
+ if (ret) {
+ DRM_ERROR("failed to wait\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
+ struct i915_oa_rcs_node *node)
+{
+ struct perf_sample_data data;
+ struct perf_event *event = dev_priv->oa_pmu.exclusive_event;
+ int format_size, snapshot_size;
+ u8 *snapshot;
+ struct drm_i915_oa_node_ctx_id *ctx_info;
+ struct perf_raw_record raw;
+
+ format_size = dev_priv->oa_pmu.oa_rcs_buffer.format_size;
+ snapshot_size = format_size + sizeof(*ctx_info);
+ snapshot = dev_priv->oa_pmu.oa_rcs_buffer.addr + node->offset;
+
+ ctx_info = (struct drm_i915_oa_node_ctx_id *)(snapshot + format_size);
+ ctx_info->ctx_id = node->ctx_id;
+
+ perf_sample_data_init(&data, 0, event->hw.last_period);
+
+ /* Note: the raw sample consists of a u32 size member and raw data. The
+ * combined size of these two fields is required to be 8 byte aligned.
+ * The size of raw data field is assumed to be 8 byte aligned already.
+ * Therefore, adding 4 bytes to the total size here. We can't use
+ * BUILD_BUG_ON here as snapshot size is derived at runtime.
+ */
+ raw.size = snapshot_size + 4;
+ raw.data = snapshot;
+
+ data.raw = &raw;
+
+ perf_event_overflow(event, &data, &dev_priv->oa_pmu.dummy_regs);
+}
+
+/*
+ * Routine to forward the samples to perf. This may be called from the event
+ * flush and worker thread. This function may sleep, hence can't be called from
+ * atomic contexts directly.
+ */
+static void forward_oa_rcs_snapshots(struct drm_i915_private *dev_priv)
+{
+ struct i915_oa_rcs_node *entry, *next;
+ LIST_HEAD(deferred_list_free);
+ int ret;
+
+ list_for_each_entry_safe
+ (entry, next, &dev_priv->oa_pmu.node_list, head) {
+ if (!i915_gem_request_completed(entry->req, true))
+ break;
+
+ forward_one_oa_rcs_sample(dev_priv, entry);
+
+ spin_lock(&dev_priv->oa_pmu.lock);
+ list_move_tail(&entry->head, &deferred_list_free);
+ spin_unlock(&dev_priv->oa_pmu.lock);
+ }
+
+ ret = i915_mutex_lock_interruptible(dev_priv->dev);
+ if (ret)
+ return;
+ while (!list_empty(&deferred_list_free)) {
+ entry = list_first_entry(&deferred_list_free,
+ struct i915_oa_rcs_node, head);
+ i915_gem_request_unreference(entry->req);
+ list_del(&entry->head);
+ kfree(entry);
+ }
+ mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
+/*
+ * Work fn to forward the snapshots. The forwarding of samples is trigged from
+ * hrtimer and event_stop (both atomic contexts). The forward function may
+ * sleep, hence the need for worker.
+ */
+static void forward_oa_rcs_work_fn(struct work_struct *__work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(__work, typeof(*dev_priv), oa_pmu.forward_work);
+
+ forward_oa_rcs_snapshots(dev_priv);
+}
+
static void
oa_rcs_buffer_destroy(struct drm_i915_private *i915)
{
@@ -361,7 +482,7 @@ static int init_oa_rcs_buffer(struct perf_event *event)
struct drm_i915_private *dev_priv =
container_of(event->pmu, typeof(*dev_priv), oa_pmu.pmu);
struct drm_i915_gem_object *bo;
- int ret;
+ int ret, node_size;
BUG_ON(dev_priv->oa_pmu.oa_rcs_buffer.obj);
@@ -373,6 +494,16 @@ static int init_oa_rcs_buffer(struct perf_event *event)
dev_priv->oa_pmu.oa_rcs_buffer.gtt_offset =
i915_gem_obj_ggtt_offset(bo);
dev_priv->oa_pmu.oa_rcs_buffer.addr = vmap_oa_buffer(bo);
+ INIT_LIST_HEAD(&dev_priv->oa_pmu.node_list);
+
+ node_size = dev_priv->oa_pmu.oa_rcs_buffer.format_size +
+ sizeof(struct drm_i915_oa_node_ctx_id);
+
+ /* node size has to be aligned to 64 bytes, since only 64 byte aligned
+ * addresses can be given to OA unit for dumping OA reports */
+ node_size = ALIGN(node_size, 64);
+ dev_priv->oa_pmu.oa_rcs_buffer.node_size = node_size;
+ dev_priv->oa_pmu.oa_rcs_buffer.node_count = bo->base.size / node_size;
DRM_DEBUG_DRIVER("OA RCS Buffer initialized, vaddr = %p",
dev_priv->oa_pmu.oa_rcs_buffer.addr);
@@ -846,7 +977,14 @@ static int i915_oa_event_flush(struct perf_event *event)
if (event->attr.sample_period) {
struct drm_i915_private *i915 =
container_of(event->pmu, typeof(*i915), oa_pmu.pmu);
+ int ret;
+ if (i915->oa_pmu.multiple_ctx_mode) {
+ ret = i915_oa_rcs_wait_gpu(i915);
+ if (ret)
+ return ret;
+ forward_oa_rcs_snapshots(i915);
+ }
flush_oa_snapshots(i915, true);
}
@@ -942,6 +1080,8 @@ void i915_oa_pmu_register(struct drm_device *dev)
hrtimer_init(&i915->oa_pmu.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
i915->oa_pmu.timer.function = hrtimer_sample;
+ INIT_WORK(&i915->oa_pmu.forward_work, forward_oa_rcs_work_fn);
+
spin_lock_init(&i915->oa_pmu.lock);
i915->oa_pmu.pmu.capabilities = PERF_PMU_CAP_IS_DEVICE;
@@ -971,6 +1111,9 @@ void i915_oa_pmu_unregister(struct drm_device *dev)
if (i915->oa_pmu.pmu.event_init == NULL)
return;
+ if (i915->oa_pmu.multiple_ctx_mode)
+ cancel_work_sync(&i915->oa_pmu.forward_work);
+
unregister_sysctl_table(i915->oa_pmu.sysctl_header);
perf_pmu_unregister(&i915->oa_pmu.pmu);
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index dcf7c87..e97b2fd 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -123,6 +123,11 @@ enum drm_i915_oa_event_type {
I915_OA_RECORD_MAX, /* non-ABI */
};
+struct drm_i915_oa_node_ctx_id {
+ __u32 ctx_id;
+ __u32 pad;
+};
+
/* Each region is a minimum of 16k, and there are at most 255 of them.
*/
#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 4/8] drm/i915: Forward periodic and CS based OA reports sorted acc to timestamps
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
` (2 preceding siblings ...)
2015-08-05 5:52 ` [RFC 3/8] drm/i915: Add mechanism for forwarding CS based OA counter snapshots through perf sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
2015-08-05 5:52 ` [RFC 5/8] drm/i915: Handle event stop and destroy for commands in flight sourab.gupta
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
The periodic reports and the RCS based reports are collected in two
separate buffers. While forwarding to userspace, these have to be sent to
single perf event ringbuffer. From a userspace perspective, it is good to
have the reports in the single buffer in order to their timestamps.
This patch addresses this problem by forwarding the periodic OA reports
with a lower timestamp, whenever we are forwarding the Command streamer
based report.
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_oa_perf.c | 40 ++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c
index 3948b45..ab58c46 100644
--- a/drivers/gpu/drm/i915/i915_oa_perf.c
+++ b/drivers/gpu/drm/i915/i915_oa_perf.c
@@ -48,8 +48,7 @@ static void forward_one_oa_snapshot_to_event(struct drm_i915_private *dev_priv,
}
static u32 forward_oa_snapshots(struct drm_i915_private *dev_priv,
- u32 head,
- u32 tail)
+ u32 head, u32 tail, u64 gpu_ts)
{
struct perf_event *exclusive_event = dev_priv->oa_pmu.exclusive_event;
int snapshot_size = dev_priv->oa_pmu.oa_buffer.format_size;
@@ -58,14 +57,6 @@ static u32 forward_oa_snapshots(struct drm_i915_private *dev_priv,
u8 *snapshot;
u32 taken;
- /*
- * Schedule a worker to forward the RCS based OA reports collected.
- * A worker is needed since it requires device mutex to be taken
- * which can't be done here because of atomic context
- */
- if (dev_priv->oa_pmu.multiple_ctx_mode)
- schedule_work(&dev_priv->oa_pmu.forward_work);
-
head -= dev_priv->oa_pmu.oa_buffer.gtt_offset;
tail -= dev_priv->oa_pmu.oa_buffer.gtt_offset;
@@ -75,12 +66,19 @@ static u32 forward_oa_snapshots(struct drm_i915_private *dev_priv,
*/
while ((taken = OA_TAKEN(tail, head))) {
+ u64 snapshot_ts;
+
/* The tail increases in 64 byte increments, not in
* format_size steps. */
if (taken < snapshot_size)
break;
snapshot = oa_buf_base + (head & mask);
+
+ snapshot_ts = *(u64 *)(snapshot + 4);
+ if (snapshot_ts > gpu_ts)
+ break;
+
head += snapshot_size;
/* We currently only allow exclusive access to the counters
@@ -122,7 +120,7 @@ static void log_oa_status(struct drm_i915_private *dev_priv,
}
static void flush_oa_snapshots(struct drm_i915_private *dev_priv,
- bool skip_if_flushing)
+ bool skip_if_flushing, u64 gpu_ts)
{
unsigned long flags;
u32 oastatus2;
@@ -165,7 +163,7 @@ static void flush_oa_snapshots(struct drm_i915_private *dev_priv,
GEN7_OASTATUS1_REPORT_LOST));
}
- head = forward_oa_snapshots(dev_priv, head, tail);
+ head = forward_oa_snapshots(dev_priv, head, tail, gpu_ts);
I915_WRITE(GEN7_OASTATUS2, (head & GEN7_OASTATUS2_HEAD_MASK) |
GEN7_OASTATUS2_GGTT);
@@ -213,6 +211,7 @@ static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
u8 *snapshot;
struct drm_i915_oa_node_ctx_id *ctx_info;
struct perf_raw_record raw;
+ u64 snapshot_ts;
format_size = dev_priv->oa_pmu.oa_rcs_buffer.format_size;
snapshot_size = format_size + sizeof(*ctx_info);
@@ -221,6 +220,10 @@ static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
ctx_info = (struct drm_i915_oa_node_ctx_id *)(snapshot + format_size);
ctx_info->ctx_id = node->ctx_id;
+ /* Flush the periodic snapshots till the ts of this OA report */
+ snapshot_ts = *(u64 *)(snapshot + 4);
+ flush_oa_snapshots(dev_priv, true, snapshot_ts);
+
perf_sample_data_init(&data, 0, event->hw.last_period);
/* Note: the raw sample consists of a u32 size member and raw data. The
@@ -516,7 +519,10 @@ static enum hrtimer_restart hrtimer_sample(struct hrtimer *hrtimer)
struct drm_i915_private *i915 =
container_of(hrtimer, typeof(*i915), oa_pmu.timer);
- flush_oa_snapshots(i915, true);
+ if (i915->oa_pmu.multiple_ctx_mode)
+ schedule_work(&i915->oa_pmu.forward_work);
+ else
+ flush_oa_snapshots(i915, true, U64_MAX);
hrtimer_forward_now(hrtimer, ns_to_ktime(PERIOD));
return HRTIMER_RESTART;
@@ -944,7 +950,9 @@ static void i915_oa_event_stop(struct perf_event *event, int flags)
if (event->attr.sample_period) {
hrtimer_cancel(&dev_priv->oa_pmu.timer);
- flush_oa_snapshots(dev_priv, false);
+ if (dev_priv->oa_pmu.multiple_ctx_mode)
+ schedule_work(&dev_priv->oa_pmu.forward_work);
+ flush_oa_snapshots(dev_priv, false, U64_MAX);
}
event->hw.state = PERF_HES_STOPPED;
@@ -984,8 +992,8 @@ static int i915_oa_event_flush(struct perf_event *event)
if (ret)
return ret;
forward_oa_rcs_snapshots(i915);
- }
- flush_oa_snapshots(i915, true);
+ } else
+ flush_oa_snapshots(i915, true, U64_MAX);
}
return 0;
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 5/8] drm/i915: Handle event stop and destroy for commands in flight
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
` (3 preceding siblings ...)
2015-08-05 5:52 ` [RFC 4/8] drm/i915: Forward periodic and CS based OA reports sorted acc to timestamps sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
2015-08-05 5:52 ` [RFC 6/8] drm/i915: Insert commands for capture of OA counters in the ring sourab.gupta
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
In the periodic OA sampling mode, the event stop would stop forwarding
samples to userspace, and disables OA synchronously. The buffer is
destroyed eventually in event destroy callback. But when we have in flight
RPC commands scheduled on GPU (like in this case), the handling of OA
disabling and buffer destruction has to take those into account. This patch
handles the event stop & destroy conditions after accounting for GPU
commands in flight using the OA unit.
Now, the event stop would just set the event state, and stop forwarding
data to userspace. From userspace perspective, for all purposes, the event
sampling is stopped. This is true for periodic OA samples also. The OA unit
is not disabled here, since there may be RPC commands scheduled on GPU.
A subsequent event start (without event destroy) would start forwarding
samples again.
The event destroy releases the local copy of the RCS buffer. But since, it
is expected that the active reference of buffer is taken while inserting
commands, we can rest assured that buffer is freed up only after GPU is
done with it.
Still there is a need to schedule a worker from event destroy, because we
need to do some further stuff listed below (in this order)
- free up request references
- disable OA unit
- dereference periodic OA buffer (as this is not managed by active ref)
- runtime_pm_put + forcewake_put
The ideal solution here would be to have a callback when the last request
is finished on GPU, so that we can do this stuff there (WIP:Chris'
retire-notification mechanism). Till the time, an async worker thread
will do.
A subsequent event init would have to wait for previously submitted RPC
commands to complete or return -EBUSY. Currently, for the sake of
simplicity, we are returning -EBUSY.
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 11 ++-
drivers/gpu/drm/i915/i915_oa_perf.c | 162 +++++++++++++++++++++++++++++-------
2 files changed, 143 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 87e7cf0..d355691 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1654,10 +1654,18 @@ struct i915_oa_reg {
u32 value;
};
+enum i915_oa_event_state {
+ I915_OA_EVENT_INIT,
+ I915_OA_EVENT_STARTED,
+ I915_OA_EVENT_STOP_IN_PROGRESS,
+ I915_OA_EVENT_STOPPED,
+};
+
struct i915_oa_rcs_node {
struct list_head head;
struct drm_i915_gem_request *req;
u32 offset;
+ bool discard;
u32 ctx_id;
};
@@ -1935,7 +1943,7 @@ struct drm_i915_private {
struct perf_event *exclusive_event;
struct intel_context *specific_ctx;
- bool event_active;
+ enum i915_oa_event_state event_state;
bool periodic;
bool multiple_ctx_mode;
@@ -1966,6 +1974,7 @@ struct drm_i915_private {
} oa_rcs_buffer;
struct list_head node_list;
struct work_struct forward_work;
+ struct work_struct event_destroy_work;
} oa_pmu;
#endif
diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c
index ab58c46..554a9fa 100644
--- a/drivers/gpu/drm/i915/i915_oa_perf.c
+++ b/drivers/gpu/drm/i915/i915_oa_perf.c
@@ -83,7 +83,7 @@ static u32 forward_oa_snapshots(struct drm_i915_private *dev_priv,
/* We currently only allow exclusive access to the counters
* so only have one event to forward too... */
- if (dev_priv->oa_pmu.event_active)
+ if (dev_priv->oa_pmu.event_state == I915_OA_EVENT_STARTED)
forward_one_oa_snapshot_to_event(dev_priv, snapshot,
exclusive_event);
}
@@ -202,6 +202,21 @@ static int i915_oa_rcs_wait_gpu(struct drm_i915_private *dev_priv)
return 0;
}
+static void i915_oa_rcs_release_request_ref(struct drm_i915_private *dev_priv)
+{
+ struct i915_oa_rcs_node *entry, *next;
+
+ list_for_each_entry_safe
+ (entry, next, &dev_priv->oa_pmu.node_list, head) {
+ i915_gem_request_unreference__unlocked(entry->req);
+
+ spin_lock(&dev_priv->oa_pmu.lock);
+ list_del(&entry->head);
+ spin_unlock(&dev_priv->oa_pmu.lock);
+ kfree(entry);
+ }
+}
+
static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
struct i915_oa_rcs_node *node)
{
@@ -256,7 +271,8 @@ static void forward_oa_rcs_snapshots(struct drm_i915_private *dev_priv)
if (!i915_gem_request_completed(entry->req, true))
break;
- forward_one_oa_rcs_sample(dev_priv, entry);
+ if (!entry->discard)
+ forward_one_oa_rcs_sample(dev_priv, entry);
spin_lock(&dev_priv->oa_pmu.lock);
list_move_tail(&entry->head, &deferred_list_free);
@@ -286,6 +302,13 @@ static void forward_oa_rcs_work_fn(struct work_struct *__work)
struct drm_i915_private *dev_priv =
container_of(__work, typeof(*dev_priv), oa_pmu.forward_work);
+ spin_lock(&dev_priv->oa_pmu.lock);
+ if (dev_priv->oa_pmu.event_state != I915_OA_EVENT_STARTED) {
+ spin_unlock(&dev_priv->oa_pmu.lock);
+ return;
+ }
+ spin_unlock(&dev_priv->oa_pmu.lock);
+
forward_oa_rcs_snapshots(dev_priv);
}
@@ -326,19 +349,90 @@ static void i915_oa_event_destroy(struct perf_event *event)
{
struct drm_i915_private *dev_priv =
container_of(event->pmu, typeof(*dev_priv), oa_pmu.pmu);
- unsigned long lock_flags;
WARN_ON(event->parent);
- /* Stop updating oacontrol via _oa_context_pin_[un]notify()... */
- spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
+ if (dev_priv->oa_pmu.multiple_ctx_mode) {
+ cancel_work_sync(&dev_priv->oa_pmu.forward_work);
+ schedule_work(&dev_priv->oa_pmu.event_destroy_work);
+
+ BUG_ON(dev_priv->oa_pmu.exclusive_event != event);
+ dev_priv->oa_pmu.exclusive_event = NULL;
+
+ /* We can deference our local copy of rcs buffer here, since
+ * an active reference of buffer would be taken while
+ * inserting commands. So the buffer would be freed up only
+ * after GPU is done with it.
+ */
+ oa_rcs_buffer_destroy(dev_priv);
+ } else {
+ /* Stop updating oacontrol via _oa_context_[un]pin_notify() */
+ spin_lock(&dev_priv->oa_pmu.lock);
+ dev_priv->oa_pmu.specific_ctx = NULL;
+ spin_unlock(&dev_priv->oa_pmu.lock);
+
+ /* Don't let the compiler start resetting OA, PM and clock
+ * gating state before we've stopped update_oacontrol()
+ */
+ barrier();
+
+ BUG_ON(dev_priv->oa_pmu.exclusive_event != event);
+ dev_priv->oa_pmu.exclusive_event = NULL;
+
+ oa_buffer_destroy(dev_priv);
+
+ I915_WRITE(GEN6_UCGCTL1, (I915_READ(GEN6_UCGCTL1) &
+ ~GEN6_CSUNIT_CLOCK_GATE_DISABLE));
+ I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) |
+ GEN7_DOP_CLOCK_GATE_ENABLE));
+
+ I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) &
+ ~GT_NOA_ENABLE));
+
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+ intel_runtime_pm_put(dev_priv);
+ dev_priv->oa_pmu.event_state = I915_OA_EVENT_INIT;
+ }
+}
+
+static void i915_oa_rcs_event_destroy_work(struct work_struct *__work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(__work, typeof(*dev_priv),
+ oa_pmu.event_destroy_work);
+ int ret;
+
+ ret = i915_oa_rcs_wait_gpu(dev_priv);
+ if (ret)
+ goto out;
+
+ i915_oa_rcs_release_request_ref(dev_priv);
+
+out:
+ /* Stop updating oacontrol via _oa_context_[un]pin_notify() */
+ spin_lock(&dev_priv->oa_pmu.lock);
dev_priv->oa_pmu.specific_ctx = NULL;
- spin_unlock_irqrestore(&dev_priv->oa_pmu.lock, lock_flags);
+ spin_unlock(&dev_priv->oa_pmu.lock);
+
+ /* Disable OA unit */
+ I915_WRITE(GEN7_OACONTROL, 0);
- /* Don't let the compiler start resetting OA, PM and clock gating
- * state before we've stopped update_oacontrol()
+ /* The periodic OA buffer has to be destroyed here, since
+ * this can be done only after OA unit is disabled. There is no active
+ * reference tracking mechanism for periodic OA buffer. So we can only
+ * dereference it in the worker after we've disabled OA unit (which we
+ * can do after we're sure to have completed the in flight GPU cmds)
*/
- barrier();
+ /* TODO: Once we have callbacks in place on completion of request
+ * (i.e. when retire-notification patches land), we can take the active
+ * reference on LRI request(submitted for disabling OA) during event
+ * stop/destroy, and perform these actions, in the callback instead of
+ * work fn
+ */
+
+ oa_buffer_destroy(dev_priv);
+
+ spin_lock(&dev_priv->oa_pmu.lock);
I915_WRITE(GEN6_UCGCTL1, (I915_READ(GEN6_UCGCTL1) &
~GEN6_CSUNIT_CLOCK_GATE_DISABLE));
@@ -348,16 +442,10 @@ static void i915_oa_event_destroy(struct perf_event *event)
I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) &
~GT_NOA_ENABLE));
- if (dev_priv->oa_pmu.multiple_ctx_mode)
- oa_rcs_buffer_destroy(dev_priv);
-
- oa_buffer_destroy(dev_priv);
-
- BUG_ON(dev_priv->oa_pmu.exclusive_event != event);
- dev_priv->oa_pmu.exclusive_event = NULL;
-
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
intel_runtime_pm_put(dev_priv);
+ dev_priv->oa_pmu.event_state = I915_OA_EVENT_INIT;
+ spin_unlock(&dev_priv->oa_pmu.lock);
}
static int alloc_obj(struct drm_i915_private *dev_priv,
@@ -638,7 +726,8 @@ static int i915_oa_event_init(struct perf_event *event)
* counter snapshots and marshal to the appropriate client
* we currently only allow exclusive access */
spin_lock(&dev_priv->oa_pmu.lock);
- if (dev_priv->oa_pmu.oa_buffer.obj) {
+ if (dev_priv->oa_pmu.oa_buffer.obj ||
+ dev_priv->oa_pmu.event_state != I915_OA_EVENT_INIT) {
spin_unlock(&dev_priv->oa_pmu.lock);
return -EBUSY;
}
@@ -803,7 +892,8 @@ static void update_oacontrol(struct drm_i915_private *dev_priv)
{
BUG_ON(!spin_is_locked(&dev_priv->oa_pmu.lock));
- if (dev_priv->oa_pmu.event_active) {
+ if ((dev_priv->oa_pmu.event_state == I915_OA_EVENT_STARTED) ||
+ (dev_priv->oa_pmu.event_state == I915_OA_EVENT_STOP_IN_PROGRESS)) {
unsigned long ctx_id = 0;
bool pinning_ok = false;
@@ -913,7 +1003,7 @@ static void i915_oa_event_start(struct perf_event *event, int flags)
spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
- dev_priv->oa_pmu.event_active = true;
+ dev_priv->oa_pmu.event_state = I915_OA_EVENT_STARTED;
update_oacontrol(dev_priv);
/* Reset the head ptr to ensure we don't forward reports relating
@@ -940,14 +1030,6 @@ static void i915_oa_event_stop(struct perf_event *event, int flags)
container_of(event->pmu, typeof(*dev_priv), oa_pmu.pmu);
unsigned long lock_flags;
- spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
-
- dev_priv->oa_pmu.event_active = false;
- update_oacontrol(dev_priv);
-
- mmiowb();
- spin_unlock_irqrestore(&dev_priv->oa_pmu.lock, lock_flags);
-
if (event->attr.sample_period) {
hrtimer_cancel(&dev_priv->oa_pmu.timer);
if (dev_priv->oa_pmu.multiple_ctx_mode)
@@ -955,6 +1037,23 @@ static void i915_oa_event_stop(struct perf_event *event, int flags)
flush_oa_snapshots(dev_priv, false, U64_MAX);
}
+ if (dev_priv->oa_pmu.multiple_ctx_mode) {
+ struct i915_oa_rcs_node *entry;
+
+ spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
+
+ dev_priv->oa_pmu.event_state = I915_OA_EVENT_STOP_IN_PROGRESS;
+ list_for_each_entry(entry, &dev_priv->oa_pmu.node_list, head)
+ entry->discard = true;
+
+ spin_unlock_irqrestore(&dev_priv->oa_pmu.lock, lock_flags);
+ } else {
+ spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
+ dev_priv->oa_pmu.event_state = I915_OA_EVENT_STOPPED;
+ update_oacontrol(dev_priv);
+ mmiowb();
+ spin_unlock_irqrestore(&dev_priv->oa_pmu.lock, lock_flags);
+ }
event->hw.state = PERF_HES_STOPPED;
}
@@ -1089,10 +1188,13 @@ void i915_oa_pmu_register(struct drm_device *dev)
i915->oa_pmu.timer.function = hrtimer_sample;
INIT_WORK(&i915->oa_pmu.forward_work, forward_oa_rcs_work_fn);
+ INIT_WORK(&i915->oa_pmu.event_destroy_work,
+ i915_oa_rcs_event_destroy_work);
spin_lock_init(&i915->oa_pmu.lock);
i915->oa_pmu.pmu.capabilities = PERF_PMU_CAP_IS_DEVICE;
+ i915->oa_pmu.event_state = I915_OA_EVENT_INIT;
/* Effectively disallow opening an event with a specific pid
* since we aren't interested in processes running on the cpu...
@@ -1119,8 +1221,10 @@ void i915_oa_pmu_unregister(struct drm_device *dev)
if (i915->oa_pmu.pmu.event_init == NULL)
return;
- if (i915->oa_pmu.multiple_ctx_mode)
+ if (i915->oa_pmu.multiple_ctx_mode) {
cancel_work_sync(&i915->oa_pmu.forward_work);
+ cancel_work_sync(&i915->oa_pmu.event_destroy_work);
+ }
unregister_sysctl_table(i915->oa_pmu.sysctl_header);
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 6/8] drm/i915: Insert commands for capture of OA counters in the ring
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
` (4 preceding siblings ...)
2015-08-05 5:52 ` [RFC 5/8] drm/i915: Handle event stop and destroy for commands in flight sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
2015-08-05 5:52 ` [RFC 7/8] drm/i915: Add support for having pid output with OA report sourab.gupta
2015-08-05 5:52 ` [RFC 8/8] drm/i915: Add support to add execbuffer tags to OA counter reports sourab.gupta
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
This patch adds the routines which insert commands for capturing OA
snapshots into the ringbuffer of RCS engine.
The command MI_REPORT_PERF_COUNT can be used to capture snapshots of OA
counters, which is inserted at BB boundaries.
While inserting the commands, we keep a reference of associated request.
This will be released when we are forwarding the samples to userspace
(or when the event is being destroyed).
Also, an active reference of the destination buffer is taken here, so that
we can be assured that the buffer is freed up only after GPU is done with
it, even if the local reference of the buffer is released.
v2: Changes (as suggested by Chris):
- Passing in 'request' struct for emit report function
- Removed multiple calls to i915_gem_obj_to_ggtt(). Keeping hold of
pinned vma from start and using when required.
- Better nomenclature, and error handling.
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 13 +++++
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 ++
drivers/gpu/drm/i915/i915_oa_perf.c | 87 ++++++++++++++++++++++++++++++
3 files changed, 104 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d355691..5c15e30 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1661,6 +1661,11 @@ enum i915_oa_event_state {
I915_OA_EVENT_STOPPED,
};
+enum i915_profile_mode {
+ I915_PROFILE_OA = 0,
+ I915_PROFILE_MAX,
+};
+
struct i915_oa_rcs_node {
struct list_head head;
struct drm_i915_gem_request *req;
@@ -1966,6 +1971,7 @@ struct drm_i915_private {
struct {
struct drm_i915_gem_object *obj;
u32 gtt_offset;
+ struct i915_vma *vma;
u8 *addr;
int format;
int format_size;
@@ -1976,6 +1982,9 @@ struct drm_i915_private {
struct work_struct forward_work;
struct work_struct event_destroy_work;
} oa_pmu;
+
+ void (*emit_profiling_data[I915_PROFILE_MAX])
+ (struct drm_i915_gem_request *req, u32 global_ctx_id);
#endif
/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
@@ -3156,6 +3165,8 @@ void i915_oa_context_pin_notify(struct drm_i915_private *dev_priv,
struct intel_context *context);
void i915_oa_context_unpin_notify(struct drm_i915_private *dev_priv,
struct intel_context *context);
+void i915_emit_profiling_data(struct drm_i915_gem_request *req,
+ u32 global_ctx_id);
#else
static inline void
i915_oa_context_pin_notify(struct drm_i915_private *dev_priv,
@@ -3163,6 +3174,8 @@ i915_oa_context_pin_notify(struct drm_i915_private *dev_priv,
static inline void
i915_oa_context_unpin_notify(struct drm_i915_private *dev_priv,
struct intel_context *context) {}
+void i915_emit_profiling_data(struct drm_i915_gem_request *req,
+ u32 global_ctx_id) {};
#endif
/* i915_gem_evict.c */
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 3336e1c..e58b10d 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -1317,6 +1317,8 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
goto error;
}
+ i915_emit_profiling_data(intel_ring_get_request(ring), ctx->global_id);
+
exec_len = args->batch_len;
if (cliprects) {
for (i = 0; i < args->num_cliprects; i++) {
@@ -1339,6 +1341,8 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
return ret;
}
+ i915_emit_profiling_data(intel_ring_get_request(ring), ctx->global_id);
+
trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags);
i915_gem_execbuffer_move_to_active(vmas, ring);
diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c
index 554a9fa..e3bc8e0 100644
--- a/drivers/gpu/drm/i915/i915_oa_perf.c
+++ b/drivers/gpu/drm/i915/i915_oa_perf.c
@@ -25,6 +25,86 @@ static int hsw_perf_format_sizes[] = {
64 /* C4_B8_HSW */
};
+void i915_emit_profiling_data(struct drm_i915_gem_request *req,
+ u32 global_ctx_id)
+{
+ struct intel_engine_cs *ring = req->ring;
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ int i;
+
+ for (i = I915_PROFILE_OA; i < I915_PROFILE_MAX; i++) {
+ if (dev_priv->emit_profiling_data[i])
+ dev_priv->emit_profiling_data[i](req, global_ctx_id);
+ }
+}
+
+/*
+ * Emits the commands to capture OA perf report, into the Render CS
+ */
+static void i915_oa_emit_perf_report(struct drm_i915_gem_request *req,
+ u32 global_ctx_id)
+{
+ struct intel_engine_cs *ring = req->ring;
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ struct drm_i915_gem_object *obj = dev_priv->oa_pmu.oa_rcs_buffer.obj;
+ struct i915_oa_rcs_node *entry;
+ unsigned long lock_flags;
+ u32 addr = 0;
+ int ret;
+
+ /* OA counters are only supported on the render ring */
+ if (ring->id != RCS)
+ return;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (entry == NULL) {
+ DRM_ERROR("alloc failed\n");
+ return;
+ }
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret) {
+ kfree(entry);
+ return;
+ }
+
+ entry->ctx_id = global_ctx_id;
+ i915_gem_request_assign(&entry->req, ring->outstanding_lazy_request);
+
+ spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
+ if (list_empty(&dev_priv->oa_pmu.node_list))
+ entry->offset = 0;
+ else {
+ struct i915_oa_rcs_node *last_entry;
+ int max_offset = dev_priv->oa_pmu.oa_rcs_buffer.node_count *
+ dev_priv->oa_pmu.oa_rcs_buffer.node_size;
+
+ last_entry = list_last_entry(&dev_priv->oa_pmu.node_list,
+ struct i915_oa_rcs_node, head);
+ entry->offset = last_entry->offset +
+ dev_priv->oa_pmu.oa_rcs_buffer.node_size;
+
+ if (entry->offset > max_offset)
+ entry->offset = 0;
+ }
+ list_add_tail(&entry->head, &dev_priv->oa_pmu.node_list);
+ spin_unlock_irqrestore(&dev_priv->oa_pmu.lock, lock_flags);
+
+ addr = dev_priv->oa_pmu.oa_rcs_buffer.gtt_offset + entry->offset;
+
+ /* addr should be 64 byte aligned */
+ BUG_ON(addr & 0x3f);
+
+ intel_ring_emit(ring, MI_REPORT_PERF_COUNT | (1<<0));
+ intel_ring_emit(ring, addr | MI_REPORT_PERF_COUNT_GGTT);
+ intel_ring_emit(ring, ring->outstanding_lazy_request->seqno);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
+
+ obj->base.write_domain = I915_GEM_DOMAIN_RENDER;
+ i915_vma_move_to_active(dev_priv->oa_pmu.oa_rcs_buffer.vma, ring);
+}
+
static void forward_one_oa_snapshot_to_event(struct drm_i915_private *dev_priv,
u8 *snapshot,
struct perf_event *event)
@@ -324,6 +404,7 @@ oa_rcs_buffer_destroy(struct drm_i915_private *i915)
spin_lock(&i915->oa_pmu.lock);
i915->oa_pmu.oa_rcs_buffer.obj = NULL;
i915->oa_pmu.oa_rcs_buffer.gtt_offset = 0;
+ i915->oa_pmu.oa_rcs_buffer.vma = NULL;
i915->oa_pmu.oa_rcs_buffer.addr = NULL;
spin_unlock(&i915->oa_pmu.lock);
}
@@ -584,6 +665,7 @@ static int init_oa_rcs_buffer(struct perf_event *event)
dev_priv->oa_pmu.oa_rcs_buffer.obj = bo;
dev_priv->oa_pmu.oa_rcs_buffer.gtt_offset =
i915_gem_obj_ggtt_offset(bo);
+ dev_priv->oa_pmu.oa_rcs_buffer.vma = i915_gem_obj_to_ggtt(bo);
dev_priv->oa_pmu.oa_rcs_buffer.addr = vmap_oa_buffer(bo);
INIT_LIST_HEAD(&dev_priv->oa_pmu.node_list);
@@ -1006,6 +1088,10 @@ static void i915_oa_event_start(struct perf_event *event, int flags)
dev_priv->oa_pmu.event_state = I915_OA_EVENT_STARTED;
update_oacontrol(dev_priv);
+ if (dev_priv->oa_pmu.multiple_ctx_mode)
+ dev_priv->emit_profiling_data[I915_PROFILE_OA] =
+ i915_oa_emit_perf_report;
+
/* Reset the head ptr to ensure we don't forward reports relating
* to a previous perf event */
oastatus1 = I915_READ(GEN7_OASTATUS1);
@@ -1042,6 +1128,7 @@ static void i915_oa_event_stop(struct perf_event *event, int flags)
spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
+ dev_priv->emit_profiling_data[I915_PROFILE_OA] = NULL;
dev_priv->oa_pmu.event_state = I915_OA_EVENT_STOP_IN_PROGRESS;
list_for_each_entry(entry, &dev_priv->oa_pmu.node_list, head)
entry->discard = true;
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 7/8] drm/i915: Add support for having pid output with OA report
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
` (5 preceding siblings ...)
2015-08-05 5:52 ` [RFC 6/8] drm/i915: Insert commands for capture of OA counters in the ring sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
2015-08-05 5:52 ` [RFC 8/8] drm/i915: Add support to add execbuffer tags to OA counter reports sourab.gupta
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
This patch introduces flags and adds support for having pid output with the
OA reports generated through the RCS commands.
When the userspace expresses its interest in listening to the pid through
an oa_attr field during event init, the OA reports generated would have an
additional field appended with the pid information. The patches enables
this framework, which can be expanded upon to introduce further fields in
the OA report metadata.
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 3 +++
drivers/gpu/drm/i915/i915_oa_perf.c | 19 ++++++++++++++++++-
include/uapi/drm/i915_drm.h | 8 +++++++-
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5c15e30..6e6f1be 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1672,6 +1672,7 @@ struct i915_oa_rcs_node {
u32 offset;
bool discard;
u32 ctx_id;
+ u32 pid;
};
extern const struct i915_oa_reg i915_oa_3d_mux_config_hsw[];
@@ -1981,6 +1982,8 @@ struct drm_i915_private {
struct list_head node_list;
struct work_struct forward_work;
struct work_struct event_destroy_work;
+#define I915_OA_SAMPLE_PID (1<<0)
+ int sample_info_flags;
} oa_pmu;
void (*emit_profiling_data[I915_PROFILE_MAX])
diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c
index e3bc8e0..f4b8a2b 100644
--- a/drivers/gpu/drm/i915/i915_oa_perf.c
+++ b/drivers/gpu/drm/i915/i915_oa_perf.c
@@ -69,6 +69,8 @@ static void i915_oa_emit_perf_report(struct drm_i915_gem_request *req,
}
entry->ctx_id = global_ctx_id;
+ if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_PID)
+ entry->pid = current->pid;
i915_gem_request_assign(&entry->req, ring->outstanding_lazy_request);
spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
@@ -303,8 +305,9 @@ static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
struct perf_sample_data data;
struct perf_event *event = dev_priv->oa_pmu.exclusive_event;
int format_size, snapshot_size;
- u8 *snapshot;
+ u8 *snapshot, *current_ptr;
struct drm_i915_oa_node_ctx_id *ctx_info;
+ struct drm_i915_oa_node_pid *pid_info;
struct perf_raw_record raw;
u64 snapshot_ts;
@@ -314,6 +317,14 @@ static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
ctx_info = (struct drm_i915_oa_node_ctx_id *)(snapshot + format_size);
ctx_info->ctx_id = node->ctx_id;
+ current_ptr = snapshot + snapshot_size;
+
+ if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_PID) {
+ pid_info = (struct drm_i915_oa_node_pid *)current_ptr;
+ pid_info->pid = node->pid;
+ snapshot_size += sizeof(*pid_info);
+ current_ptr = snapshot + snapshot_size;
+ }
/* Flush the periodic snapshots till the ts of this OA report */
snapshot_ts = *(u64 *)(snapshot + 4);
@@ -672,6 +683,9 @@ static int init_oa_rcs_buffer(struct perf_event *event)
node_size = dev_priv->oa_pmu.oa_rcs_buffer.format_size +
sizeof(struct drm_i915_oa_node_ctx_id);
+ if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_PID)
+ node_size += sizeof(struct drm_i915_oa_node_pid);
+
/* node size has to be aligned to 64 bytes, since only 64 byte aligned
* addresses can be given to OA unit for dumping OA reports */
node_size = ALIGN(node_size, 64);
@@ -824,6 +838,9 @@ static int i915_oa_event_init(struct perf_event *event)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
dev_priv->oa_pmu.multiple_ctx_mode = true;
+ if (oa_attr.sample_pid)
+ dev_priv->oa_pmu.sample_info_flags |=
+ I915_OA_SAMPLE_PID;
}
report_format = oa_attr.format;
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index e97b2fd..65e8297 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -93,7 +93,8 @@ typedef struct _drm_i915_oa_attr {
__u64 single_context : 1,
multiple_context_mode:1,
- __reserved_1:62;
+ sample_pid:1,
+ __reserved_1:61;
} drm_i915_oa_attr_t;
/* Header for PERF_RECORD_DEVICE type events */
@@ -128,6 +129,11 @@ struct drm_i915_oa_node_ctx_id {
__u32 pad;
};
+struct drm_i915_oa_node_pid {
+ __u32 pid;
+ __u32 pad;
+};
+
/* Each region is a minimum of 16k, and there are at most 255 of them.
*/
#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 8/8] drm/i915: Add support to add execbuffer tags to OA counter reports
2015-08-05 5:52 [RFC 0/8] Introduce framework to forward multi context OA snapshots sourab.gupta
` (6 preceding siblings ...)
2015-08-05 5:52 ` [RFC 7/8] drm/i915: Add support for having pid output with OA report sourab.gupta
@ 2015-08-05 5:52 ` sourab.gupta
7 siblings, 0 replies; 11+ messages in thread
From: sourab.gupta @ 2015-08-05 5:52 UTC (permalink / raw)
To: intel-gfx; +Cc: Insoo Woo, Peter Zijlstra, Jabin Wu, Sourab Gupta
From: Sourab Gupta <sourab.gupta@intel.com>
This patch enables userspace to specify tags (per workload), provided via
execbuffer ioctl, which could be added to OA reports, to help associate
reports with the corresponding workloads.
There may be multiple stages within a single context, from a userspace
perspective. An ability is needed to individually associate the OA reports
with their corresponding workloads(execbuffers), which may not be possible
solely with ctx_id or pid information. This patch enables such a mechanism.
In this patch, rsvd2 field of execbuffer arguments is being utilized for
passing the tag. A new bitfield in execbuffer flags is introduced in order
to inform kernel of the tag being passed in execbuffer arguments.
v2: Changes (as suggested by Chris):
- Using upper 32 bits of rsvd1 field for passing tag (as it is a
natural complement to ctx_id which is there in lower 32 bits of rsvd1
- Removed the flags field to inform kernel of tag being passed.
- Better ABI definition.
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 8 +++++---
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 ++++--
drivers/gpu/drm/i915/i915_oa_perf.c | 23 ++++++++++++++++++++---
include/uapi/drm/i915_drm.h | 13 ++++++++++++-
4 files changed, 41 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 6e6f1be..d5d9156 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1673,6 +1673,7 @@ struct i915_oa_rcs_node {
bool discard;
u32 ctx_id;
u32 pid;
+ u32 tag;
};
extern const struct i915_oa_reg i915_oa_3d_mux_config_hsw[];
@@ -1983,11 +1984,12 @@ struct drm_i915_private {
struct work_struct forward_work;
struct work_struct event_destroy_work;
#define I915_OA_SAMPLE_PID (1<<0)
+#define I915_OA_SAMPLE_TAG (1<<1)
int sample_info_flags;
} oa_pmu;
void (*emit_profiling_data[I915_PROFILE_MAX])
- (struct drm_i915_gem_request *req, u32 global_ctx_id);
+ (struct drm_i915_gem_request *req, u32 global_ctx_id, u32 tag);
#endif
/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
@@ -3169,7 +3171,7 @@ void i915_oa_context_pin_notify(struct drm_i915_private *dev_priv,
void i915_oa_context_unpin_notify(struct drm_i915_private *dev_priv,
struct intel_context *context);
void i915_emit_profiling_data(struct drm_i915_gem_request *req,
- u32 global_ctx_id);
+ u32 global_ctx_id, u32 tag);
#else
static inline void
i915_oa_context_pin_notify(struct drm_i915_private *dev_priv,
@@ -3178,7 +3180,7 @@ static inline void
i915_oa_context_unpin_notify(struct drm_i915_private *dev_priv,
struct intel_context *context) {}
void i915_emit_profiling_data(struct drm_i915_gem_request *req,
- u32 global_ctx_id) {};
+ u32 global_ctx_id, u32 tag) {};
#endif
/* i915_gem_evict.c */
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index e58b10d..7f2246f 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -1317,7 +1317,8 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
goto error;
}
- i915_emit_profiling_data(intel_ring_get_request(ring), ctx->global_id);
+ i915_emit_profiling_data(intel_ring_get_request(ring), ctx->global_id,
+ i915_execbuffer2_get_tag(*args));
exec_len = args->batch_len;
if (cliprects) {
@@ -1341,7 +1342,8 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
return ret;
}
- i915_emit_profiling_data(intel_ring_get_request(ring), ctx->global_id);
+ i915_emit_profiling_data(intel_ring_get_request(ring), ctx->global_id,
+ i915_execbuffer2_get_tag(*args));
trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags);
diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c
index f4b8a2b..48591fc 100644
--- a/drivers/gpu/drm/i915/i915_oa_perf.c
+++ b/drivers/gpu/drm/i915/i915_oa_perf.c
@@ -26,7 +26,7 @@ static int hsw_perf_format_sizes[] = {
};
void i915_emit_profiling_data(struct drm_i915_gem_request *req,
- u32 global_ctx_id)
+ u32 global_ctx_id, u32 tag)
{
struct intel_engine_cs *ring = req->ring;
struct drm_i915_private *dev_priv = ring->dev->dev_private;
@@ -34,7 +34,8 @@ void i915_emit_profiling_data(struct drm_i915_gem_request *req,
for (i = I915_PROFILE_OA; i < I915_PROFILE_MAX; i++) {
if (dev_priv->emit_profiling_data[i])
- dev_priv->emit_profiling_data[i](req, global_ctx_id);
+ dev_priv->emit_profiling_data[i](req, global_ctx_id,
+ tag);
}
}
@@ -42,7 +43,7 @@ void i915_emit_profiling_data(struct drm_i915_gem_request *req,
* Emits the commands to capture OA perf report, into the Render CS
*/
static void i915_oa_emit_perf_report(struct drm_i915_gem_request *req,
- u32 global_ctx_id)
+ u32 global_ctx_id, u32 tag)
{
struct intel_engine_cs *ring = req->ring;
struct drm_i915_private *dev_priv = ring->dev->dev_private;
@@ -71,6 +72,8 @@ static void i915_oa_emit_perf_report(struct drm_i915_gem_request *req,
entry->ctx_id = global_ctx_id;
if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_PID)
entry->pid = current->pid;
+ if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_TAG)
+ entry->tag = tag;
i915_gem_request_assign(&entry->req, ring->outstanding_lazy_request);
spin_lock_irqsave(&dev_priv->oa_pmu.lock, lock_flags);
@@ -308,6 +311,7 @@ static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
u8 *snapshot, *current_ptr;
struct drm_i915_oa_node_ctx_id *ctx_info;
struct drm_i915_oa_node_pid *pid_info;
+ struct drm_i915_oa_node_tag *tag_info;
struct perf_raw_record raw;
u64 snapshot_ts;
@@ -326,6 +330,13 @@ static void forward_one_oa_rcs_sample(struct drm_i915_private *dev_priv,
current_ptr = snapshot + snapshot_size;
}
+ if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_TAG) {
+ tag_info = (struct drm_i915_oa_node_tag *)current_ptr;
+ tag_info->tag = node->tag;
+ snapshot_size += sizeof(*tag_info);
+ current_ptr = snapshot + snapshot_size;
+ }
+
/* Flush the periodic snapshots till the ts of this OA report */
snapshot_ts = *(u64 *)(snapshot + 4);
flush_oa_snapshots(dev_priv, true, snapshot_ts);
@@ -686,6 +697,9 @@ static int init_oa_rcs_buffer(struct perf_event *event)
if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_PID)
node_size += sizeof(struct drm_i915_oa_node_pid);
+ if (dev_priv->oa_pmu.sample_info_flags & I915_OA_SAMPLE_TAG)
+ node_size += sizeof(struct drm_i915_oa_node_tag);
+
/* node size has to be aligned to 64 bytes, since only 64 byte aligned
* addresses can be given to OA unit for dumping OA reports */
node_size = ALIGN(node_size, 64);
@@ -841,6 +855,9 @@ static int i915_oa_event_init(struct perf_event *event)
if (oa_attr.sample_pid)
dev_priv->oa_pmu.sample_info_flags |=
I915_OA_SAMPLE_PID;
+ if (oa_attr.sample_tag)
+ dev_priv->oa_pmu.sample_info_flags |=
+ I915_OA_SAMPLE_TAG;
}
report_format = oa_attr.format;
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 65e8297..abe5826 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -94,7 +94,8 @@ typedef struct _drm_i915_oa_attr {
__u64 single_context : 1,
multiple_context_mode:1,
sample_pid:1,
- __reserved_1:61;
+ sample_tag:1,
+ __reserved_1:60;
} drm_i915_oa_attr_t;
/* Header for PERF_RECORD_DEVICE type events */
@@ -134,6 +135,11 @@ struct drm_i915_oa_node_pid {
__u32 pad;
};
+struct drm_i915_oa_node_tag {
+ __u32 tag;
+ __u32 pad;
+};
+
/* Each region is a minimum of 16k, and there are at most 255 of them.
*/
#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
@@ -848,6 +854,11 @@ struct drm_i915_gem_execbuffer2 {
#define i915_execbuffer2_get_context_id(eb2) \
((eb2).rsvd1 & I915_EXEC_CONTEXT_ID_MASK)
+/* upper 32 bits of rsvd1 field contain tag */
+#define I915_EXEC_TAG_MASK (0xffffffff00000000UL)
+#define i915_execbuffer2_get_tag(eb2) \
+ ((eb2).rsvd1 & I915_EXEC_TAG_MASK)
+
struct drm_i915_gem_pin {
/** Handle of the buffer to be pinned. */
__u32 handle;
--
1.8.5.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 11+ messages in thread