From dd684d313e280c3bad2ebb7b33e7688ab5409bc9 Mon Sep 17 00:00:00 2001 From: Alex Xie Date: Tue, 30 May 2017 17:10:16 -0400 Subject: drm/amdgpu: Optimize a function called by every IB sheduling Move several if statements and a loop statment from run time to initialization time. Signed-off-by: Alex Xie Reviewed-by: Chunming Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 6a85db0c0bc3..7d95435fad16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -152,6 +152,36 @@ void amdgpu_ring_undo(struct amdgpu_ring *ring) ring->funcs->end_use(ring); } +/** + * amdgpu_ring_check_compute_vm_bug - check whether this ring has compute vm bug + * + * @adev: amdgpu_device pointer + * @ring: amdgpu_ring structure holding ring information + */ +static void amdgpu_ring_check_compute_vm_bug(struct amdgpu_device *adev, + struct amdgpu_ring *ring) +{ + const struct amdgpu_ip_block *ip_block; + + ring->has_compute_vm_bug = false; + + if (ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE) + /* only compute rings */ + return; + + ip_block = amdgpu_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GFX); + if (!ip_block) + return; + + /* Compute ring has a VM bug for GFX version < 7. + And compute ring has a VM bug for GFX 8 MEC firmware version < 673.*/ + if (ip_block->version->major <= 7) { + ring->has_compute_vm_bug = true; + } else if (ip_block->version->major == 8) + if (adev->gfx.mec_fw_version < 673) + ring->has_compute_vm_bug = true; +} + /** * amdgpu_ring_init - init driver ring struct. * @@ -257,6 +287,9 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, if (amdgpu_debugfs_ring_init(adev, ring)) { DRM_ERROR("Failed to register debugfs file for rings !\n"); } + + amdgpu_ring_check_compute_vm_bug(adev, ring); + return 0; } -- cgit v1.2.1 From 795f2813e628bcf57a69f2dfe413360d14a1d7f4 Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Mon, 6 Mar 2017 16:27:55 -0500 Subject: drm/amdgpu: implement lru amdgpu_queue_mgr policy for compute v4 Use an LRU policy to map usermode rings to HW compute queues. Most compute clients use one queue, and usually the first queue available. This results in poor pipe/queue work distribution when multiple compute apps are running. In most cases pipe 0 queue 0 is the only queue that gets used. In order to better distribute work across multiple HW queues, we adopt a policy to map the usermode ring ids to the LRU HW queue. This fixes a large majority of multi-app compute workloads sharing the same HW queue, even though 7 other queues are available. v2: use ring->funcs->type instead of ring->hw_ip v3: remove amdgpu_queue_mapper_funcs v4: change ring_lru_list_lock to spinlock, grab only once in lru_get() Signed-off-by: Andres Rodriguez Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 63 ++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 7d95435fad16..f1076e3edf53 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -135,6 +135,8 @@ void amdgpu_ring_commit(struct amdgpu_ring *ring) if (ring->funcs->end_use) ring->funcs->end_use(ring); + + amdgpu_ring_lru_touch(ring->adev, ring); } /** @@ -283,6 +285,8 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, } ring->max_dw = max_dw; + INIT_LIST_HEAD(&ring->lru_list); + amdgpu_ring_lru_touch(adev, ring); if (amdgpu_debugfs_ring_init(adev, ring)) { DRM_ERROR("Failed to register debugfs file for rings !\n"); @@ -327,6 +331,65 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring) ring->adev->rings[ring->idx] = NULL; } +static void amdgpu_ring_lru_touch_locked(struct amdgpu_device *adev, + struct amdgpu_ring *ring) +{ + /* list_move_tail handles the case where ring isn't part of the list */ + list_move_tail(&ring->lru_list, &adev->ring_lru_list); +} + +/** + * amdgpu_ring_lru_get - get the least recently used ring for a HW IP block + * + * @adev: amdgpu_device pointer + * @type: amdgpu_ring_type enum + * @ring: output ring + * + * Retrieve the amdgpu_ring structure for the least recently used ring of + * a specific IP block (all asics). + * Returns 0 on success, error on failure. + */ +int amdgpu_ring_lru_get(struct amdgpu_device *adev, int type, + struct amdgpu_ring **ring) +{ + struct amdgpu_ring *entry; + + /* List is sorted in LRU order, find first entry corresponding + * to the desired HW IP */ + *ring = NULL; + spin_lock(&adev->ring_lru_list_lock); + list_for_each_entry(entry, &adev->ring_lru_list, lru_list) { + if (entry->funcs->type == type) { + *ring = entry; + amdgpu_ring_lru_touch_locked(adev, *ring); + break; + } + } + spin_unlock(&adev->ring_lru_list_lock); + + if (!*ring) { + DRM_ERROR("Ring LRU contains no entries for ring type:%d\n", type); + return -EINVAL; + } + + return 0; +} + +/** + * amdgpu_ring_lru_touch - mark a ring as recently being used + * + * @adev: amdgpu_device pointer + * @ring: ring to touch + * + * Move @ring to the tail of the lru list + */ +void amdgpu_ring_lru_touch(struct amdgpu_device *adev, struct amdgpu_ring *ring) +{ + spin_lock(&adev->ring_lru_list_lock); + amdgpu_ring_lru_touch_locked(adev, ring); + spin_unlock(&adev->ring_lru_list_lock); +} + /* * Debugfs info */ -- cgit v1.2.1 From 6065343a116fce16f7523ab10841efd942ce612d Mon Sep 17 00:00:00 2001 From: Andres Rodriguez Date: Fri, 17 Mar 2017 14:30:15 -0400 Subject: drm/amdgpu: guarantee bijective mapping of ring ids for LRU v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on usage patterns, the current LRU policy may create a non-injective mapping between userspace ring ids and kernel rings. This behaviour is undesired as apps that attempt to fill all HW blocks would be unable to reach some of them. This change forces the LRU policy to create bijective mappings only. v2: compress ring_blacklist v3: simplify amdgpu_ring_is_blacklisted() logic Signed-off-by: Andres Rodriguez Reviewed-by: Nicolai Hähnle Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 33 +++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index f1076e3edf53..cef135ef7334 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -338,19 +338,34 @@ static void amdgpu_ring_lru_touch_locked(struct amdgpu_device *adev, list_move_tail(&ring->lru_list, &adev->ring_lru_list); } +static bool amdgpu_ring_is_blacklisted(struct amdgpu_ring *ring, + int *blacklist, int num_blacklist) +{ + int i; + + for (i = 0; i < num_blacklist; i++) { + if (ring->idx == blacklist[i]) + return true; + } + + return false; +} + /** * amdgpu_ring_lru_get - get the least recently used ring for a HW IP block * * @adev: amdgpu_device pointer * @type: amdgpu_ring_type enum + * @blacklist: blacklisted ring ids array + * @num_blacklist: number of entries in @blacklist * @ring: output ring * * Retrieve the amdgpu_ring structure for the least recently used ring of * a specific IP block (all asics). * Returns 0 on success, error on failure. */ -int amdgpu_ring_lru_get(struct amdgpu_device *adev, int type, - struct amdgpu_ring **ring) +int amdgpu_ring_lru_get(struct amdgpu_device *adev, int type, int *blacklist, + int num_blacklist, struct amdgpu_ring **ring) { struct amdgpu_ring *entry; @@ -359,11 +374,15 @@ int amdgpu_ring_lru_get(struct amdgpu_device *adev, int type, *ring = NULL; spin_lock(&adev->ring_lru_list_lock); list_for_each_entry(entry, &adev->ring_lru_list, lru_list) { - if (entry->funcs->type == type) { - *ring = entry; - amdgpu_ring_lru_touch_locked(adev, *ring); - break; - } + if (entry->funcs->type != type) + continue; + + if (amdgpu_ring_is_blacklisted(entry, blacklist, num_blacklist)) + continue; + + *ring = entry; + amdgpu_ring_lru_touch_locked(adev, *ring); + break; } spin_unlock(&adev->ring_lru_list_lock); -- cgit v1.2.1 From e59c020598666ffc22c627910667e44ac2412304 Mon Sep 17 00:00:00 2001 From: Alex Xie Date: Thu, 1 Jun 2017 09:42:59 -0400 Subject: drm/amdgpu: Move compute vm bug logic to amdgpu_vm.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In review, Christian would like to keep the logic inside amdgpu_vm.c with a cost of slightly slower. The loop is still optimized out with this patch. v2: remove the if statement. Now it is not slower. Signed-off-by: Alex Xie Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 32 -------------------------------- 1 file changed, 32 deletions(-) (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index cef135ef7334..75165e07b1cd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -154,36 +154,6 @@ void amdgpu_ring_undo(struct amdgpu_ring *ring) ring->funcs->end_use(ring); } -/** - * amdgpu_ring_check_compute_vm_bug - check whether this ring has compute vm bug - * - * @adev: amdgpu_device pointer - * @ring: amdgpu_ring structure holding ring information - */ -static void amdgpu_ring_check_compute_vm_bug(struct amdgpu_device *adev, - struct amdgpu_ring *ring) -{ - const struct amdgpu_ip_block *ip_block; - - ring->has_compute_vm_bug = false; - - if (ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE) - /* only compute rings */ - return; - - ip_block = amdgpu_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GFX); - if (!ip_block) - return; - - /* Compute ring has a VM bug for GFX version < 7. - And compute ring has a VM bug for GFX 8 MEC firmware version < 673.*/ - if (ip_block->version->major <= 7) { - ring->has_compute_vm_bug = true; - } else if (ip_block->version->major == 8) - if (adev->gfx.mec_fw_version < 673) - ring->has_compute_vm_bug = true; -} - /** * amdgpu_ring_init - init driver ring struct. * @@ -292,8 +262,6 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, DRM_ERROR("Failed to register debugfs file for rings !\n"); } - amdgpu_ring_check_compute_vm_bug(adev, ring); - return 0; } -- cgit v1.2.1