vkd3d: Use reader-writer spinlock in view map.

The common case is that we find an entry, so taking a writer lock should
be the rare case. We need to optimize for the case where the application
hammers the view map with e.g. buffers.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
Hans-Kristian Arntzen 2020-12-02 11:45:09 +01:00
parent b3024365d0
commit 5f8659f4bb
2 changed files with 32 additions and 24 deletions

View File

@ -22,6 +22,7 @@
#include <float.h>
#include "vkd3d_private.h"
#include "vkd3d_rw_spinlock.h"
#include "hashmap.h"
#define VKD3D_NULL_SRV_FORMAT DXGI_FORMAT_R8G8B8A8_UNORM
@ -1520,11 +1521,7 @@ static bool vkd3d_view_entry_compare(const void *key, const struct hash_map_entr
HRESULT vkd3d_view_map_init(struct vkd3d_view_map *view_map)
{
int rc;
if ((rc = pthread_mutex_init(&view_map->mutex, NULL)))
return hresult_from_errno(rc);
view_map->spinlock = 0;
hash_map_init(&view_map->map, &vkd3d_view_entry_hash, &vkd3d_view_entry_compare, sizeof(struct vkd3d_view_entry));
return S_OK;
}
@ -1544,8 +1541,6 @@ void vkd3d_view_map_destroy(struct vkd3d_view_map *view_map, struct d3d12_device
}
hash_map_clear(&view_map->map);
pthread_mutex_destroy(&view_map->mutex);
}
static struct vkd3d_view *vkd3d_view_create(enum vkd3d_view_type type);
@ -1557,23 +1552,23 @@ struct vkd3d_view *vkd3d_view_map_create_view(struct vkd3d_view_map *view_map,
struct d3d12_device *device, const struct vkd3d_view_key *key)
{
struct vkd3d_view_entry entry, *e;
struct vkd3d_view *redundant_view;
struct vkd3d_view *view;
bool success;
int rc;
if ((rc = pthread_mutex_lock(&view_map->mutex)))
{
ERR("Failed to lock mutex, rc %d.\n", rc);
return NULL;
}
/* In the steady state, we will be reading existing entries from a view map.
* Prefer read-write spinlocks here to reduce contention as much as possible. */
rw_spinlock_acquire_read(&view_map->spinlock);
if ((e = (struct vkd3d_view_entry *)hash_map_find(&view_map->map, key)))
{
view = e->view;
pthread_mutex_unlock(&view_map->mutex);
rw_spinlock_release_read(&view_map->spinlock);
return view;
}
rw_spinlock_release_read(&view_map->spinlock);
switch (key->view_type)
{
case VKD3D_VIEW_TYPE_BUFFER:
@ -1596,23 +1591,36 @@ struct vkd3d_view *vkd3d_view_map_create_view(struct vkd3d_view_map *view_map,
}
if (!success)
{
pthread_mutex_unlock(&view_map->mutex);
return NULL;
}
entry.key = *key;
entry.view = view;
if (!hash_map_insert(&view_map->map, key, &entry.entry))
rw_spinlock_acquire_write(&view_map->spinlock);
if (!(e = (struct vkd3d_view_entry *)hash_map_insert(&view_map->map, key, &entry.entry)))
ERR("Failed to insert view into hash map.\n");
/* If we start emitting too many typed SRVs, we will eventually crash on NV, since
* VkBufferView objects appear to consume GPU resources. */
if ((view_map->map.used_count % 1024) == 0)
ERR("Intense view map pressure! Got %u views in hash map %p.\n", view_map->map.used_count, &view_map->map);
if (e->view != view)
{
/* We yielded on the insert because another thread came in-between, and allocated a new hash map entry.
* This can happen between releasing reader lock, and acquiring writer lock. */
redundant_view = view;
view = e->view;
rw_spinlock_release_write(&view_map->spinlock);
vkd3d_view_decref(redundant_view, device);
}
else
{
/* If we start emitting too many typed SRVs, we will eventually crash on NV, since
* VkBufferView objects appear to consume GPU resources. */
if ((view_map->map.used_count % 1024) == 0)
ERR("Intense view map pressure! Got %u views in hash map %p.\n", view_map->map.used_count, &view_map->map);
view = e->view;
rw_spinlock_release_write(&view_map->spinlock);
}
pthread_mutex_unlock(&view_map->mutex);
return view;
}

View File

@ -470,7 +470,7 @@ struct d3d12_sparse_info
struct vkd3d_view_map
{
pthread_mutex_t mutex;
spinlock_t spinlock;
struct hash_map map;
};