struct lru_item lru_head;
struct process *victim;
-struct pool_item victim_core_item, victim_swap_item;
+#ifdef PREALLOCATE_CORE
+int victim_core_size;
+#else
+struct pool_item victim_core_item;
+#endif
+#ifdef PREALLOCATE_SWAP
+int victim_swap_size;
+#else
+struct pool_item victim_swap_item;
+#endif
#if 1
// won't work when compiled with NDEBUG
static void check_invariants() {
- int avail =
+#if defined(PREALLOCATE_CORE) && defined(PREALLOCATE_SWAP)
+ int core_head_avail =
core_head.item.base -
core_head.item.limit -
- core_head.spare +
+ core_head.spare;
+ int swap_head_avail =
swap_head.item.base -
swap_head.item.limit -
- swap_head.spare -
- process_spare;
- if (victim) {
- assert(victim_core_item.prev && victim_core_item.next);
- assert(victim_swap_item.prev && victim_core_item.next);
- }
- else {
+ swap_head.spare;
+ int avail = (
+ core_head_avail < swap_head_avail ? core_head_avail : swap_head_avail
+ ) - process_spare;
+#elif defined(PREALLOCATE_CORE)
+ int core_head_avail =
+ core_head.item.base -
+ core_head.item.limit -
+ core_head.spare;
+ int avail = core_head_avail - process_spare;
+#elif defined(PREALLOCATE_SWAP)
+ int swap_head_avail =
+ swap_head.item.base -
+ swap_head.item.limit -
+ swap_head.spare;
+ int avail = swap_head_avail - process_spare;
+#else
+ int core_head_avail =
+ core_head.item.base -
+ core_head.item.limit -
+ core_head.spare;
+ int swap_head_avail =
+ swap_head.item.base -
+ swap_head.item.limit -
+ swap_head.spare;
+ int avail = core_head_avail + swap_head_avail - process_spare;
+#endif
+ if (victim == NULL) {
+#ifdef PREALLOCATE_CORE
+ assert(victim_core_size == 0);
+#else
assert(victim_core_item.prev == NULL && victim_core_item.next == NULL);
+#endif
+#ifdef PREALLOCATE_SWAP
+ assert(victim_swap_size == 0);
+#else
assert(victim_swap_item.prev == NULL && victim_swap_item.prev == NULL);
+#endif
}
for (int i = 0; i < n_processes; ++i)
- if (processes[i].size != -1) {
- if (processes + i == victim) {
- assert(processes[i].lru_item.prev == NULL);
+ if (processes[i].size == -1) {
+#ifdef PREALLOCATE_CORE
+ assert(
+ processes[i].core_item.prev == NULL &&
+ processes[i].core_item.next == NULL
+ );
+#endif
+#ifdef PREALLOCATE_SWAP
+ assert(
+ processes[i].swap_item.prev == NULL &&
+ processes[i].swap_item.next == NULL
+ );
+#endif
+ }
+ else {
+#ifdef PREALLOCATE_CORE
+ assert(processes[i].core_item.prev && processes[i].core_item.next);
+#endif
+#ifdef PREALLOCATE_SWAP
+ assert(processes[i].swap_item.prev && processes[i].swap_item.next);
+#endif
+ if (processes[i].lru_item.prev) {
+ assert(processes + i != victim);
+ assert(processes[i].lru_item.prev->next == &processes[i].lru_item);
+ assert(processes[i].lru_item.next->prev == &processes[i].lru_item);
+#ifdef PREALLOCATE_CORE
+#ifndef PREALLOCATE_SWAP
assert(
processes[i].pool_item.prev == NULL &&
processes[i].pool_item.next == NULL
);
- int core_size = victim_core_item.limit - victim_core_item.base;
- assert(core_size);
- int swap_size = victim_swap_item.limit - victim_swap_item.base;
- assert(swap_size);
- assert(processes[i].size == core_size + swap_size);
+#endif
+#else
+ assert(processes[i].pool_item.prev && processes[i].pool_item.next);
+ assert(
+ processes[i].size ==
+ processes[i].pool_item.limit -
+ processes[i].pool_item.base
+ );
+#endif
+ }
+ else if (processes + i == victim) {
+#if !defined(PREALLOCATE_CORE) || !defined(PREALLOCATE_SWAP)
+ assert(
+ processes[i].pool_item.prev == NULL &&
+ processes[i].pool_item.next == NULL
+ );
+#endif
+#ifndef PREALLOCATE_CORE
+ assert(victim_core_item.prev && victim_core_item.next);
+ int victim_core_size = victim_core_item.limit - victim_core_item.base;
+#endif
+ assert(victim_core_size);
+#ifndef PREALLOCATE_SWAP
+ assert(victim_swap_item.prev && victim_swap_item.next);
+ int victim_swap_size = victim_swap_item.limit - victim_swap_item.base;
+#endif
+ assert(victim_swap_size);
+ assert(processes[i].size == victim_core_size + victim_swap_size);
}
else {
- if (processes[i].lru_item.prev) {
- assert(processes[i].lru_item.prev->next == &processes[i].lru_item);
- assert(processes[i].lru_item.next->prev == &processes[i].lru_item);
- }
+#ifdef PREALLOCATE_SWAP
+#ifndef PREALLOCATE_CORE
+ assert(
+ processes[i].pool_item.prev == NULL &&
+ processes[i].pool_item.next == NULL
+ );
+#endif
+#else
+ assert(processes[i].pool_item.prev && processes[i].pool_item.next);
assert(
processes[i].size ==
processes[i].pool_item.limit -
processes[i].pool_item.base
);
+#endif
}
avail -= processes[i].size;
}
processes[i].size = -1;
#endif
+#if defined(PREALLOCATE_CORE) && defined(PREALLOCATE_SWAP)
+ process_avail = (
+ core_head.avail < swap_head.avail ? core_head.avail : swap_head.avail
+ ) - spare;
+#elif defined(PREALLOCATE_CORE)
+ process_avail = core_head.avail - spare;
+#elif defined(PREALLOCATE_SWAP)
+ process_avail = swap_head.avail - spare;
+#else
process_avail = core_head.avail + swap_head.avail - spare;
+#endif
process_spare = spare;
lru_head.prev = &lru_head;
victim = NULL;
#ifndef NDEBUG
+#ifdef PREALLOCATE_CORE
+ victim_core_size = 0;
+#else
memset(&victim_core_item, 0, sizeof(victim_core_item));
+#endif
+#ifdef PREALLOCATE_SWAP
+ victim_swap_size = 0;
+#else
memset(&victim_swap_item, 0, sizeof(victim_swap_item));
+#endif
#endif
check_invariants();
}
static void do_swap_out(int swap_out) {
- printf("swap_out %d\n", swap_out);
- int victim_size, size;
+#ifndef PREALLOCATE_CORE
+ int victim_core_size;
+#endif
+#ifndef PREALLOCATE_SWAP
+ int victim_swap_size;
+#endif
+ int size;
// loop entry code for the case of an existing victim
if (swap_out > 0) {
if (victim) {
// calculate amount to swap
- victim_size = victim_core_item.limit - victim_core_item.base;
- size = swap_out < victim_size ? swap_out : victim_size;
- printf("existing victim %d, swap out %d of %d\n", (int)(victim - processes), size, victim_size);
+#ifndef PREALLOCATE_CORE
+ victim_core_size = victim_core_item.limit - victim_core_item.base;
+#endif
+#ifndef PREALLOCATE_SWAP
+ victim_swap_size = victim_swap_item.limit - victim_swap_item.base;
+#endif
+ size = swap_out < victim_core_size ? swap_out : victim_core_size;
+ printf("existing victim %d, swap out %d of %d\n", (int)(victim - processes), size, victim_core_size);
// increase swap allocation
+ victim_swap_size += size;
+#ifndef PREALLOCATE_SWAP
rassert(
- pool_realloc_moveable(
- &swap_head,
- &victim_swap_item,
- size + victim_swap_item.limit - victim_swap_item.base
- )
+ pool_realloc_moveable(&swap_head, &victim_swap_item, victim_swap_size)
);
+#endif
goto loop_entry;
}
victim->lru_item.next->prev = victim->lru_item.prev;
victim->lru_item.prev = NULL; // indicates not runnable
+#ifndef PREALLOCATE_CORE
// move per-process to dedicated core item
pool_move_item(&victim->pool_item, &victim_core_item);
+ victim_core_size = victim_core_item.limit - victim_core_item.base;
+#endif
// calculate amount to swap
- victim_size = victim_core_item.limit - victim_core_item.base;
- size = swap_out < victim_size ? swap_out : victim_size;
- printf("new victim %d, swap out %d of %d\n", (int)(victim - processes), size, victim_size);
+ size = swap_out < victim_core_size ? swap_out : victim_core_size;
+ printf("new victim %d, swap out %d of %d\n", (int)(victim - processes), size, victim_core_size);
// add to swap pool, using dedicated swap item
- rassert(pool_alloc_moveable(&swap_head, &victim_swap_item, size));
+ victim_swap_size = size;
+#ifndef PREALLOCATE_SWAP
+ rassert(
+ pool_alloc_moveable(&swap_head, &victim_swap_item, victim_swap_size)
+ );
+#endif
loop_entry:
// transfer data to swap
swap_write(
+#ifdef PREALLOCATE_SWAP
+ ~(victim->swap_item.base + victim_swap_size),
+#else
~victim_swap_item.limit,
+#endif
+#ifdef PREALLOCATE_CORE
+ victim->core_item.base + victim_core_size - size,
+#else
victim_core_item.limit - size,
+#endif
size
);
// see if victim fully swapped out
- victim_size -= size;
- if (victim_size) {
+ victim_core_size -= size;
+ if (victim_core_size) {
+#ifndef PREALLOCATE_CORE
// no, reduce core allocation, using dedicated core item
rassert(
- pool_realloc_moveable(&core_head, &victim_core_item, victim_size)
+ pool_realloc_moveable(&core_head, &victim_core_item, victim_core_size)
);
+#endif
// as an optimization, skip the calculation of swap_out -= size
return;
}
printf("victimized %d\n", (int)(victim - processes));
+#ifndef PREALLOCATE_CORE
// remove from core pool, using dedicated core item
pool_free(&core_head, &victim_core_item);
+#endif
+#ifndef PREALLOCATE_SWAP
// move dedicated to per-process swap item
pool_move_item(&victim_swap_item, &victim->pool_item);
+#endif
swap_out -= size;
} while (swap_out);
victim = NULL;
+#ifdef PREALLOCATE_CORE
+ assert(victim_core_size == 0);
+#endif
+#ifdef PREALLOCATE_SWAP
+ victim_swap_size = 0;
+#endif
}
}
do_swap_out(swap_out);
// allocate core, can't fail
+#ifdef PREALLOCATE_CORE
+ rassert(pool_alloc_moveable(&core_head, &process->core_item, size));
+#else
rassert(pool_alloc_moveable(&core_head, &process->pool_item, size));
+#endif
+#ifdef PREALLOCATE_SWAP
+ rassert(pool_alloc_moveable(&swap_head, &process->swap_item, size));
+#endif
// insert at head of LRU list
process->lru_item.prev = &lru_head;
do_swap_out(swap_out);
// reallocate core, can't fail
+#ifdef PREALLOCATE_CORE
+ rassert(pool_realloc_moveable(&core_head, &process->core_item, size));
+#else
rassert(pool_realloc_moveable(&core_head, &process->pool_item, size));
- process->size = size;
+#endif
+#ifdef PREALLOCATE_SWAP
+ rassert(pool_realloc_moveable(&swap_head, &process->swap_item, size));
+#endif
// track total allocation
process->size = size;
}
void process_run(struct process *process) {
- int swap_in, size, swap_out;
- struct pool_item process_core_item, process_swap_item;
+ int size, swap_out;
+ int process_core_size;
+#ifndef PREALLOCATE_CORE
+ struct pool_item process_core_item;
+#endif
+ int process_swap_size;
+#ifndef PREALLOCATE_SWAP
+ struct pool_item process_swap_item;
+#endif
// must be already allocated
assert(process->size != -1);
else {
// no, need to swap some in
#ifndef NDEBUG
+#ifndef PREALLOCATE_CORE
memset(&process_core_item, 0, sizeof(process_core_item));
+#endif
+#ifndef PREALLOCATE_SWAP
memset(&process_swap_item, 0, sizeof(process_swap_item));
+#endif
#endif
// loop entry code for case of fully in swap
if (process != victim) {
// fully in swap, take over only the per-process swap item
+#ifdef PREALLOCATE_SWAP
+ process_swap_size = process->size;
+#else
pool_move_item(&process->pool_item, &process_swap_item);
- swap_in = process_swap_item.limit - process_swap_item.base;
+ process_swap_size = process_swap_item.limit - process_swap_item.base;
+#endif
// calculate amount to swap
- size = swap_in;
+ size = process_swap_size;
swap_out = size - core_head.avail;
if (swap_out > swap_head.avail) {
size += swap_head.avail - swap_out;
do_swap_out(swap_out);
// add to core pool, using dedicated core item
- rassert(pool_alloc_moveable(&core_head, &process_core_item, size));
+ process_core_size = size;
+#ifndef PREALLOCATE_CORE
+ rassert(
+ pool_alloc_moveable(&core_head, &process_core_item, process_core_size)
+ );
+#endif
goto loop_entry_full;
}
// victim, take over the dedicated pool items
victim = NULL;
+#ifdef PREALLOCATE_CORE
+ process_core_size = victim_core_size;
+#ifndef NDEBUG
+ victim_core_size = 0;
+#endif
+#else
pool_move_item(&victim_core_item, &process_core_item);
+ process_core_size = process_core_item.limit - process_core_item.base;
+#endif
+#ifdef PREALLOCATE_SWAP
+ process_swap_size = victim_swap_size;
+#ifndef NDEBUG
+ victim_swap_size = 0;
+#endif
+#else
pool_move_item(&victim_swap_item, &process_swap_item);
- swap_in = process_swap_item.limit - process_swap_item.base;
+ process_swap_size = process_swap_item.limit - process_swap_item.base;
goto loop_entry_partial;
+#endif
// loop for case of partially in core, partially in swap
do {
+#ifndef PREALLOCATE_SWAP
// reduce swap allocation
rassert(
- pool_realloc_moveable(
- &swap_head,
- &process_swap_item,
- swap_in
- )
+ pool_realloc_moveable(&swap_head, &process_swap_item, process_swap_size)
);
loop_entry_partial:
+#endif
// calculate how much to swap
- size = swap_in;
+ size = process_swap_size;
swap_out = size - core_head.avail;
if (swap_out > swap_head.avail) {
size += swap_head.avail - swap_out;
do_swap_out(swap_out);
// increase core allocation
+ process_core_size += size;
+#ifndef PREALLOCATE_CORE
rassert(
- pool_realloc_moveable(
- &core_head,
- &process_core_item,
- process_core_item.limit - process_core_item.base + size
- )
+ pool_realloc_moveable(&core_head, &process_core_item, process_core_size)
);
+#endif
loop_entry_full:
// transfer data to core
swap_read(
+#ifdef PREALLOCATE_SWAP
+ ~(process->swap_item.base + process_swap_size),
+#else
~process_swap_item.limit,
+#endif
+#ifdef PREALLOCATE_CORE
+ process->core_item.base + process_core_size - size,
+#else
process_core_item.limit - size,
+#endif
size
);
- swap_in -= size;
- } while (swap_in);
+ process_swap_size -= size;
+ } while (process_swap_size);
+#ifndef PREALLOCATE_CORE
// move dedicated to per-process core item
pool_move_item(&process_core_item, &process->pool_item);
+#endif
+#ifndef PREALLOCATE_SWAP
// remove from swap pool, using dedicated swap item
pool_free(&swap_head, &process_swap_item);
+#endif
}
// insert at head of LRU list
// must be already allocated
assert(process->size != -1);
+#ifdef PREALLOCATE_CORE
+ pool_free(&core_head, &process->core_item);
+#endif
+#ifdef PREALLOCATE_SWAP
+ pool_free(&swap_head, &process->swap_item);
+#endif
+
// see whether fully in core, victim, or fully in swap
if (process->lru_item.prev != NULL) {
// fully in core, remove from LRU list and core pool
process->lru_item.prev->next = process->lru_item.next;
process->lru_item.next->prev = process->lru_item.prev;
+#ifndef PREALLOCATE_CORE
pool_free(&core_head, &process->pool_item);
+#endif
}
else if (process == victim) {
// victim, free the dedicated pool items
victim = NULL;
+#ifdef PREALLOCATE_CORE
+ victim_core_size = 0;
+#else
pool_free(&core_head, &victim_core_item);
+#endif
+#ifdef PREALLOCATE_SWAP
+ victim_swap_size = 0;
+#else
pool_free(&swap_head, &victim_swap_item);
+#endif
}
+#ifndef PREALLOCATE_SWAP
else {
// fully in swap, remove from swap pool
pool_free(&swap_head, &process->pool_item);
}
+#endif
// track total allocation
process_avail += process->size;
processes[process].size = -1;
}
else {
- int base = processes[process].pool_item.base;
- printf("new core [%d,%d)\n", base, base + size);
- rassert(processes[process].pool_item.limit == base + size);
+#ifdef PREALLOCATE_CORE
+ int core_base = processes[process].core_item.base;
+#else
+ int core_base = processes[process].pool_item.base;
+#endif
+ printf("new core [%d,%d)\n", core_base, core_base + size);
for (int i = 0; i < size; ++i) {
- rassert(core_mem[base + i] == 0xaaaaaaaa);
+ rassert(core_mem[core_base + i] == 0xaaaaaaaa);
long long hash = process * 17 + i * 29;
hash = (hash & 0xffffffffffffffffLL) + (hash >> 32);
hash = (hash & 0xffffffffffffffffLL) + (hash >> 32);
- core_mem[base + i] = (int)hash;
+ core_mem[core_base + i] = (int)hash;
}
+#ifdef PREALLOCATE_SWAP
+ printf("new swap [%d,%d)\n", ~processes[process].swap_item.limit, ~processes[process].swap_item.base);
+#endif
}
}
}
success
);
else {
+#ifdef PREALLOCATE_CORE
+ printf("old core [%d,%d)\n", processes[process].core_item.base, processes[process].core_item.limit);
+#else
printf("old core [%d,%d)\n", processes[process].pool_item.base, processes[process].pool_item.limit);
+#endif
+#ifdef PREALLOCATE_SWAP
+ printf("old swap [%d,%d)\n", ~processes[process].swap_item.limit, processes[process].swap_item.base);
+#endif
int actual_old_size = processes[process].size;
rassert(actual_old_size <= old_size);
bool result = process_realloc(processes + process, size);
rassert(process_realloc(processes + process, actual_old_size));
}
else {
- int base = processes[process].pool_item.base;
- printf("new core [%d,%d)\n", base, base + size);
- rassert(processes[process].pool_item.limit == base + size);
+#ifdef PREALLOCATE_CORE
+ int core_base = processes[process].core_item.base;
+#else
+ int core_base = processes[process].pool_item.base;
+#endif
+ printf("new core [%d,%d)\n", core_base, core_base + size);
for (int i = actual_old_size; i < size; ++i) {
- rassert(core_mem[base + i] == 0xaaaaaaaa);
+ rassert(core_mem[core_base + i] == 0xaaaaaaaa);
long long hash = process * 17 + i * 29;
hash = (hash & 0xffffffffffffffffLL) + (hash >> 32);
hash = (hash & 0xffffffffffffffffLL) + (hash >> 32);
- core_mem[base + i] = (int)hash;
+ core_mem[core_base + i] = (int)hash;
}
for (int i = size; i < actual_old_size; ++i) {
long long hash = process * 17 + i * 29;
hash = (hash & 0xffffffffffffffffLL) + (hash >> 32);
hash = (hash & 0xffffffffffffffffLL) + (hash >> 32);
- rassert(core_mem[base + i] == (int)hash);
- core_mem[base + i] = 0xaaaaaaaa;
+ rassert(core_mem[core_base + i] == (int)hash);
+ core_mem[core_base + i] = 0xaaaaaaaa;
}
+#ifdef PREALLOCATE_SWAP
+ printf("new swap [%d,%d)\n", ~processes[process].swap_item.limit, ~processes[process].swap_item.base);
+#endif
}
}
}
old_size
);
else {
- bool is_victim = processes + process == victim;
- bool in_core = processes[process].lru_item.prev != NULL;
int actual_old_size = processes[process].size;
rassert(actual_old_size <= old_size);
+ bool is_victim = processes + process == victim;
+ bool in_core = processes[process].lru_item.prev != NULL;
+#ifdef PREALLOCATE_CORE
+ int core_size = is_victim ? victim_core_size : in_core ? processes[process].size : 0;
+ int core_base = processes[process].core_item.base;
+#else
+ int core_base = is_victim ? victim_core_item.base : in_core ? processes[process].pool_item.base : -1;
+ int core_size = is_victim ? victim_core_item.limit - core_base : in_core ? processes[process].pool_item.limit - core_base : 0;
+#endif
+#ifdef PREALLOCATE_SWAP
+ int swap_size = is_victim ? victim_swap_size : !in_core ? processes[process].size : 0;
+ int swap_limit = processes[process].swap_item.base + swap_size;
+#else
+ int swap_limit = is_victim ? victim_swap_item.limit : !in_core ? processes[process].pool_item.limit : 0;
+ int swap_size = is_victim ? swap_limit - victim_swap_item.base : !in_core ? swap_limit - processes[process].pool_item.base : 0;
+#endif
+ rassert(core_size + swap_size == actual_old_size);
process_free(processes + process);
processes[process].size = -1;
printf(
old_size,
actual_old_size
);
- int core_base = is_victim ? victim_core_item.base : in_core ? processes[process].pool_item.base : -1;
- int core_size = is_victim ? victim_core_item.limit - core_base : in_core ? processes[process].pool_item.limit - core_base : 0;
- int swap_limit = is_victim ? victim_swap_item.limit : !in_core ? processes[process].pool_item.limit : 0;
- int swap_size = is_victim ? swap_limit - victim_swap_item.base : !in_core ? swap_limit - processes[process].pool_item.base : 0;
- rassert(core_size + swap_size == actual_old_size);
int swap_base = ~swap_limit;
printf("old core [%d,%d) swap [%d,%d)\n", core_base, core_base + core_size, swap_base, swap_base + swap_size);
for (int i = 0; i < actual_old_size; ++i) {
else {
bool is_victim = processes + i == victim;
bool in_core = processes[i].lru_item.prev != NULL;
+#ifdef PREALLOCATE_CORE
+ int core_size = is_victim ? victim_core_size : in_core ? processes[i].size : 0;
+ int core_base = processes[i].core_item.base;
+#else
int core_base = is_victim ? victim_core_item.base : in_core ? processes[i].pool_item.base : -1;
int core_size = is_victim ? victim_core_item.limit - core_base : in_core ? processes[i].pool_item.limit - core_base : 0;
+#endif
+#ifdef PREALLOCATE_SWAP
+ int swap_size = is_victim ? victim_swap_size : !in_core ? processes[i].size : 0;
+ int swap_limit = processes[i].swap_item.base + swap_size;
+#else
int swap_limit = is_victim ? victim_swap_item.limit : !in_core ? processes[i].pool_item.limit : 0;
int swap_size = is_victim ? swap_limit - victim_swap_item.base : !in_core ? swap_limit - processes[i].pool_item.base : 0;
+#endif
int swap_base = ~swap_limit;
printf("process %d: core [%d,%d) swap [%d,%d)\n", i, core_base, core_base + core_size, swap_base, swap_base + swap_size);
for (int j = 0; j < processes[i].size; ++j) {