# HG changeset patch # User Fabian Huch # Date 1701881730 -3600 # Node ID 229f4920460301db109b4644e0cbcd61c2779cf0 # Parent 7ed43417770ffc9893d540d896377ca7c758aa82 clarified build heuristics parameters; diff -r 7ed43417770f -r 229f49204603 src/Pure/Tools/build_schedule.scala --- a/src/Pure/Tools/build_schedule.scala Wed Dec 06 17:44:51 2023 +0100 +++ b/src/Pure/Tools/build_schedule.scala Wed Dec 06 17:55:30 2023 +0100 @@ -611,34 +611,52 @@ object Path_Time_Heuristic { - sealed trait Criterion - case class Absolute_Time(time: Time) extends Criterion { + sealed trait Critical_Criterion + case class Absolute_Time(time: Time) extends Critical_Criterion { override def toString: String = "absolute time (" + time.message_hms + ")" } - case class Relative_Time(factor: Double) extends Criterion { + case class Relative_Time(factor: Double) extends Critical_Criterion { override def toString: String = "relative time (" + factor + ")" } - sealed trait Strategy - case class Fixed_Thread(threads: Int) extends Strategy { + sealed trait Parallel_Strategy + case class Fixed_Thread(threads: Int) extends Parallel_Strategy { override def toString: String = "fixed threads (" + threads + ")" } - case class Time_Based_Threads(f: Time => Int) extends Strategy { + case class Time_Based_Threads(f: Time => Int) extends Parallel_Strategy { override def toString: String = "time based threads" } + + sealed trait Host_Criterion + case object Critical_Nodes extends Host_Criterion { + override def toString: String = "per critical node" + } + case class Fixed_Fraction(fraction: Double) extends Host_Criterion { + override def toString: String = "fixed fraction (" + fraction + ")" + } + case class Host_Speed(min_factor: Double) extends Host_Criterion { + override def toString: String = "host speed (" + min_factor + ")" + } } class Path_Time_Heuristic( - is_critical: Path_Time_Heuristic.Criterion, - parallel_threads: Path_Time_Heuristic.Strategy, + is_critical: Path_Time_Heuristic.Critical_Criterion, + parallel_threads: Path_Time_Heuristic.Parallel_Strategy, + host_criterion: Path_Time_Heuristic.Host_Criterion, timing_data: Timing_Data, sessions_structure: Sessions.Structure, max_threads_limit: Int = 8 ) extends Path_Heuristic(timing_data, sessions_structure, max_threads_limit) { import Path_Time_Heuristic.* - override def toString: Node = - "path time heuristic (critical: " + is_critical + ", parallel: " + parallel_threads + ")" + override def toString: Node = { + val params = + List( + "critical: " + is_critical, + "parallel: " + parallel_threads, + "fast hosts: " + host_criterion) + "path time heuristic (" + params.mkString(", ") + ")" + } def next(state: Build_Process.State): List[Config] = { val resources = host_infos.available(state) @@ -648,7 +666,10 @@ val rev_ordered_hosts = ordered_hosts.reverse.map(_ -> max_threads) - val resources0 = host_infos.available(state.copy(running = Map.empty)) + val available_nodes = + host_infos.available(state.copy(running = Map.empty)) + .unused_nodes(max_threads) + .sortBy(node => host_infos.the_host(node))(host_infos.host_speeds).reverse def remaining_time(node: Node): (Node, Time) = state.running.get(node) match { @@ -661,11 +682,9 @@ } val max_parallel = parallel_paths(state.ready.map(_.name).map(remaining_time)) - val fully_parallelizable = max_parallel <= resources0.unused_nodes(max_threads).length - val next_sorted = state.next_ready.sortBy(max_time(_).ms).reverse - if (fully_parallelizable) { + if (max_parallel <= available_nodes.length) { val all_tasks = next_sorted.map(task => (task, best_threads(task), best_threads(task))) resources.try_allocate_tasks(rev_ordered_hosts, all_tasks)._1 } @@ -694,7 +713,22 @@ val max_critical_parallel = parallel_paths(critical_minimals.map(remaining_time), critical_nodes.contains) - val (critical_hosts, other_hosts) = rev_ordered_hosts.splitAt(max_critical_parallel) + val max_critical_hosts = + available_nodes.take(max_critical_parallel).map(_.hostname).distinct.length + + val split = + this.host_criterion match { + case Critical_Nodes => max_critical_hosts + case Fixed_Fraction(fraction) => + ((rev_ordered_hosts.length * fraction).ceil.toInt max 1) min max_critical_hosts + case Host_Speed(min_factor) => + val best = rev_ordered_hosts.head._1.info.benchmark_score.get + val num_fast = + rev_ordered_hosts.count(_._1.info.benchmark_score.exists(_ >= best * min_factor)) + num_fast min max_critical_hosts + } + + val (critical_hosts, other_hosts) = rev_ordered_hosts.splitAt(split) val (configs1, resources1) = resources.try_allocate_tasks(critical_hosts, critical_tasks) val (configs2, _) = resources1.try_allocate_tasks(other_hosts, other_tasks) @@ -903,12 +937,19 @@ case time if time < Time.minutes(5) => 4 case _ => 8 })) + val machine_splits = + List( + Path_Time_Heuristic.Critical_Nodes, + Path_Time_Heuristic.Fixed_Fraction(0.3), + Path_Time_Heuristic.Host_Speed(0.9)) val path_time_heuristics = for { is_critical <- is_criticals parallel <- parallel_threads - } yield Path_Time_Heuristic(is_critical, parallel, timing_data, sessions_structure) + machine_split <- machine_splits + } yield + Path_Time_Heuristic(is_critical, parallel, machine_split, timing_data, sessions_structure) val heuristics = Default_Heuristic(timing_data, context.build_options) :: path_time_heuristics new Meta_Heuristic(heuristics)