mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-03 15:55:37 +00:00
memory: Share FlatView's and dispatch trees between address spaces
This allows sharing flat views between address spaces (AS) when the same root memory region is used when creating a new address space. This is done by walking through all ASes and caching one FlatView per a physical root MR (i.e. not aliased). This removes search for duplicates from address_space_init_shareable() as FlatViews are shared elsewhere and keeping as::ref_count correct seems an unnecessary and useless complication. This should cause no change and memory use or boot time yet. Backports commit 967dc9b1194a9281124b2e1ce67b6c3359a2138f from qemu
This commit is contained in:
parent
0d9fe8e20c
commit
f2c72dc278
|
@ -199,6 +199,7 @@ struct uc_struct {
|
|||
uintptr_t helper_retaddr;
|
||||
|
||||
// qemu/memory.c
|
||||
GHashTable *flat_views;
|
||||
bool global_dirty_log;
|
||||
|
||||
/* This is a multi-level map on the virtual address space.
|
||||
|
|
|
@ -55,11 +55,29 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
*
|
||||
* Returns: a hash value corresponding to the key.
|
||||
*/
|
||||
static guint g_direct_hash (gconstpointer v)
|
||||
guint g_direct_hash (gconstpointer v)
|
||||
{
|
||||
return GPOINTER_TO_UINT (v);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_direct_equal:
|
||||
* @v1: a key.
|
||||
* @v2: a key to compare with @v1.
|
||||
*
|
||||
* Compares two #gpointer arguments and returns %TRUE if they are equal.
|
||||
* It can be passed to g_hash_table_new() as the @key_equal_func
|
||||
* parameter, when using pointers as keys in a #GHashTable.
|
||||
*
|
||||
* Returns: %TRUE if the two keys match.
|
||||
*/
|
||||
gboolean
|
||||
g_direct_equal (gconstpointer v1,
|
||||
gconstpointer v2)
|
||||
{
|
||||
return v1 == v2;
|
||||
}
|
||||
|
||||
// g_str_hash() is lifted glib-2.28.0/glib/gstring.c
|
||||
/**
|
||||
* g_str_hash:
|
||||
|
@ -1438,6 +1456,27 @@ void g_hash_table_insert (GHashTable *hash_table,
|
|||
g_hash_table_insert_internal (hash_table, key, value, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_hash_table_replace:
|
||||
* @hash_table: a #GHashTable.
|
||||
* @key: a key to insert.
|
||||
* @value: the value to associate with the key.
|
||||
*
|
||||
* Inserts a new key and value into a #GHashTable similar to
|
||||
* g_hash_table_insert(). The difference is that if the key already exists
|
||||
* in the #GHashTable, it gets replaced by the new key. If you supplied a
|
||||
* @value_destroy_func when creating the #GHashTable, the old value is freed
|
||||
* using that function. If you supplied a @key_destroy_func when creating the
|
||||
* #GHashTable, the old key is freed using that function.
|
||||
**/
|
||||
void
|
||||
g_hash_table_replace (GHashTable *hash_table,
|
||||
gpointer key,
|
||||
gpointer value)
|
||||
{
|
||||
g_hash_table_insert_internal (hash_table, key, value, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* g_hash_table_lookup_node:
|
||||
* @hash_table: our #GHashTable
|
||||
|
|
|
@ -57,6 +57,9 @@ typedef void (*GFunc)(gpointer data, gpointer user_data);
|
|||
typedef gint (*GCompareFunc)(gconstpointer v1, gconstpointer v2);
|
||||
typedef void (*GDestroyNotify)(gpointer data);
|
||||
|
||||
guint g_direct_hash(gconstpointer v);
|
||||
gboolean g_direct_equal(gconstpointer v1, gconstpointer v2);
|
||||
|
||||
guint g_str_hash(gconstpointer v);
|
||||
gboolean g_str_equal(gconstpointer v1, gconstpointer v2);
|
||||
gboolean g_str_has_suffix(const gchar *str, const gchar *prefix);
|
||||
|
@ -137,6 +140,7 @@ void g_hash_table_destroy(GHashTable *hash_table);
|
|||
gpointer g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, gpointer user_data);
|
||||
void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, gpointer user_data);
|
||||
void g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value);
|
||||
void g_hash_table_replace(GHashTable *hash_table, gpointer key, gpointer value);
|
||||
gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointer key);
|
||||
GHashTable *g_hash_table_new(GHashFunc hash_func, GEqualFunc key_equal_func);
|
||||
GHashTable *g_hash_table_new_full(GHashFunc hash_func, GEqualFunc key_equal_func,
|
||||
|
|
|
@ -720,6 +720,7 @@ static FlatView *generate_memory_topology(MemoryRegion *mr)
|
|||
flatview_add_to_dispatch(view, &mrs);
|
||||
}
|
||||
address_space_dispatch_compact(view->dispatch);
|
||||
g_hash_table_replace(mr->uc->flat_views, mr, view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -801,11 +802,47 @@ static void address_space_update_topology_pass(AddressSpace *as,
|
|||
}
|
||||
|
||||
|
||||
static void address_space_update_topology(AddressSpace *as)
|
||||
static void flatviews_init(struct uc_struct *uc)
|
||||
{
|
||||
if (uc->flat_views) {
|
||||
return;
|
||||
}
|
||||
|
||||
uc->flat_views = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
|
||||
(GDestroyNotify) flatview_unref);
|
||||
}
|
||||
|
||||
static void flatviews_reset(struct uc_struct *uc)
|
||||
{
|
||||
AddressSpace *as;
|
||||
|
||||
if (uc->flat_views) {
|
||||
g_hash_table_unref(uc->flat_views);
|
||||
uc->flat_views = NULL;
|
||||
}
|
||||
flatviews_init(uc);
|
||||
|
||||
/* Render unique FVs */
|
||||
QTAILQ_FOREACH(as, &uc->address_spaces, address_spaces_link) {
|
||||
MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
|
||||
|
||||
if (g_hash_table_lookup(uc->flat_views, physmr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
generate_memory_topology(physmr);
|
||||
}
|
||||
}
|
||||
|
||||
static void address_space_set_flatview(AddressSpace *as)
|
||||
{
|
||||
FlatView *old_view = address_space_get_flatview(as);
|
||||
MemoryRegion *physmr = memory_region_get_flatview_root(old_view->root);
|
||||
FlatView *new_view = generate_memory_topology(physmr);
|
||||
MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
|
||||
FlatView *new_view = g_hash_table_lookup(as->uc->flat_views, physmr);
|
||||
|
||||
assert(new_view);
|
||||
|
||||
flatview_ref(new_view);
|
||||
|
||||
if (!QTAILQ_EMPTY(&as->listeners)) {
|
||||
address_space_update_topology_pass(as, old_view, new_view, false);
|
||||
|
@ -843,10 +880,12 @@ void memory_region_transaction_commit(struct uc_struct *uc)
|
|||
--uc->memory_region_transaction_depth;
|
||||
if (!uc->memory_region_transaction_depth) {
|
||||
if (uc->memory_region_update_pending) {
|
||||
flatviews_reset(uc);
|
||||
|
||||
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
|
||||
|
||||
QTAILQ_FOREACH(as, &uc->address_spaces, address_spaces_link) {
|
||||
address_space_update_topology(as);
|
||||
address_space_set_flatview(as);
|
||||
}
|
||||
|
||||
MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
|
||||
|
@ -1863,13 +1902,6 @@ AddressSpace *address_space_init_shareable(struct uc_struct *uc, MemoryRegion *r
|
|||
{
|
||||
AddressSpace *as;
|
||||
|
||||
QTAILQ_FOREACH(as, &uc->address_spaces, address_spaces_link) {
|
||||
if (root == as->root && as->malloced) {
|
||||
as->ref_count++;
|
||||
return as;
|
||||
}
|
||||
}
|
||||
|
||||
as = g_malloc0(sizeof *as);
|
||||
address_space_init(uc, as, root, name);
|
||||
as->malloced = true;
|
||||
|
|
|
@ -78,6 +78,9 @@ static void release_common(void *t)
|
|||
tcg_pool_reset(s);
|
||||
g_hash_table_destroy(s->helpers);
|
||||
|
||||
// Destory flat view hash table
|
||||
g_hash_table_destroy(s->uc->flat_views);
|
||||
|
||||
// TODO(danghvu): these function is not available outside qemu
|
||||
// so we keep them here instead of outside uc_close.
|
||||
free_address_spaces(s->uc);
|
||||
|
|
Loading…
Reference in a new issue