Maintain all the dirty runs in a linked list for each arena
This commit is contained in:
parent
dd03242da9
commit
04d60a132b
@ -89,6 +89,9 @@ struct arena_chunk_map_s {
|
|||||||
}; /* union { ... }; */
|
}; /* union { ... }; */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Linkage for list of dirty runs. */
|
||||||
|
ql_elm(arena_chunk_map_t) dr_link;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run address (or size) and various flags are stored together. The bit
|
* Run address (or size) and various flags are stored together. The bit
|
||||||
* layout looks like (assuming 32-bit system):
|
* layout looks like (assuming 32-bit system):
|
||||||
@ -333,6 +336,9 @@ struct arena_s {
|
|||||||
/* Tree of dirty-page-containing chunks this arena manages. */
|
/* Tree of dirty-page-containing chunks this arena manages. */
|
||||||
arena_chunk_tree_t chunks_dirty;
|
arena_chunk_tree_t chunks_dirty;
|
||||||
|
|
||||||
|
/* List of dirty runs this arena manages. */
|
||||||
|
arena_chunk_mapelms_t runs_dirty;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In order to avoid rapid chunk allocation/deallocation when an arena
|
* In order to avoid rapid chunk allocation/deallocation when an arena
|
||||||
* oscillates right on the cusp of needing a new chunk, cache the most
|
* oscillates right on the cusp of needing a new chunk, cache the most
|
||||||
|
47
src/arena.c
47
src/arena.c
@ -394,6 +394,7 @@ static void
|
|||||||
arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind,
|
arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind,
|
||||||
size_t flag_dirty, size_t need_pages)
|
size_t flag_dirty, size_t need_pages)
|
||||||
{
|
{
|
||||||
|
arena_chunk_map_t *mapelm;
|
||||||
size_t total_pages, rem_pages;
|
size_t total_pages, rem_pages;
|
||||||
|
|
||||||
total_pages = arena_mapbits_unallocated_size_get(chunk, run_ind) >>
|
total_pages = arena_mapbits_unallocated_size_get(chunk, run_ind) >>
|
||||||
@ -404,6 +405,11 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind,
|
|||||||
rem_pages = total_pages - need_pages;
|
rem_pages = total_pages - need_pages;
|
||||||
|
|
||||||
arena_avail_remove(arena, chunk, run_ind, total_pages, true, true);
|
arena_avail_remove(arena, chunk, run_ind, total_pages, true, true);
|
||||||
|
if (flag_dirty != 0) {
|
||||||
|
/* If the run is dirty, it must be in the dirty list. */
|
||||||
|
mapelm = arena_mapp_get(chunk, run_ind);
|
||||||
|
ql_remove(&arena->runs_dirty, mapelm, dr_link);
|
||||||
|
}
|
||||||
arena_cactive_update(arena, need_pages, 0);
|
arena_cactive_update(arena, need_pages, 0);
|
||||||
arena->nactive += need_pages;
|
arena->nactive += need_pages;
|
||||||
|
|
||||||
@ -416,6 +422,14 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind,
|
|||||||
arena_mapbits_unallocated_set(chunk,
|
arena_mapbits_unallocated_set(chunk,
|
||||||
run_ind+total_pages-1, (rem_pages << LG_PAGE),
|
run_ind+total_pages-1, (rem_pages << LG_PAGE),
|
||||||
flag_dirty);
|
flag_dirty);
|
||||||
|
mapelm = arena_mapp_get(chunk, run_ind+need_pages);
|
||||||
|
/*
|
||||||
|
* Append the trailing run at the end of the dirty list.
|
||||||
|
* We could also insert the run at the original place.
|
||||||
|
* Let us consider this later.
|
||||||
|
*/
|
||||||
|
ql_elm_new(mapelm, dr_link);
|
||||||
|
ql_tail_insert(&arena->runs_dirty, mapelm, dr_link);
|
||||||
} else {
|
} else {
|
||||||
arena_mapbits_unallocated_set(chunk, run_ind+need_pages,
|
arena_mapbits_unallocated_set(chunk, run_ind+need_pages,
|
||||||
(rem_pages << LG_PAGE),
|
(rem_pages << LG_PAGE),
|
||||||
@ -701,6 +715,11 @@ arena_chunk_alloc(arena_t *arena)
|
|||||||
/* Insert the run into the runs_avail tree. */
|
/* Insert the run into the runs_avail tree. */
|
||||||
arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias,
|
arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias,
|
||||||
false, false);
|
false, false);
|
||||||
|
if (arena_mapbits_dirty_get(chunk, map_bias) != 0) {
|
||||||
|
arena_chunk_map_t *mapelm = arena_mapp_get(chunk, map_bias);
|
||||||
|
ql_elm_new(mapelm, dr_link);
|
||||||
|
ql_tail_insert(&arena->runs_dirty, mapelm, dr_link);
|
||||||
|
}
|
||||||
|
|
||||||
return (chunk);
|
return (chunk);
|
||||||
}
|
}
|
||||||
@ -739,6 +758,7 @@ arena_chunk_dalloc_huge(arena_t *arena, void *chunk, size_t size)
|
|||||||
static void
|
static void
|
||||||
arena_chunk_dalloc(arena_t *arena, arena_chunk_t *chunk)
|
arena_chunk_dalloc(arena_t *arena, arena_chunk_t *chunk)
|
||||||
{
|
{
|
||||||
|
|
||||||
assert(arena_mapbits_allocated_get(chunk, map_bias) == 0);
|
assert(arena_mapbits_allocated_get(chunk, map_bias) == 0);
|
||||||
assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0);
|
assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0);
|
||||||
assert(arena_mapbits_unallocated_size_get(chunk, map_bias) ==
|
assert(arena_mapbits_unallocated_size_get(chunk, map_bias) ==
|
||||||
@ -754,6 +774,10 @@ arena_chunk_dalloc(arena_t *arena, arena_chunk_t *chunk)
|
|||||||
*/
|
*/
|
||||||
arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias,
|
arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias,
|
||||||
false, false);
|
false, false);
|
||||||
|
if (arena_mapbits_dirty_get(chunk, map_bias) != 0) {
|
||||||
|
arena_chunk_map_t *mapelm = arena_mapp_get(chunk, map_bias);
|
||||||
|
ql_remove(&arena->runs_dirty, mapelm, dr_link);
|
||||||
|
}
|
||||||
|
|
||||||
if (arena->spare != NULL) {
|
if (arena->spare != NULL) {
|
||||||
arena_chunk_t *spare = arena->spare;
|
arena_chunk_t *spare = arena->spare;
|
||||||
@ -1216,6 +1240,13 @@ arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size,
|
|||||||
arena_avail_remove(arena, chunk, run_ind+run_pages, nrun_pages,
|
arena_avail_remove(arena, chunk, run_ind+run_pages, nrun_pages,
|
||||||
false, true);
|
false, true);
|
||||||
|
|
||||||
|
/* If the successor is dirty, remove it from runs_dirty. */
|
||||||
|
if (flag_dirty != 0) {
|
||||||
|
arena_chunk_map_t *mapelm = arena_mapp_get(chunk,
|
||||||
|
run_ind+run_pages);
|
||||||
|
ql_remove(&arena->runs_dirty, mapelm, dr_link);
|
||||||
|
}
|
||||||
|
|
||||||
size += nrun_size;
|
size += nrun_size;
|
||||||
run_pages += nrun_pages;
|
run_pages += nrun_pages;
|
||||||
|
|
||||||
@ -1244,6 +1275,13 @@ arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size,
|
|||||||
arena_avail_remove(arena, chunk, run_ind, prun_pages, true,
|
arena_avail_remove(arena, chunk, run_ind, prun_pages, true,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
/* If the predecessor is dirty, remove it from runs_dirty. */
|
||||||
|
if (flag_dirty != 0) {
|
||||||
|
arena_chunk_map_t *mapelm = arena_mapp_get(chunk,
|
||||||
|
run_ind);
|
||||||
|
ql_remove(&arena->runs_dirty, mapelm, dr_link);
|
||||||
|
}
|
||||||
|
|
||||||
size += prun_size;
|
size += prun_size;
|
||||||
run_pages += prun_pages;
|
run_pages += prun_pages;
|
||||||
|
|
||||||
@ -1261,6 +1299,7 @@ static void
|
|||||||
arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned)
|
arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned)
|
||||||
{
|
{
|
||||||
arena_chunk_t *chunk;
|
arena_chunk_t *chunk;
|
||||||
|
arena_chunk_map_t *mapelm;
|
||||||
size_t size, run_ind, run_pages, flag_dirty;
|
size_t size, run_ind, run_pages, flag_dirty;
|
||||||
|
|
||||||
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
|
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
|
||||||
@ -1315,6 +1354,13 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned)
|
|||||||
arena_mapbits_dirty_get(chunk, run_ind+run_pages-1));
|
arena_mapbits_dirty_get(chunk, run_ind+run_pages-1));
|
||||||
arena_avail_insert(arena, chunk, run_ind, run_pages, true, true);
|
arena_avail_insert(arena, chunk, run_ind, run_pages, true, true);
|
||||||
|
|
||||||
|
if (dirty) {
|
||||||
|
/* Insert into runs_dirty list. */
|
||||||
|
mapelm = arena_mapp_get(chunk, run_ind);
|
||||||
|
ql_elm_new(mapelm, dr_link);
|
||||||
|
ql_tail_insert(&arena->runs_dirty, mapelm, dr_link);
|
||||||
|
}
|
||||||
|
|
||||||
/* Deallocate chunk if it is now completely unused. */
|
/* Deallocate chunk if it is now completely unused. */
|
||||||
if (size == arena_maxclass) {
|
if (size == arena_maxclass) {
|
||||||
assert(run_ind == map_bias);
|
assert(run_ind == map_bias);
|
||||||
@ -2437,6 +2483,7 @@ arena_new(arena_t *arena, unsigned ind)
|
|||||||
|
|
||||||
/* Initialize chunks. */
|
/* Initialize chunks. */
|
||||||
arena_chunk_dirty_new(&arena->chunks_dirty);
|
arena_chunk_dirty_new(&arena->chunks_dirty);
|
||||||
|
ql_new(&arena->runs_dirty);
|
||||||
arena->spare = NULL;
|
arena->spare = NULL;
|
||||||
|
|
||||||
arena->nactive = 0;
|
arena->nactive = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user