src/Pure/Tools/build_schedule.scala
author Fabian Huch <huch@in.tum.de>
Fri, 24 Nov 2023 17:05:49 +0100
changeset 79037 1b3a6cc4a2bf
parent 79036 be42ba4b4672
child 79038 cd7c1acc9cf2
permissions -rw-r--r--
clarified and tuned timing estimation;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     1
/*  Title:      Pure/Tools/build_schedule.scala
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     2
    Author:     Fabian Huch, TU Muenchen
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     3
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     4
Build schedule generated by Heuristic methods, allowing for more efficient builds.
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     5
 */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     6
package isabelle
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     7
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     8
78846
966aa081929f tuned imports;
wenzelm
parents: 78845
diff changeset
     9
import Host.Node_Info
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    10
import scala.annotation.tailrec
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    11
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    12
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    13
object Build_Schedule {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    14
  val engine_name = "build_schedule"
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    15
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    16
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    17
  /* organized historic timing information (extracted from build logs) */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    18
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    19
  case class Timing_Entry(job_name: String, hostname: String, threads: Int, elapsed: Time)
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    20
  case class Timing_Entries(entries: List[Timing_Entry]) {
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    21
    require(entries.nonEmpty)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    22
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    23
    def is_empty = entries.isEmpty
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    24
    def size = entries.length
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    25
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    26
    lazy val by_job = entries.groupBy(_.job_name).view.mapValues(Timing_Entries(_)).toMap
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    27
    lazy val by_threads = entries.groupBy(_.threads).view.mapValues(Timing_Entries(_)).toMap
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    28
    lazy val by_hostname = entries.groupBy(_.hostname).view.mapValues(Timing_Entries(_)).toMap
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    29
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    30
    def mean_time: Time = Timing_Data.mean_time(entries.map(_.elapsed))
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    31
    def best_entry: Timing_Entry = entries.minBy(_.elapsed.ms)
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    32
  }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    33
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    34
  class Timing_Data private(data: Timing_Entries, val host_infos: Host_Infos) {
79025
f78ee2d48bf5 handle inflection point in interpolation with monotone prefix;
Fabian Huch <huch@in.tum.de>
parents: 79024
diff changeset
    35
    private def inflection_point(last_mono: Int, next: Int): Int =
f78ee2d48bf5 handle inflection point in interpolation with monotone prefix;
Fabian Huch <huch@in.tum.de>
parents: 79024
diff changeset
    36
      last_mono + ((next - last_mono) / 2)
f78ee2d48bf5 handle inflection point in interpolation with monotone prefix;
Fabian Huch <huch@in.tum.de>
parents: 79024
diff changeset
    37
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    38
    def best_threads(job_name: String, max_threads: Int): Int = {
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    39
      val worse_threads =
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
    40
        data.by_job.get(job_name).toList.flatMap(_.by_hostname).flatMap {
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    41
          case (hostname, data) =>
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    42
            val best_threads = data.best_entry.threads
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    43
            data.by_threads.keys.toList.sorted.find(_ > best_threads).map(
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    44
              inflection_point(best_threads, _))
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    45
        }
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    46
      (max_threads :: worse_threads).min
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
    47
    }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    48
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    49
    private def hostname_factor(from: String, to: String): Double =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    50
      host_infos.host_factor(host_infos.the_host(from), host_infos.the_host(to))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    51
79036
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    52
    private def approximate_threads(entries: List[(Int, Time)], threads: Int): Time = {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    53
      def sorted_prefix[A](xs: List[A], f: A => Long): List[A] =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    54
        xs match {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    55
          case x1 :: x2 :: xs =>
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    56
            if (f(x1) <= f(x2)) x1 :: sorted_prefix(x2 :: xs, f) else x1 :: Nil
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    57
          case xs => xs
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    58
        }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    59
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    60
      def linear(p0: (Int, Time), p1: (Int, Time)): Time = {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    61
        val a = (p1._2 - p0._2).scale(1.0 / (p1._1 - p0._1))
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    62
        val b = p0._2 - a.scale(p0._1)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    63
        Time.ms((a.scale(threads) + b).ms max 0)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    64
      }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    65
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    66
      val mono_prefix = sorted_prefix(entries, e => -e._2.ms)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    67
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    68
      val is_mono = entries == mono_prefix
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    69
      val in_prefix = mono_prefix.length > 1 && threads <= mono_prefix.last._1
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    70
      val in_inflection =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    71
        !is_mono && mono_prefix.length > 1 && threads < entries.drop(mono_prefix.length).head._1
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    72
      if (is_mono || in_prefix || in_inflection) {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    73
        // Model with Amdahl's law
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    74
        val t_p =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    75
          Timing_Data.median_time(for {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    76
            (n, t0) <- mono_prefix
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    77
            (m, t1) <- mono_prefix
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    78
            if m != n
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    79
          } yield (t0 - t1).scale(n.toDouble * m / (m - n)))
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    80
        val t_c =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    81
          Timing_Data.median_time(for ((n, t) <- mono_prefix) yield t - t_p.scale(1.0 / n))
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    82
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    83
        def model(threads: Int): Time = t_c + t_p.scale(1.0 / threads)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    84
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    85
        if (is_mono || in_prefix) model(threads)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    86
        else {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    87
          val post_inflection = entries.drop(mono_prefix.length).head
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    88
          val inflection_threads = inflection_point(mono_prefix.last._1, post_inflection._1)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    89
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    90
          if (threads <= inflection_threads) model(threads)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    91
          else linear((inflection_threads, model(inflection_threads)), post_inflection)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    92
        }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    93
      } else {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    94
        // Piecewise linear
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    95
        val (p0, p1) =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    96
          if (entries.head._1 <= threads && threads <= entries.last._1) {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    97
            val split = entries.partition(_._1 <= threads)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    98
            (split._1.last, split._2.head)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    99
          } else {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   100
            val piece = if (threads < entries.head._1) entries.take(2) else entries.takeRight(2)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   101
            (piece.head, piece.last)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   102
          }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   103
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   104
        linear(p0, p1)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   105
      }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   106
    }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   107
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   108
    private def unify_hosts(job_name: String, on_host: String): List[(Int, Time)] = {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   109
      def unify(hostname: String, data: Timing_Entries) =
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   110
        data.mean_time.scale(hostname_factor(hostname, on_host))
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   111
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   112
      for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   113
        data <- data.by_job.get(job_name).toList
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   114
        (threads, data) <- data.by_threads
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   115
        entries = data.by_hostname.toList.map(unify)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   116
      } yield threads -> Timing_Data.median_time(entries)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   117
    }
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   118
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   119
    def estimate_threads(job_name: String, hostname: String, threads: Int): Option[Time] = {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   120
      for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   121
        data <- data.by_job.get(job_name)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   122
        data <- data.by_hostname.get(hostname)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   123
        entries = data.by_threads.toList.map((threads, data) => threads -> data.mean_time)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   124
        time <- data.by_threads.get(threads).map(_.mean_time).orElse(
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   125
          if (data.by_threads.size < 2) None else Some(approximate_threads(entries, threads)))
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   126
      } yield time
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   127
    }
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   128
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   129
    def global_threads_factor(from: Int, to: Int): Double = {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   130
      def median(xs: Iterable[Double]): Double = xs.toList.sorted.apply(xs.size / 2)
79036
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   131
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   132
      val estimates =
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   133
        for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   134
          (hostname, data) <- data.by_hostname
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   135
          job_name <- data.by_job.keys
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   136
          from_time <- estimate_threads(job_name, hostname, from)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   137
          to_time <- estimate_threads(job_name, hostname, to)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   138
        } yield from_time.ms.toDouble / to_time.ms
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   139
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   140
      if (estimates.nonEmpty) median(estimates)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   141
      else {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   142
        // unify hosts
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   143
        val estimates =
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   144
          for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   145
            (job_name, data) <- data.by_job
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   146
            hostname = data.by_hostname.keys.head
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   147
            entries = unify_hosts(job_name, hostname)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   148
            if entries.length > 1
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   149
          } yield
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   150
            approximate_threads(entries, from).ms.toDouble / approximate_threads(entries, to).ms
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   151
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   152
        if (estimates.nonEmpty) median(estimates)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   153
        else from.toDouble / to.toDouble
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   154
      }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   155
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   156
79026
6585acdd6505 clarified time estimation: does not use config;
Fabian Huch <huch@in.tum.de>
parents: 79025
diff changeset
   157
    def estimate(job_name: String, hostname: String, threads: Int): Time =
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
   158
      data.by_job.get(job_name) match {
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
   159
        case None => data.mean_time
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   160
        case Some(data) =>
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   161
          data.by_threads.get(threads) match {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   162
            case None => // interpolate threads
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   163
              estimate_threads(job_name, hostname, threads).getOrElse {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   164
                // per machine, try to approximate config for threads
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   165
                val approximated =
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   166
                  for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   167
                    hostname1 <- data.by_hostname.keys
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   168
                    estimate <- estimate_threads(job_name, hostname1, threads)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   169
                    factor = hostname_factor(hostname1, hostname)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   170
                  } yield estimate.scale(factor)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   171
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   172
                if (approximated.nonEmpty) Timing_Data.mean_time(approximated)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   173
                else {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   174
                  // no single machine where config can be approximated, unify data points
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   175
                  val unified_entries = unify_hosts(job_name, hostname)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   176
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   177
                  if (unified_entries.length > 1) approximate_threads(unified_entries, threads)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   178
                  else {
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   179
                    // only single data point, use global curve to approximate
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   180
                    val (job_threads, job_time) = unified_entries.head
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   181
                    job_time.scale(global_threads_factor(job_threads, threads))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   182
                  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   183
                }
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   184
              }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   185
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   186
            case Some(data) => // time for job/thread exists, interpolate machine
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   187
              data.by_hostname.get(hostname).map(_.mean_time).getOrElse {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   188
                Timing_Data.median_time(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   189
                  data.by_hostname.toList.map((hostname1, data) =>
78888
95bbf9a576b3 prefer Time.scale(), following Isabelle/ML;
wenzelm
parents: 78884
diff changeset
   190
                    data.mean_time.scale(hostname_factor(hostname1, hostname))))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   191
              }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   192
          }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   193
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   194
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   195
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   196
  object Timing_Data {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   197
    def median_time(obs: List[Time]): Time = obs.sortBy(_.ms).drop(obs.length / 2).head
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   198
    def mean_time(obs: Iterable[Time]): Time = Time.ms(obs.map(_.ms).sum / obs.size)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   199
78934
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   200
    private def dummy_entries(host: Host, host_factor: Double) =
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   201
      List(
78934
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   202
        Timing_Entry("dummy", host.info.hostname, 1, Time.minutes(5).scale(host_factor)),
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   203
        Timing_Entry("dummy", host.info.hostname, 8, Time.minutes(1).scale(host_factor)))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   204
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   205
    def make(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   206
      host_infos: Host_Infos,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   207
      build_history: List[(Build_Log.Meta_Info, Build_Log.Build_Info)],
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   208
    ): Timing_Data = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   209
      val hosts = host_infos.hosts
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   210
      val measurements =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   211
        for {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   212
          (meta_info, build_info) <- build_history
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   213
          build_host <- meta_info.get(Build_Log.Prop.build_host).toList
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   214
          (job_name, session_info) <- build_info.sessions.toList
78933
4f940d7293ea use only finished sessions in timing data;
Fabian Huch <huch@in.tum.de>
parents: 78932
diff changeset
   215
          if build_info.finished_sessions.contains(job_name)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   216
          hostname = session_info.hostname.getOrElse(build_host)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   217
          host <- hosts.find(_.info.hostname == build_host).toList
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   218
          threads = session_info.threads.getOrElse(host.info.num_cpus)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   219
        } yield (job_name, hostname, threads) -> session_info.timing.elapsed
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   220
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   221
      val entries =
78934
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   222
        if (measurements.isEmpty) {
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   223
          val default_host = host_infos.hosts.sorted(host_infos.host_speeds).head
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   224
          host_infos.hosts.flatMap(host =>
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   225
            dummy_entries(host, host_infos.host_factor(default_host, host)))
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   226
        }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   227
        else
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   228
          measurements.groupMap(_._1)(_._2).toList.map {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   229
            case ((job_name, hostname, threads), timings) =>
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   230
              Timing_Entry(job_name, hostname, threads, median_time(timings))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   231
          }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   232
79035
6beb60b508e6 clarified timing data vs. timing entries: full top-level data view vs. dynamic partial data;
Fabian Huch <huch@in.tum.de>
parents: 79034
diff changeset
   233
      new Timing_Data(Timing_Entries(entries), host_infos)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   234
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   235
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   236
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   237
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   238
  /* host information */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   239
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   240
  case class Host(info: isabelle.Host.Info, build: Build_Cluster.Host)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   241
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   242
  object Host_Infos {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   243
    def dummy: Host_Infos =
78846
966aa081929f tuned imports;
wenzelm
parents: 78845
diff changeset
   244
      new Host_Infos(
966aa081929f tuned imports;
wenzelm
parents: 78845
diff changeset
   245
        List(Host(isabelle.Host.Info("dummy", Nil, 8, Some(1.0)), Build_Cluster.Host("dummy"))))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   246
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   247
    def apply(build_hosts: List[Build_Cluster.Host], db: SQL.Database): Host_Infos = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   248
      def get_host(build_host: Build_Cluster.Host): Host = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   249
        val info =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   250
          isabelle.Host.read_info(db, build_host.name).getOrElse(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   251
            error("No benchmark for " + quote(build_host.name)))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   252
        Host(info, build_host)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   253
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   254
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   255
      new Host_Infos(build_hosts.map(get_host))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   256
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   257
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   258
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   259
  class Host_Infos private(val hosts: List[Host]) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   260
    private val by_hostname = hosts.map(host => host.info.hostname -> host).toMap
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   261
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   262
    def host_factor(from: Host, to: Host): Double =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   263
      from.info.benchmark_score.get / to.info.benchmark_score.get
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   264
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   265
    val host_speeds: Ordering[Host] =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   266
      Ordering.fromLessThan((host1, host2) => host_factor(host1, host2) > 1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   267
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   268
    def the_host(hostname: String): Host =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   269
      by_hostname.getOrElse(hostname, error("Unknown host " + quote(hostname)))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   270
    def the_host(node_info: Node_Info): Host = the_host(node_info.hostname)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   271
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   272
    def num_threads(node_info: Node_Info): Int =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   273
      if (node_info.rel_cpus.nonEmpty) node_info.rel_cpus.length
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   274
      else the_host(node_info).info.num_cpus
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   275
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   276
    def available(state: Build_Process.State): Resources = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   277
      val allocated =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   278
        state.running.values.map(_.node_info).groupMapReduce(the_host)(List(_))(_ ::: _)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   279
      Resources(this, allocated)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   280
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   281
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   282
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   283
79029
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   284
  /* offline tracking of job configurations and resource allocations */
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   285
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   286
  object Config {
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   287
    def from_job(job: Build_Process.Job): Config = Config(job.name, job.node_info)
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   288
  }
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   289
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   290
  case class Config(job_name: String, node_info: Node_Info) {
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   291
    def job_of(start_time: Time): Build_Process.Job =
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   292
      Build_Process.Job(job_name, "", "", node_info, Date(start_time), None)
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   293
  }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   294
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   295
  case class Resources(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   296
    host_infos: Host_Infos,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   297
    allocated_nodes: Map[Host, List[Node_Info]]
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   298
  ) {
78973
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   299
    def unused_nodes(threads: Int): List[Node_Info] = {
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   300
      val fully_allocated =
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   301
        host_infos.hosts.foldLeft(this) { case (resources, host) =>
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   302
          if (!resources.available(host, threads)) resources
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   303
          else resources.allocate(resources.next_node(host, threads))
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   304
        }
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   305
      val used_nodes = allocated_nodes.values.flatten.toSet
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   306
      fully_allocated.allocated_nodes.values.flatten.toList.filterNot(used_nodes.contains)
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   307
    }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   308
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   309
    def allocated(host: Host): List[Node_Info] = allocated_nodes.getOrElse(host, Nil)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   310
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   311
    def allocate(node: Node_Info): Resources = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   312
      val host = host_infos.the_host(node)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   313
      copy(allocated_nodes = allocated_nodes + (host -> (node :: allocated(host))))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   314
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   315
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   316
    def try_allocate_tasks(
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   317
      hosts: List[(Host, Int)],
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   318
      tasks: List[(Build_Process.Task, Int, Int)],
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   319
    ): (List[Config], Resources) =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   320
      tasks match {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   321
        case Nil => (Nil, this)
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   322
        case (task, min_threads, max_threads) :: tasks =>
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   323
          val (config, resources) =
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   324
            hosts.find((host, _) => available(host, min_threads)) match {
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   325
              case Some((host, host_max_threads)) =>
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   326
                val free_threads = host.info.num_cpus - ((host.build.jobs - 1) * host_max_threads)
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   327
                val node_info = next_node(host, (min_threads max free_threads) min max_threads)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   328
                (Some(Config(task.name, node_info)), allocate(node_info))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   329
              case None => (None, this)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   330
            }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   331
          val (configs, resources1) = resources.try_allocate_tasks(hosts, tasks)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   332
          (configs ++ config, resources1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   333
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   334
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   335
    def next_node(host: Host, threads: Int): Node_Info = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   336
      val numa_node_num_cpus = host.info.num_cpus / (host.info.numa_nodes.length max 1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   337
      def explicit_cpus(node_info: Node_Info): List[Int] =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   338
        if (node_info.rel_cpus.nonEmpty) node_info.rel_cpus else (0 until numa_node_num_cpus).toList
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   339
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   340
      val used_nodes = allocated(host).groupMapReduce(_.numa_node)(explicit_cpus)(_ ::: _)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   341
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   342
      val available_nodes = host.info.numa_nodes
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   343
      val numa_node =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   344
        if (!host.build.numa) None
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   345
        else available_nodes.sortBy(n => used_nodes.getOrElse(Some(n), Nil).length).headOption
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   346
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   347
      val used_cpus = used_nodes.getOrElse(numa_node, Nil).toSet
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   348
      val available_cpus = (0 until numa_node_num_cpus).filterNot(used_cpus.contains).toList
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   349
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   350
      val rel_cpus = if (available_cpus.length >= threads) available_cpus.take(threads) else Nil
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   351
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   352
      Node_Info(host.info.hostname, numa_node, rel_cpus)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   353
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   354
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   355
    def available(host: Host, threads: Int): Boolean = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   356
      val used = allocated(host)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   357
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   358
      if (used.length >= host.build.jobs) false
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   359
      else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   360
        if (host.info.numa_nodes.length <= 1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   361
          used.map(host_infos.num_threads).sum + threads <= host.info.num_cpus
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   362
        else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   363
          def node_threads(n: Int): Int =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   364
            used.filter(_.numa_node.contains(n)).map(host_infos.num_threads).sum
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   365
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   366
          host.info.numa_nodes.exists(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   367
            node_threads(_) + threads <= host.info.num_cpus / host.info.numa_nodes.length)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   368
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   369
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   370
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   371
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   372
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   373
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   374
  /* schedule generation */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   375
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   376
  case class State(build_state: Build_Process.State, current_time: Time) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   377
    def start(config: Config): State =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   378
      copy(build_state =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   379
        build_state.copy(running = build_state.running +
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   380
          (config.job_name -> config.job_of(current_time))))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   381
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   382
    def step(timing_data: Timing_Data): State = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   383
      val remaining =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   384
        build_state.running.values.toList.map { job =>
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   385
          val elapsed = current_time - job.start_date.time
79026
6585acdd6505 clarified time estimation: does not use config;
Fabian Huch <huch@in.tum.de>
parents: 79025
diff changeset
   386
          val threads = timing_data.host_infos.num_threads(job.node_info)
6585acdd6505 clarified time estimation: does not use config;
Fabian Huch <huch@in.tum.de>
parents: 79025
diff changeset
   387
          val predicted = timing_data.estimate(job.name, job.node_info.hostname, threads)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   388
          val remaining = if (elapsed > predicted) Time.zero else predicted - elapsed
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   389
          job -> remaining
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   390
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   391
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   392
      if (remaining.isEmpty) error("Schedule step without running sessions")
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   393
      else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   394
        val (job, elapsed) = remaining.minBy(_._2.ms)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   395
        State(build_state.remove_running(job.name).remove_pending(job.name), current_time + elapsed)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   396
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   397
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   398
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   399
    def finished: Boolean = build_state.pending.isEmpty && build_state.running.isEmpty
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   400
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   401
78932
Fabian Huch <huch@in.tum.de>
parents: 78931
diff changeset
   402
  trait Scheduler {
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   403
    def next(state: Build_Process.State): List[Config]
78931
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   404
    def build_duration(build_state: Build_Process.State): Time
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   405
  }
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   406
79027
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   407
  abstract class Heuristic(timing_data: Timing_Data, max_threads_limit: Int) extends Scheduler {
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   408
    val host_infos = timing_data.host_infos
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   409
    val ordered_hosts = host_infos.hosts.sorted(host_infos.host_speeds)
79027
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   410
    val max_threads = host_infos.hosts.map(_.info.num_cpus).max min max_threads_limit
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   411
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   412
    def best_time(job_name: String): Time = {
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   413
      val host = ordered_hosts.last
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   414
      val threads = timing_data.best_threads(job_name, max_threads) min host.info.num_cpus
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   415
      timing_data.estimate(job_name, host.info.hostname, threads)
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   416
    }
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   417
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   418
    def build_duration(build_state: Build_Process.State): Time = {
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   419
      @tailrec
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   420
      def simulate(state: State): State =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   421
        if (state.finished) state
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   422
        else {
78932
Fabian Huch <huch@in.tum.de>
parents: 78931
diff changeset
   423
          val state1 = next(state.build_state).foldLeft(state)(_.start(_)).step(timing_data)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   424
          simulate(state1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   425
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   426
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   427
      val start = Time.now()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   428
      simulate(State(build_state, start)).current_time - start
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   429
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   430
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   431
78931
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   432
  class Meta_Heuristic(heuristics: List[Heuristic]) extends Scheduler {
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   433
    require(heuristics.nonEmpty)
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   434
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   435
    def best_result(state: Build_Process.State): (Heuristic, Time) =
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   436
      heuristics.map(heuristic => heuristic -> heuristic.build_duration(state)).minBy(_._2.ms)
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   437
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   438
    def next(state: Build_Process.State): List[Config] = best_result(state)._1.next(state)
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   439
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   440
    def build_duration(state: Build_Process.State): Time = best_result(state)._2
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   441
  }
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   442
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   443
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   444
  /* heuristics */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   445
79027
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   446
  abstract class Path_Heuristic(
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   447
    timing_data: Timing_Data,
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   448
    sessions_structure: Sessions.Structure,
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   449
    max_threads_limit: Int
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   450
  ) extends Heuristic(timing_data, max_threads_limit) {
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   451
    /* pre-computed properties for efficient heuristic */
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   452
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   453
    type Node = String
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   454
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   455
    val build_graph = sessions_structure.build_graph
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   456
    val all_maximals = build_graph.maximals.toSet
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   457
    val maximals_preds =
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   458
      all_maximals.map(node => node -> build_graph.all_preds(List(node)).toSet).toMap
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   459
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   460
    val best_times = build_graph.keys.map(node => node -> best_time(node)).toMap
78974
Fabian Huch <huch@in.tum.de>
parents: 78973
diff changeset
   461
    val remaining_time_ms = build_graph.node_height(best_times(_).ms)
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   462
78974
Fabian Huch <huch@in.tum.de>
parents: 78973
diff changeset
   463
    def elapsed_times(node: Node): Map[Node, Time] =
Fabian Huch <huch@in.tum.de>
parents: 78973
diff changeset
   464
      build_graph.reachable_length(best_times(_).ms, build_graph.imm_succs, List(node)).map(
Fabian Huch <huch@in.tum.de>
parents: 78973
diff changeset
   465
        (node, ms) => node -> Time.ms(ms))
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   466
78974
Fabian Huch <huch@in.tum.de>
parents: 78973
diff changeset
   467
    def path_times(node: Node): Map[Node, Time] = {
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   468
      val maximals = all_maximals.intersect(build_graph.all_succs(List(node)).toSet)
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   469
      val elapsed_time = elapsed_times(node)
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   470
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   471
      maximals
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   472
        .flatMap(node => maximals_preds(node).map(_ -> elapsed_time(node)))
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   473
        .groupMapReduce(_._1)(_._2)(_ max _)
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   474
    }
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   475
78972
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   476
    def parallel_paths(minimals: Set[Node], pred: Node => Boolean = _ => true): Int = {
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   477
      def start(node: Node): (Node, Time) = node -> best_times(node)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   478
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   479
      def pass_time(elapsed: Time)(node: Node, time: Time): (Node, Time) =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   480
        node -> (time - elapsed)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   481
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   482
      def parallel_paths(running: Map[Node, Time]): (Int, Map[Node, Time]) =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   483
        if (running.isEmpty) (0, running)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   484
        else {
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   485
          def get_next(node: Node): List[Node] =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   486
            build_graph.imm_succs(node).filter(pred).filter(
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   487
              build_graph.imm_preds(_).intersect(running.keySet).isEmpty).toList
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   488
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   489
          val (next, elapsed) = running.minBy(_._2.ms)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   490
          val (remaining, finished) =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   491
            running.toList.map(pass_time(elapsed)).partition(_._2 > Time.zero)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   492
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   493
          val running1 =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   494
            remaining.map(pass_time(elapsed)).toMap ++
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   495
              finished.map(_._1).flatMap(get_next).map(start)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   496
          val (res, running2) = parallel_paths(running1)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   497
          (res max running1.size, running2)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   498
        }
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   499
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   500
      parallel_paths(minimals.map(start).toMap)._1
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   501
    }
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   502
  }
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   503
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   504
  class Timing_Heuristic(
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   505
    threshold: Time,
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   506
    timing_data: Timing_Data,
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   507
    sessions_structure: Sessions.Structure,
79027
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   508
    max_threads_limit: Int = 8
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   509
  ) extends Path_Heuristic(timing_data, sessions_structure, max_threads_limit) {
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   510
    val critical_path_nodes =
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   511
      build_graph.keys.map(node =>
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   512
        node -> path_times(node).filter((_, time) => time > threshold).keySet).toMap
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   513
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   514
    def next(state: Build_Process.State): List[Config] = {
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   515
      val resources = host_infos.available(state)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   516
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   517
      def best_threads(task: Build_Process.Task): Int =
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   518
        timing_data.best_threads(task.name, max_threads)
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   519
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   520
      val rev_ordered_hosts = ordered_hosts.reverse.map(_ -> max_threads)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   521
79021
1c91e884035d properly incorporate running tasks into timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79020
diff changeset
   522
      val resources0 = host_infos.available(state.copy(running = Map.empty))
1c91e884035d properly incorporate running tasks into timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79020
diff changeset
   523
      val max_parallel = parallel_paths(state.ready.map(_.name).toSet)
1c91e884035d properly incorporate running tasks into timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79020
diff changeset
   524
      val fully_parallelizable = max_parallel <= resources0.unused_nodes(max_threads).length
78973
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   525
d91e131840a0 timing heuristic: parallelize more aggressively to utilize hosts fully;
Fabian Huch <huch@in.tum.de>
parents: 78972
diff changeset
   526
      if (fully_parallelizable) {
79020
ef76705bf402 clarified ready vs. next ready;
Fabian Huch <huch@in.tum.de>
parents: 79019
diff changeset
   527
        val all_tasks = state.next_ready.map(task => (task, best_threads(task), best_threads(task)))
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   528
        resources.try_allocate_tasks(rev_ordered_hosts, all_tasks)._1
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   529
      }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   530
      else {
79021
1c91e884035d properly incorporate running tasks into timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79020
diff changeset
   531
        val critical_nodes = state.ready.toSet.flatMap(task => critical_path_nodes(task.name))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   532
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   533
        val (critical, other) =
79020
ef76705bf402 clarified ready vs. next ready;
Fabian Huch <huch@in.tum.de>
parents: 79019
diff changeset
   534
          state.next_ready.sortBy(task => remaining_time_ms(task.name)).reverse.partition(task =>
78974
Fabian Huch <huch@in.tum.de>
parents: 78973
diff changeset
   535
            critical_nodes.contains(task.name))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   536
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   537
        val critical_tasks = critical.map(task => (task, best_threads(task), best_threads(task)))
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   538
        val other_tasks = other.map(task => (task, 1, best_threads(task)))
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   539
79021
1c91e884035d properly incorporate running tasks into timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79020
diff changeset
   540
        val critical_minimals = critical_nodes.intersect(state.ready.map(_.name).toSet)
1c91e884035d properly incorporate running tasks into timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79020
diff changeset
   541
        val max_critical_parallel = parallel_paths(critical_minimals, critical_nodes.contains)
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   542
        val (critical_hosts, other_hosts) = rev_ordered_hosts.splitAt(max_critical_parallel)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   543
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   544
        val (configs1, resources1) = resources.try_allocate_tasks(critical_hosts, critical_tasks)
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   545
        val (configs2, _) = resources1.try_allocate_tasks(other_hosts, other_tasks)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   546
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   547
        configs1 ::: configs2
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   548
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   549
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   550
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   551
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   552
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   553
  /* process for scheduled build */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   554
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   555
  abstract class Scheduled_Build_Process(
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   556
    build_context: Build.Context,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   557
    build_progress: Progress,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   558
    server: SSH.Server,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   559
  ) extends Build_Process(build_context, build_progress, server) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   560
    protected val start_date = Date.now()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   561
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   562
    def init_scheduler(timing_data: Timing_Data): Scheduler
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   563
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   564
    /* global resources with common close() operation */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   565
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   566
    private final lazy val _log_store: Build_Log.Store = Build_Log.store(build_options)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   567
    private final lazy val _log_database: SQL.Database =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   568
      try {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   569
        val db = _log_store.open_database(server = this.server)
78851
db37cae970a6 more robust init_database();
wenzelm
parents: 78849
diff changeset
   570
        _log_store.init_database(db)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   571
        db
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   572
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   573
      catch { case exn: Throwable => close(); throw exn }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   574
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   575
    override def close(): Unit = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   576
      super.close()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   577
      Option(_log_database).foreach(_.close())
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   578
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   579
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   580
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   581
    /* previous results via build log */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   582
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   583
    override def open_build_cluster(): Build_Cluster = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   584
      val build_cluster = super.open_build_cluster()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   585
      build_cluster.init()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   586
      if (build_context.master && build_context.max_jobs > 0) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   587
        val benchmark_options = build_options.string("build_hostname") = hostname
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   588
        Benchmark.benchmark(benchmark_options, progress)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   589
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   590
      build_cluster.benchmark()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   591
      build_cluster
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   592
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   593
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   594
    private val timing_data: Timing_Data = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   595
      val cluster_hosts: List[Build_Cluster.Host] =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   596
        if (build_context.max_jobs == 0) build_context.build_hosts
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   597
        else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   598
          val local_build_host =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   599
            Build_Cluster.Host(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   600
              hostname, jobs = build_context.max_jobs, numa = build_context.numa_shuffling)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   601
          local_build_host :: build_context.build_hosts
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   602
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   603
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   604
      val host_infos = Host_Infos(cluster_hosts, _host_database)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   605
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   606
      val build_history =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   607
        for {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   608
          log_name <- _log_database.execute_query_statement(
78849
df162316b6a7 clarified names;
wenzelm
parents: 78846
diff changeset
   609
            Build_Log.private_data.meta_info_table.select(List(Build_Log.private_data.log_name)),
df162316b6a7 clarified names;
wenzelm
parents: 78846
diff changeset
   610
            List.from[String], res => res.string(Build_Log.private_data.log_name))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   611
          meta_info <- _log_store.read_meta_info(_log_database, log_name)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   612
          build_info = _log_store.read_build_info(_log_database, log_name)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   613
        } yield (meta_info, build_info)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   614
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   615
      Timing_Data.make(host_infos, build_history)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   616
    }
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   617
    private val scheduler = init_scheduler(timing_data)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   618
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   619
    def write_build_log(results: Build.Results, state: Build_Process.State.Results): Unit = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   620
      val sessions =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   621
        for {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   622
          (session_name, result) <- state.toList
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   623
          if !result.current
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   624
        } yield {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   625
          val info = build_context.sessions_structure(session_name)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   626
          val entry =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   627
            if (!results.cancelled(session_name)) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   628
              val status =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   629
                if (result.ok) Build_Log.Session_Status.finished
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   630
                else Build_Log.Session_Status.failed
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   631
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   632
              Build_Log.Session_Entry(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   633
                chapter = info.chapter,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   634
                groups = info.groups,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   635
                hostname = Some(result.node_info.hostname),
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   636
                threads = Some(timing_data.host_infos.num_threads(result.node_info)),
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   637
                timing = result.process_result.timing,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   638
                sources = Some(result.output_shasum.digest.toString),
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   639
                status = Some(status))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   640
            }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   641
            else
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   642
              Build_Log.Session_Entry(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   643
                chapter = info.chapter,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   644
                groups = info.groups,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   645
                status = Some(Build_Log.Session_Status.cancelled))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   646
          session_name -> entry
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   647
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   648
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   649
      val settings =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   650
        Build_Log.Settings.all_settings.map(_.name).map(name =>
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   651
          name -> Isabelle_System.getenv(name))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   652
      val props =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   653
        List(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   654
          Build_Log.Prop.build_id.name -> build_context.build_uuid,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   655
          Build_Log.Prop.build_engine.name -> build_context.engine.name,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   656
          Build_Log.Prop.build_host.name -> hostname,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   657
          Build_Log.Prop.build_start.name -> Build_Log.print_date(start_date))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   658
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   659
      val meta_info = Build_Log.Meta_Info(props, settings)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   660
      val build_info = Build_Log.Build_Info(sessions.toMap)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   661
      val log_name = Build_Log.log_filename(engine = engine_name, date = start_date)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   662
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   663
      _log_store.update_sessions(_log_database, log_name.file_name, build_info)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   664
      _log_store.update_meta_info(_log_database, log_name.file_name, meta_info)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   665
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   666
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   667
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   668
    /* build process */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   669
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   670
    case class Cache(state: Build_Process.State, configs: List[Config], estimate: Date) {
78975
4a5d35b35aeb better invalidation for schedule cache (only on relevant changes);
Fabian Huch <huch@in.tum.de>
parents: 78974
diff changeset
   671
      def is_current(state: Build_Process.State): Boolean =
4a5d35b35aeb better invalidation for schedule cache (only on relevant changes);
Fabian Huch <huch@in.tum.de>
parents: 78974
diff changeset
   672
        this.state.pending.nonEmpty && this.state.results == state.results
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   673
      def is_current_estimate(estimate: Date): Boolean =
78975
4a5d35b35aeb better invalidation for schedule cache (only on relevant changes);
Fabian Huch <huch@in.tum.de>
parents: 78974
diff changeset
   674
        Math.abs((this.estimate.time - estimate.time).ms) < Time.minutes(1).ms
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   675
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   676
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   677
    private var cache = Cache(Build_Process.State(), Nil, Date.now())
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   678
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   679
    override def next_node_info(state: Build_Process.State, session_name: String): Node_Info = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   680
      val configs =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   681
        if (cache.is_current(state)) cache.configs
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   682
        else scheduler.next(state)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   683
      configs.find(_.job_name == session_name).get.node_info
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   684
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   685
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   686
    def is_current(state: Build_Process.State, session_name: String): Boolean =
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   687
      state.ancestor_results(session_name) match {
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   688
        case Some(ancestor_results) if ancestor_results.forall(_.current) =>
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   689
          val sources_shasum = state.sessions(session_name).sources_shasum
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   690
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   691
          val input_shasum =
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   692
            if (ancestor_results.isEmpty) ML_Process.bootstrap_shasum()
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   693
            else SHA1.flat_shasum(ancestor_results.map(_.output_shasum))
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   694
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   695
          val store_heap =
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   696
            build_context.build_heap || Sessions.is_pure(session_name) ||
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   697
              state.sessions.iterator.exists(_.ancestors.contains(session_name))
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   698
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   699
          store.check_output(
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   700
            _database_server, session_name,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   701
            session_options = build_context.sessions_structure(session_name).options,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   702
            sources_shasum = sources_shasum,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   703
            input_shasum = input_shasum,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   704
            fresh_build = build_context.fresh_build,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   705
            store_heap = store_heap)._1
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   706
        case _ => false
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   707
    }
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   708
78970
5d38b72a1a66 finalize scheduled build only on master node;
Fabian Huch <huch@in.tum.de>
parents: 78969
diff changeset
   709
    override def next_jobs(state: Build_Process.State): List[String] = {
5d38b72a1a66 finalize scheduled build only on master node;
Fabian Huch <huch@in.tum.de>
parents: 78969
diff changeset
   710
      val finalize_limit = if (build_context.master) Int.MaxValue else 0
5d38b72a1a66 finalize scheduled build only on master node;
Fabian Huch <huch@in.tum.de>
parents: 78969
diff changeset
   711
79020
ef76705bf402 clarified ready vs. next ready;
Fabian Huch <huch@in.tum.de>
parents: 79019
diff changeset
   712
      if (progress.stopped) state.next_ready.map(_.name).take(finalize_limit)
78975
4a5d35b35aeb better invalidation for schedule cache (only on relevant changes);
Fabian Huch <huch@in.tum.de>
parents: 78974
diff changeset
   713
      else if (cache.is_current(state)) cache.configs.map(_.job_name).filterNot(state.is_running)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   714
      else {
79020
ef76705bf402 clarified ready vs. next ready;
Fabian Huch <huch@in.tum.de>
parents: 79019
diff changeset
   715
        val current = state.next_ready.filter(task => is_current(state, task.name))
78970
5d38b72a1a66 finalize scheduled build only on master node;
Fabian Huch <huch@in.tum.de>
parents: 78969
diff changeset
   716
        if (current.nonEmpty) current.map(_.name).take(finalize_limit)
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   717
        else {
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   718
          val start = Time.now()
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   719
          val next = scheduler.next(state)
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   720
          val estimate = Date(Time.now() + scheduler.build_duration(state))
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   721
          val elapsed = Time.now() - start
78884
0233d5a5a4ca improved build messages;
Fabian Huch <huch@in.tum.de>
parents: 78851
diff changeset
   722
78976
8da0eedd562c tuned message;
Fabian Huch <huch@in.tum.de>
parents: 78975
diff changeset
   723
          val timing_msg = if (elapsed.is_relevant) " (took " + elapsed.message + ")" else ""
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   724
          progress.echo_if(build_context.master && !cache.is_current_estimate(estimate),
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   725
            "Estimated completion: " + estimate + timing_msg)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   726
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   727
          val configs = next.filter(_.node_info.hostname == hostname)
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   728
          cache = Cache(state, configs, estimate)
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   729
          configs.map(_.job_name)
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   730
        }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   731
      }
78970
5d38b72a1a66 finalize scheduled build only on master node;
Fabian Huch <huch@in.tum.de>
parents: 78969
diff changeset
   732
    }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   733
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   734
    override def run(): Build.Results = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   735
      val results = super.run()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   736
      if (build_context.master) write_build_log(results, snapshot().results)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   737
      results
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   738
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   739
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   740
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   741
  class Engine extends Build.Engine(engine_name) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   742
    override def open_build_process(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   743
      context: Build.Context,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   744
      progress: Progress,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   745
      server: SSH.Server
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   746
    ): Build_Process =
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   747
      new Scheduled_Build_Process(context, progress, server) {
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   748
        def init_scheduler(timing_data: Timing_Data): Scheduler = {
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   749
          val heuristics =
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   750
            List(5, 10, 20).map(minutes =>
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   751
              Timing_Heuristic(
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   752
                Time.minutes(minutes),
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   753
                timing_data,
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   754
                context.build_deps.sessions_structure))
78931
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   755
          new Meta_Heuristic(heuristics)
78928
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   756
        }
6c2c60b852e0 move timing data into scheduler for more efficient heuristics (e.g., with pre-calculated values);
Fabian Huch <huch@in.tum.de>
parents: 78888
diff changeset
   757
      }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   758
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   759
}