src/Pure/Tools/build_process.scala
changeset 77317 b8ec3c0455db
parent 77315 f34559b24277
child 77329 1b7c5d4b97a8
--- a/src/Pure/Tools/build_process.scala	Mon Feb 20 17:10:22 2023 +0100
+++ b/src/Pure/Tools/build_process.scala	Mon Feb 20 17:13:19 2023 +0100
@@ -119,9 +119,10 @@
             }
         }
 
-      new Context(store, deps, sessions, ordering, progress,
-        build_heap = build_heap, numa_shuffling = numa_shuffling, max_jobs = max_jobs,
-        fresh_build = fresh_build, no_build = no_build, verbose = verbose, session_setup)
+      val numa_nodes = if (numa_shuffling) NUMA.nodes() else Nil
+      new Context(store, deps, sessions, ordering, progress, numa_nodes,
+        build_heap = build_heap, max_jobs = max_jobs, fresh_build = fresh_build,
+        no_build = no_build, verbose = verbose, session_setup)
     }
   }
 
@@ -131,8 +132,8 @@
     sessions: Map[String, Session_Context],
     val ordering: Ordering[String],
     val progress: Progress,
+    val numa_nodes: List[Int],
     val build_heap: Boolean,
-    val numa_shuffling: Boolean,
     val max_jobs: Int,
     val fresh_build: Boolean,
     val no_build: Boolean,
@@ -191,7 +192,7 @@
     }
 
   // global state
-  private val _numa_nodes = new NUMA.Nodes(build_context.numa_shuffling)
+  private var _numa_index = 0
   private var _pending: List[Build_Process.Entry] =
     (for ((name, (_, (preds, _))) <- build_context.sessions_structure.build_graph.iterator)
       yield Build_Process.Entry(name, preds.toList)).toList
@@ -214,8 +215,18 @@
   }
 
   private def next_numa_node(): Option[Int] = synchronized {
-    _numa_nodes.next(used =
-      Set.from(for { job <- _running.valuesIterator; i <- job.numa_node } yield i))
+    val available = build_context.numa_nodes.zipWithIndex
+    if (available.isEmpty) None
+    else {
+      val used = Set.from(for (job <- _running.valuesIterator; i <- job.numa_node) yield i)
+      val index = _numa_index
+      val candidates = available.drop(index) ::: available.take(index)
+      val (n, i) =
+        candidates.find({ case (n, i) => i == index && !used(n) }) orElse
+        candidates.find({ case (n, _) => !used(n) }) getOrElse candidates.head
+      _numa_index = (i + 1) % available.length
+      Some(n)
+    }
   }
 
   private def stop_running(): Unit = synchronized { _running.valuesIterator.foreach(_.terminate()) }