memory: Share special empty FlatView

This shares an cached empty FlatView among address spaces. The empty
FV is used every time when a root MR renders into a FV without memory
sections which happens when MR or its children are not enabled or
zero-sized. The empty_view is not NULL to keep the rest of memory
API intact; it also has a dispatch tree for the same reason.

On POWER8 with 255 CPUs, 255 virtio-net, 40 PCI bridges guest this halves
the amount of FlatView's in use (557 -> 260) and dispatch tables
(~800000 -> ~370000). In an unrelated experiment with 112 non-virtio
devices on x86 ("-M pc"), only 4 FlatViews are alive, and about ~2000
are created at startup.

Backports commit 092aa2fc65b7a35121616aad8f39d47b8f921618 from qemu
This commit is contained in:
Alexey Kardashevskiy 2018-03-11 22:23:21 -04:00 committed by Lioncash
parent 20b1bd767f
commit b90333a531
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
18 changed files with 41 additions and 5 deletions

View file

@ -199,6 +199,7 @@ struct uc_struct {
uintptr_t helper_retaddr;
// qemu/memory.c
FlatView *empty_view;
GHashTable *flat_views;
bool global_dirty_log;

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_aarch64
#define unassigned_mem_read unassigned_mem_read_aarch64
#define unassigned_mem_write unassigned_mem_write_aarch64
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_aarch64
#define update_spsel update_spsel_aarch64
#define use_idiv_instructions_rt use_idiv_instructions_rt_aarch64
#define v6_cp_reginfo v6_cp_reginfo_aarch64

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_aarch64eb
#define unassigned_mem_read unassigned_mem_read_aarch64eb
#define unassigned_mem_write unassigned_mem_write_aarch64eb
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_aarch64eb
#define update_spsel update_spsel_aarch64eb
#define use_idiv_instructions_rt use_idiv_instructions_rt_aarch64eb
#define v6_cp_reginfo v6_cp_reginfo_aarch64eb

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_arm
#define unassigned_mem_read unassigned_mem_read_arm
#define unassigned_mem_write unassigned_mem_write_arm
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_arm
#define update_spsel update_spsel_arm
#define use_idiv_instructions_rt use_idiv_instructions_rt_arm
#define v6_cp_reginfo v6_cp_reginfo_arm

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_armeb
#define unassigned_mem_read unassigned_mem_read_armeb
#define unassigned_mem_write unassigned_mem_write_armeb
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_armeb
#define update_spsel update_spsel_armeb
#define use_idiv_instructions_rt use_idiv_instructions_rt_armeb
#define v6_cp_reginfo v6_cp_reginfo_armeb

View file

@ -3004,6 +3004,7 @@ symbols = (
'unassigned_mem_ops',
'unassigned_mem_read',
'unassigned_mem_write',
'unicorn_free_empty_flat_view',
'update_spsel',
'use_idiv_instructions_rt',
'v6_cp_reginfo',

View file

@ -1379,6 +1379,8 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr,
address_space_write(cache->as, cache->xlat + addr, MEMTXATTRS_UNSPECIFIED, buf, len);
}
void unicorn_free_empty_flat_view(struct uc_struct *uc);
#endif
#endif

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_m68k
#define unassigned_mem_read unassigned_mem_read_m68k
#define unassigned_mem_write unassigned_mem_write_m68k
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_m68k
#define update_spsel update_spsel_m68k
#define use_idiv_instructions_rt use_idiv_instructions_rt_m68k
#define v6_cp_reginfo v6_cp_reginfo_m68k

View file

@ -346,6 +346,15 @@ static void flatview_unref(FlatView *view)
}
}
void unicorn_free_empty_flat_view(struct uc_struct *uc)
{
if (!uc->empty_view) {
return;
}
flatview_destroy(uc->empty_view);
}
FlatView *address_space_to_flatview(AddressSpace *as)
{
// Unicorn: atomic_read used instead of atomic_rcu_read
@ -728,7 +737,7 @@ static MemoryRegion *memory_region_get_flatview_root(MemoryRegion *mr)
}
/* Render a memory topology into a list of disjoint absolute ranges. */
static FlatView *generate_memory_topology(MemoryRegion *mr)
static FlatView *generate_memory_topology(struct uc_struct *uc, MemoryRegion *mr)
{
int i;
FlatView *view;
@ -741,14 +750,14 @@ static FlatView *generate_memory_topology(MemoryRegion *mr)
}
flatview_simplify(view);
view->dispatch = address_space_dispatch_new(mr->uc, view);
view->dispatch = address_space_dispatch_new(uc, view);
for (i = 0; i < view->nr; i++) {
MemoryRegionSection mrs =
section_from_flat_range(&view->ranges[i], view);
flatview_add_to_dispatch(view, &mrs);
}
address_space_dispatch_compact(view->dispatch);
g_hash_table_replace(mr->uc->flat_views, mr, view);
g_hash_table_replace(uc->flat_views, mr, view);
return view;
}
@ -838,6 +847,15 @@ static void flatviews_init(struct uc_struct *uc)
uc->flat_views = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
(GDestroyNotify) flatview_unref);
if (!uc->empty_view) {
uc->empty_view = generate_memory_topology(uc, NULL);
/* We keep it alive forever in the global variable. */
flatview_ref(uc->empty_view);
} else {
g_hash_table_replace(uc->flat_views, NULL, uc->empty_view);
flatview_ref(uc->empty_view);
}
}
static void flatviews_reset(struct uc_struct *uc)
@ -858,7 +876,7 @@ static void flatviews_reset(struct uc_struct *uc)
continue;
}
generate_memory_topology(physmr);
generate_memory_topology(uc, physmr);
}
}
@ -915,7 +933,7 @@ static void address_space_update_topology(AddressSpace *as)
flatviews_init(uc);
if (!g_hash_table_lookup(uc->flat_views, physmr)) {
generate_memory_topology(physmr);
generate_memory_topology(uc, physmr);
}
address_space_set_flatview(as);
}

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_mips
#define unassigned_mem_read unassigned_mem_read_mips
#define unassigned_mem_write unassigned_mem_write_mips
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_mips
#define update_spsel update_spsel_mips
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips
#define v6_cp_reginfo v6_cp_reginfo_mips

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_mips64
#define unassigned_mem_read unassigned_mem_read_mips64
#define unassigned_mem_write unassigned_mem_write_mips64
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_mips64
#define update_spsel update_spsel_mips64
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips64
#define v6_cp_reginfo v6_cp_reginfo_mips64

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_mips64el
#define unassigned_mem_read unassigned_mem_read_mips64el
#define unassigned_mem_write unassigned_mem_write_mips64el
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_mips64el
#define update_spsel update_spsel_mips64el
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips64el
#define v6_cp_reginfo v6_cp_reginfo_mips64el

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_mipsel
#define unassigned_mem_read unassigned_mem_read_mipsel
#define unassigned_mem_write unassigned_mem_write_mipsel
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_mipsel
#define update_spsel update_spsel_mipsel
#define use_idiv_instructions_rt use_idiv_instructions_rt_mipsel
#define v6_cp_reginfo v6_cp_reginfo_mipsel

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_powerpc
#define unassigned_mem_read unassigned_mem_read_powerpc
#define unassigned_mem_write unassigned_mem_write_powerpc
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_powerpc
#define update_spsel update_spsel_powerpc
#define use_idiv_instructions_rt use_idiv_instructions_rt_powerpc
#define v6_cp_reginfo v6_cp_reginfo_powerpc

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_sparc
#define unassigned_mem_read unassigned_mem_read_sparc
#define unassigned_mem_write unassigned_mem_write_sparc
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_sparc
#define update_spsel update_spsel_sparc
#define use_idiv_instructions_rt use_idiv_instructions_rt_sparc
#define v6_cp_reginfo v6_cp_reginfo_sparc

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_sparc64
#define unassigned_mem_read unassigned_mem_read_sparc64
#define unassigned_mem_write unassigned_mem_write_sparc64
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_sparc64
#define update_spsel update_spsel_sparc64
#define use_idiv_instructions_rt use_idiv_instructions_rt_sparc64
#define v6_cp_reginfo v6_cp_reginfo_sparc64

View file

@ -80,6 +80,7 @@ static void release_common(void *t)
// Destory flat view hash table
g_hash_table_destroy(s->uc->flat_views);
unicorn_free_empty_flat_view(s->uc);
// TODO(danghvu): these function is not available outside qemu
// so we keep them here instead of outside uc_close.

View file

@ -2998,6 +2998,7 @@
#define unassigned_mem_ops unassigned_mem_ops_x86_64
#define unassigned_mem_read unassigned_mem_read_x86_64
#define unassigned_mem_write unassigned_mem_write_x86_64
#define unicorn_free_empty_flat_view unicorn_free_empty_flat_view_x86_64
#define update_spsel update_spsel_x86_64
#define use_idiv_instructions_rt use_idiv_instructions_rt_x86_64
#define v6_cp_reginfo v6_cp_reginfo_x86_64