Make the current victim be stored at head of in-swap LRU list instead of tail of...
authorNick Downing <nick@ndcode.org>
Fri, 15 Mar 2019 13:02:52 +0000 (00:02 +1100)
committerNick Downing <nick@ndcode.org>
Fri, 15 Mar 2019 13:08:46 +0000 (00:08 +1100)
process.c

index 0fe0223..736dac0 100644 (file)
--- a/process.c
+++ b/process.c
@@ -42,33 +42,32 @@ static void check_invariants() {
   assert(avail == process_avail);
 
   // in-core LRU list processes:
-  // must have core, can't have swap except the last
-  for (
-    struct lru_item *p0 = lru_head_core.next;
-    p0 != &lru_head_core;
-    p0 = p0->next
-  ) {
+  // must have core, can't have swap
+  struct lru_item *p0;
 #define p ((struct process *)p0)
+  for (p0 = lru_head_core.next; p0 != &lru_head_core; p0 = p0->next) {
     assert(p0->prev->next == p0);
     assert(p0->next->prev == p0);
     assert(p->core_item.prev);
-    assert(p->swap_item.prev == NULL || p0->next == &lru_head_core);
-#undef p
+    assert(p->swap_item.prev == NULL);
   }
 
   // in-swap LRU list processes:
-  // may have swap, can't have core
-  for (
-    struct lru_item *p0 = lru_head_swap.next;
-    p0 != &lru_head_swap;
-    p0 = p0->next
-  ) {
-#define p ((struct process *)p0)
+  // must have swap, can't have core except the first
+  p0 = lru_head_swap.next;
+  if (p0 != &lru_head_swap) {
     assert(p0->prev->next == p0);
     assert(p0->next->prev == p0);
-    assert(p->core_item.prev == NULL);
-#undef p
+    assert(p->core_item.prev);
+    assert(p->swap_item.prev);
+    for (p0 = p0->next; p0 != &lru_head_swap; p0 = p0->next) {
+      assert(p0->prev->next == p0);
+      assert(p0->next->prev == p0);
+      assert(p->core_item.prev == NULL);
+      assert(p->swap_item.prev);
+    }
   }
+#undef p
 }
 #endif
 
@@ -97,10 +96,19 @@ static void do_swap_out(int swap_out) {
   for (; swap_out > 0; swap_out -= size) {
     // choose victim and calculate how much can swap out,
     // getting rid of victims that are completely swapped
-    goto loop_entry;
-    do {
+    victim0 = lru_head_swap.next;
+    if (victim0 == &lru_head_swap)
+      goto no_victim;
+    while ((size = victim->core_item.limit - victim->core_item.base) == 0) {
  printf("victimized %d\n", (int)(victim - processes));
-      // remove from tail of in-core LRU list
+      // remove from core pool
+      pool_free(&core_head, &victim->core_item);
+      victim->core_item.prev = NULL;
+
+    no_victim:
+      // take new victim from tail of in-core LRU list
+      victim0 = lru_head_core.prev;
+      assert(victim0 != &lru_head_core);
       victim0->prev->next = victim0->next;
       victim0->next->prev = victim0->prev;
 
@@ -110,21 +118,9 @@ static void do_swap_out(int swap_out) {
       victim0->prev->next = victim0;
       victim0->next->prev = victim0;
 
-      // remove from core pool for efficiency
-      // note: if zero length it's neither in core nor swap pool
-      pool_free(&core_head, &victim->core_item);
-      victim->core_item.prev = NULL;
-
-    loop_entry:
-      // there must be a victim, based on calculations above
-      victim0 = lru_head_core.prev;
-      assert(victim0 != &lru_head_core);
-      size = victim->core_item.limit - victim->core_item.base;
-    } while (size == 0);
-
-    // if removed from swap pool for efficiency, put back in
-    if (victim->swap_item.prev == NULL)
+      // put in swap pool
       rassert(pool_alloc_moveable(&swap_head, &victim->swap_item, 0));
+    }
 
     // calculate amount to swap
     if (size > swap_out)
@@ -225,82 +221,100 @@ bool process_realloc(struct process *process, int size) {
 
 void process_run(struct process *process) {
   int swap_in, swap_out;
+  struct lru_item *victim0;
+#define victim ((struct process *)victim0)
 
   // must be already allocated
   assert(process->lru_item.prev && process->lru_item.next);
 
+  // note current victim before messing with LRU lists
+  victim0 = lru_head_swap.next;
+
   // remove from whichever LRU list it's in
   process->lru_item.prev->next = process->lru_item.next;
   process->lru_item.next->prev = process->lru_item.prev;
 
-  // insert at head of in-core LRU list
-  process->lru_item.prev = &lru_head_core;
-  process->lru_item.next = lru_head_core.next;
-  process->lru_item.prev->next = &process->lru_item;
-  process->lru_item.next->prev = &process->lru_item;
-  // if removed from core pool for efficiency, put back in
-  // note: this can only happen if it came from in-swap LRU list
-  if (process->core_item.prev == NULL)
-    rassert(pool_alloc_moveable(&core_head, &process->core_item, 0));
-
-  // if not in swap pool, then it must be fully in core
-  if (process->swap_item.prev == NULL)
-    return;
-
-  // while not fully in core, make space and bring some in
-  while (
-    (
-      swap_in =
-        process->size +
-        process->core_item.base -
-        process->core_item.limit
-    ) != 0
-  ) {
-    // free up as much core as we can, for this iteration
-    swap_out = swap_in - core_head.avail;
-    if (swap_out > swap_head.avail) {
-      swap_in += swap_head.avail - swap_out;
-      swap_out = swap_head.avail;
+  // if in swap pool, may need to swap in
+  if (process->swap_item.prev) {
+    // see if we are the current victim
+    if (victim == process) {
+      // we are already in core pool
+      // if there is a new victim, put it in core pool
+      victim0 = victim0->next;
+      if (victim0 != &lru_head_swap)
+        rassert(pool_alloc_moveable(&core_head, &victim->core_item, 0));
     }
-    do_swap_out(swap_out);
+    else
+      // put us in core pool
+      rassert(pool_alloc_moveable(&core_head, &process->core_item, 0));
+
+    // while not fully in core, make space and bring some in
+    while (
+      (
+        swap_in =
+          process->size +
+          process->core_item.base -
+          process->core_item.limit
+      ) != 0
+    ) {
+      // free up as much core as we can, for this iteration
+      swap_out = swap_in - core_head.avail;
+      if (swap_out > swap_head.avail) {
+        swap_in += swap_head.avail - swap_out;
+        swap_out = swap_head.avail;
+      }
+      do_swap_out(swap_out);
+
+      // increase core allocation
+      rassert(
+        pool_realloc_moveable(
+          &core_head,
+          &process->core_item,
+          swap_in + process->core_item.limit - process->core_item.base
+        )
+      );
 
-    // increase core allocation
-    rassert(
-      pool_realloc_moveable(
-        &core_head,
-        &process->core_item,
-        swap_in + process->core_item.limit - process->core_item.base
-      )
-    );
+      // transfer data to core
+      swap_pop(
+        process->swap_item.limit,
+        process->core_item.limit - swap_in,
+        swap_in
+      );
 
-    // transfer data to core
-    swap_pop(
-      process->swap_item.limit,
-      process->core_item.limit - swap_in,
-      swap_in
-    );
+      // reduce swap allocation
+      rassert(
+        pool_realloc_moveable(
+          &swap_head,
+          &process->swap_item,
+          process->swap_item.limit - process->swap_item.base - swap_in
+        )
+      );
+    }
 
-    // reduce swap allocation
-    rassert(
-      pool_realloc_moveable(
-        &swap_head,
-        &process->swap_item,
-        process->swap_item.limit - process->swap_item.base - swap_in
-      )
-    );
+    // remove from swap pool
+    pool_free(&swap_head, &process->swap_item);
+    process->swap_item.prev = NULL;
   }
 
-  // remove from swap pool for efficiency
-  pool_free(&swap_head, &process->swap_item);
-  process->swap_item.prev = NULL;
+  // insert at head of in-core LRU list
+  process->lru_item.prev = &lru_head_core;
+  process->lru_item.next = lru_head_core.next;
+  process->lru_item.prev->next = &process->lru_item;
+  process->lru_item.next->prev = &process->lru_item;
  check_invariants();
+#undef victim
 }
 
 void process_free(struct process *process) {
+  struct lru_item *victim0;
+#define victim ((struct process *)victim0)
+
+ check_invariants();
   // must be already allocated
   assert(process->lru_item.prev && process->lru_item.next);
 
+  // note current victim before messing with LRU lists
+  victim0 = lru_head_swap.next;
   // remove from whichever LRU list it's in
   process->lru_item.prev->next = process->lru_item.next;
   process->lru_item.next->prev = process->lru_item.prev;
@@ -309,6 +323,15 @@ void process_free(struct process *process) {
   process->lru_item.next = NULL;
 #endif
 
+  // see if we are the current victim
+  if (victim == process) {
+    // if there is a new victim, put it in core pool
+    victim0 = lru_head_swap.next;
+ printf("victim0 %p\n", victim0);
+    if (victim0 != &lru_head_swap)
+      rassert(pool_alloc_moveable(&core_head, &victim->core_item, 0));
+  }
+
   // free from core and/or swap pools if there
   if (process->core_item.prev)
     pool_free(&core_head, &process->core_item);
@@ -318,4 +341,5 @@ void process_free(struct process *process) {
   // track total allocation
   process_avail += process->size;
  check_invariants();
+#undef victim
 }