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:
Alexey Kardashevskiy 2018-03-11 21:48:48 -04:00 committed by Lioncash
parent 0d9fe8e20c
commit f2c72dc278
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
5 changed files with 92 additions and 13 deletions

View file

@ -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.

View file

@ -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

View file

@ -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,

View file

@ -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;

View file

@ -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);