Optimize memory handling (#1963)

* optimize ram block handling

Save the last element of the ram_list. This allows to
faster find where to add new elements when they are not
bigger then page size.

* save ram_list freed

this keeps the optimization for find_ram_offset() intact after snapshot
restore.

* cow only clear the tlb of affected pages

* update flatview when possible

Building each flatview new when the memory has changed is quite
expensive when many MemoryRegions are used. This is an issue when using
snapshots.

* update benchmark for new api

* save flatview in context

this avoids rebuilding the flatview when restore a context.

* init context flatview with zero

* address_space_dispatch_clear remove subpage with higher priority

* docutemnt the options for UC_CTL_CONTEXT_MODE

Specialy stress that with UC_CTL_CONTEXT_MEMORY it is not possible to
use the context with a different unicorn object.
This commit is contained in:
PhilippTakacs
2024-10-16 15:51:13 +02:00
committed by GitHub
parent fea3411803
commit e8ca3cbea5
27 changed files with 236 additions and 45 deletions

View File

@@ -957,12 +957,10 @@ void flatview_add_to_dispatch(struct uc_struct *uc, FlatView *fv, MemoryRegionSe
static ram_addr_t find_ram_offset_last(struct uc_struct *uc, ram_addr_t size)
{
RAMBlock *block;
ram_addr_t result = 0;
RAMBlock *block = uc->ram_list.last_block;
RAMBLOCK_FOREACH(block) {
result = MAX(block->offset + block->max_length, result);
}
result = block->offset + block->max_length;
if (result + size > RAM_ADDR_MAX) {
abort();
@@ -1076,18 +1074,26 @@ static void ram_block_add(struct uc_struct *uc, RAMBlock *new_block)
* QLIST (which has an RCU-friendly variant) does not have insertion at
* tail, so save the last element in last_block.
*/
RAMBLOCK_FOREACH(block) {
last_block = block;
if (block->max_length < new_block->max_length) {
break;
if (uc->ram_list.freed || new_block->max_length > uc->target_page_size) {
RAMBLOCK_FOREACH(block) {
last_block = block;
if (block->max_length < new_block->max_length) {
break;
}
}
} else {
last_block = uc->ram_list.last_block;
block = NULL;
}
if (block) {
QLIST_INSERT_BEFORE_RCU(block, new_block, next);
} else if (last_block) {
QLIST_INSERT_AFTER_RCU(last_block, new_block, next);
uc->ram_list.last_block = new_block;
} else { /* list is empty */
QLIST_INSERT_HEAD_RCU(&uc->ram_list.blocks, new_block, next);
uc->ram_list.last_block = new_block;
}
uc->ram_list.mru_block = NULL;
@@ -1165,6 +1171,7 @@ void qemu_ram_free(struct uc_struct *uc, RAMBlock *block)
QLIST_REMOVE_RCU(block, next);
uc->ram_list.mru_block = NULL;
uc->ram_list.freed = true;
uc->ram_list.last_block = NULL;
/* Write list before version */
//smp_wmb();
// call_rcu(block, reclaim_ramblock, rcu);
@@ -1388,6 +1395,7 @@ static subpage_t *subpage_init(struct uc_struct *uc, FlatView *fv, hwaddr base)
memory_region_init_io(fv->root->uc, &mmio->iomem, &subpage_ops, mmio,
TARGET_PAGE_SIZE);
mmio->iomem.subpage = true;
mmio->iomem.priority = uc->snapshot_level;
#if defined(DEBUG_SUBPAGE)
printf("%s: %p base " TARGET_FMT_plx " len %08x\n", __func__,
mmio, base, TARGET_PAGE_SIZE);
@@ -1448,6 +1456,22 @@ AddressSpaceDispatch *address_space_dispatch_new(struct uc_struct *uc, FlatView
return d;
}
void address_space_dispatch_clear(AddressSpaceDispatch *d)
{
MemoryRegionSection *section;
struct uc_struct *uc = d->uc;
while (d->map.sections_nb > 0) {
d->map.sections_nb--;
section = &d->map.sections[d->map.sections_nb];
if (section->mr->priority > uc->snapshot_level) {
phys_section_destroy(section->mr);
}
}
g_free(d->map.sections);
g_free(d->map.nodes);
g_free(d);
}
void address_space_dispatch_free(AddressSpaceDispatch *d)
{
phys_sections_free(&d->map);