[PATCH] drm/radeon: Adding UVD handle basis fps estimation v2

Christian König deathsimple at vodafone.de
Thu Aug 7 04:33:30 PDT 2014


From: Marco A Benatto <marco.antonio.780 at gmail.com>

Adding a Frames Per Second estimation logic on UVD handles
when it has being used. This estimation is per handle basis
and will help on DPM profile calculation.

v2 (chk): fix timestamp type, move functions around and
          cleanup code a bit.

Signed-off-by: Marco A Benatto <marco.antonio.780 at gmail.com>
Signed-off-by: Christian König <christian.koenig at amd.com>
---
 drivers/gpu/drm/radeon/radeon.h     | 10 ++++++
 drivers/gpu/drm/radeon/radeon_uvd.c | 64 +++++++++++++++++++++++++++++++++----
 2 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 9e1732e..e92f6cb 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1617,6 +1617,15 @@ int radeon_pm_get_type_index(struct radeon_device *rdev,
 #define RADEON_UVD_STACK_SIZE	(1024*1024)
 #define RADEON_UVD_HEAP_SIZE	(1024*1024)
 
+#define RADEON_UVD_FPS_EVENTS_MAX 8
+#define RADEON_UVD_DEFAULT_FPS 60
+
+struct radeon_uvd_fps {
+	uint64_t	timestamp;
+	uint8_t		event_index;
+	uint8_t 	events[RADEON_UVD_FPS_EVENTS_MAX];
+};
+
 struct radeon_uvd {
 	struct radeon_bo	*vcpu_bo;
 	void			*cpu_addr;
@@ -1626,6 +1635,7 @@ struct radeon_uvd {
 	struct drm_file		*filp[RADEON_MAX_UVD_HANDLES];
 	unsigned		img_size[RADEON_MAX_UVD_HANDLES];
 	struct delayed_work	idle_work;
+	struct radeon_uvd_fps	fps_info[RADEON_MAX_UVD_HANDLES];
 };
 
 int radeon_uvd_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index 6bf55ec..ef5667a 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -237,6 +237,51 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo)
 	rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
 }
 
+static void radeon_uvd_fps_clear_events(struct radeon_device *rdev, int idx)
+{
+	struct radeon_uvd_fps *fps = &rdev->uvd.fps_info[idx];
+	unsigned i;
+
+	fps->timestamp = jiffies_64;
+	fps->event_index = 0;
+	for (i = 0; i < RADEON_UVD_FPS_EVENTS_MAX; i++)
+		fps->events[i] = 0;
+}
+
+static void radeon_uvd_fps_note_event(struct radeon_device *rdev, int idx)
+{
+	struct radeon_uvd_fps *fps = &rdev->uvd.fps_info[idx];
+	uint64_t timestamp = jiffies_64;
+	unsigned rate = 0;
+
+	uint8_t index = fps->event_index++;
+	fps->event_index %= RADEON_UVD_FPS_EVENTS_MAX;
+
+	rate = div64_u64(HZ, max(timestamp - fps->timestamp, 1ULL));
+
+	fps->timestamp = timestamp;
+	fps->events[index] = min(rate, 120u);
+}
+
+static unsigned radeon_uvd_estimate_fps(struct radeon_device *rdev, int idx)
+{
+	struct radeon_uvd_fps *fps = &rdev->uvd.fps_info[idx];
+	unsigned i, valid = 0, count = 0;
+
+	for (i = 0; i < RADEON_UVD_FPS_EVENTS_MAX; i++) {
+		/* We should ignore zero values */
+		if (fps->events[i] != 0) {
+			count += fps->events[i];
+			valid++;
+		}
+	}
+
+	if (valid > 0)
+		return count / valid;
+	else
+		return RADEON_UVD_DEFAULT_FPS;
+}
+
 void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
 {
 	int i, r;
@@ -419,8 +464,10 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
 
 	/* create or decode, validate the handle */
 	for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
-		if (atomic_read(&p->rdev->uvd.handles[i]) == handle)
+		if (atomic_read(&p->rdev->uvd.handles[i]) == handle) {
+			radeon_uvd_fps_note_event(p->rdev, i);
 			return 0;
+		}
 	}
 
 	/* handle not found try to alloc a new one */
@@ -428,6 +475,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
 		if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) {
 			p->rdev->uvd.filp[i] = p->filp;
 			p->rdev->uvd.img_size[i] = img_size;
+			radeon_uvd_fps_clear_events(p->rdev, i);
 			return 0;
 		}
 	}
@@ -763,7 +811,7 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
 static void radeon_uvd_count_handles(struct radeon_device *rdev,
 				     unsigned *sd, unsigned *hd)
 {
-	unsigned i;
+	unsigned i, fps_rate = 0;
 
 	*sd = 0;
 	*hd = 0;
@@ -772,10 +820,13 @@ static void radeon_uvd_count_handles(struct radeon_device *rdev,
 		if (!atomic_read(&rdev->uvd.handles[i]))
 			continue;
 
-		if (rdev->uvd.img_size[i] >= 720*576)
-			++(*hd);
-		else
-			++(*sd);
+		fps_rate = radeon_uvd_estimate_fps(rdev, i);
+
+		if (rdev->uvd.img_size[i] >= 720*576) {
+			(*hd) += fps_rate > 30 ? 1 : 2;
+		} else {
+			(*sd) += fps_rate > 30 ? 1 : 2;
+		}
 	}
 }
 
@@ -805,6 +856,7 @@ void radeon_uvd_note_usage(struct radeon_device *rdev)
 	set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
 					    msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
 
+
 	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
 		unsigned hd = 0, sd = 0;
 		radeon_uvd_count_handles(rdev, &sd, &hd);
-- 
1.9.1



More information about the dri-devel mailing list