From b90333a5317f0d37b9cbbd625e243b50f75bef25 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Sun, 11 Mar 2018 22:23:21 -0400 Subject: [PATCH] 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 --- include/uc_priv.h | 1 + qemu/aarch64.h | 1 + qemu/aarch64eb.h | 1 + qemu/arm.h | 1 + qemu/armeb.h | 1 + qemu/header_gen.py | 1 + qemu/include/exec/memory.h | 2 ++ qemu/m68k.h | 1 + qemu/memory.c | 28 +++++++++++++++++++++++----- qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/powerpc.h | 1 + qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/unicorn_common.h | 1 + qemu/x86_64.h | 1 + 18 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 0a6260e5..056d345a 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -199,6 +199,7 @@ struct uc_struct { uintptr_t helper_retaddr; // qemu/memory.c + FlatView *empty_view; GHashTable *flat_views; bool global_dirty_log; diff --git a/qemu/aarch64.h b/qemu/aarch64.h index f533aa5b..3d0c0761 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -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 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index cd988552..72954163 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -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 diff --git a/qemu/arm.h b/qemu/arm.h index 3c4cf74f..0bf5d18d 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -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 diff --git a/qemu/armeb.h b/qemu/armeb.h index 5e4ab139..84627350 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -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 diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 4256fc15..5facef62 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -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', diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index 917ebcd5..d3eedbe2 100644 --- a/qemu/include/exec/memory.h +++ b/qemu/include/exec/memory.h @@ -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 diff --git a/qemu/m68k.h b/qemu/m68k.h index 0f3d61fc..a5b52c18 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -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 diff --git a/qemu/memory.c b/qemu/memory.c index 3ec68a8e..f7421ee6 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -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); } diff --git a/qemu/mips.h b/qemu/mips.h index c96b56d7..e7d14928 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -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 diff --git a/qemu/mips64.h b/qemu/mips64.h index c86ed637..152b7ff5 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -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 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index abf4687f..392fe9fb 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -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 diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 0d55b9b5..5f1d5b64 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -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 diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 701ea3a9..b54daa89 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -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 diff --git a/qemu/sparc.h b/qemu/sparc.h index 48829b71..50532e52 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -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 diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 06af7c83..41081872 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -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 diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 8b3b6565..cba7f339 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -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. diff --git a/qemu/x86_64.h b/qemu/x86_64.h index f28b0557..233e0ac1 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -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