src/Pure/Tools/build_schedule.scala
author Fabian Huch <huch@in.tum.de>
Wed, 06 Dec 2023 18:18:56 +0100
changeset 79181 9d6d559c9fde
parent 79180 229f49204603
child 79182 6202d0ff36b4
permissions -rw-r--r--
added graphical representation of build schedules;
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
  /* organized historic timing information (extracted from build logs) */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    15
79085
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
    16
  case class Timing_Entry(job_name: String, hostname: String, threads: Int, timing: Timing) {
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
    17
    def elapsed: Time = timing.elapsed
79087
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
    18
    def proper_cpu: Option[Time] = timing.cpu.proper_ms.map(Time.ms)
79085
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
    19
  }
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
79041
ff7d48e776ab properly sort entries;
Fabian Huch <huch@in.tum.de>
parents: 79040
diff changeset
    52
    private def approximate_threads(entries_unsorted: List[(Int, Time)], threads: Int): Time = {
ff7d48e776ab properly sort entries;
Fabian Huch <huch@in.tum.de>
parents: 79040
diff changeset
    53
      val entries = entries_unsorted.sortBy(_._1)
ff7d48e776ab properly sort entries;
Fabian Huch <huch@in.tum.de>
parents: 79040
diff changeset
    54
79036
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    55
      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
    56
        xs match {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    57
          case x1 :: x2 :: xs =>
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    58
            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
    59
          case xs => xs
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    60
        }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    61
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    62
      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
    63
        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
    64
        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
    65
        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
    66
      }
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 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
    69
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    70
      val is_mono = entries == mono_prefix
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    71
      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
    72
      val in_inflection =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    73
        !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
    74
      if (is_mono || in_prefix || in_inflection) {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    75
        // Model with Amdahl's law
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    76
        val t_p =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    77
          Timing_Data.median_time(for {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    78
            (n, t0) <- mono_prefix
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    79
            (m, t1) <- mono_prefix
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    80
            if m != n
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    81
          } 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
    82
        val t_c =
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    83
          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
    84
79086
59d5d1e26393 lower bound for approximated times;
Fabian Huch <huch@in.tum.de>
parents: 79085
diff changeset
    85
        def model(threads: Int): Time = Time.ms((t_c + t_p.scale(1.0 / threads)).ms max 0)
79036
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    86
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    87
        if (is_mono || in_prefix) model(threads)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    88
        else {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    89
          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
    90
          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
    91
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    92
          if (threads <= inflection_threads) model(threads)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    93
          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
    94
        }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    95
      } else {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    96
        // Piecewise linear
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
    97
        val (p0, p1) =
79042
1a9f3806987d proper split;
Fabian Huch <huch@in.tum.de>
parents: 79041
diff changeset
    98
          if (entries.head._1 < threads && threads < entries.last._1) {
1a9f3806987d proper split;
Fabian Huch <huch@in.tum.de>
parents: 79041
diff changeset
    99
            val split = entries.partition(_._1 < threads)
79036
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   100
            (split._1.last, split._2.head)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   101
          } else {
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   102
            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
   103
            (piece.head, piece.last)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   104
          }
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
        linear(p0, p1)
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   107
      }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   108
    }
be42ba4b4672 split actual approximation from data handling;
Fabian Huch <huch@in.tum.de>
parents: 79035
diff changeset
   109
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   110
    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
   111
      def unify(hostname: String, data: Timing_Entries) =
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   112
        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
   113
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   114
      for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   115
        data <- data.by_job.get(job_name).toList
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   116
        (threads, data) <- data.by_threads
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   117
        entries = data.by_hostname.toList.map(unify)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   118
      } yield threads -> Timing_Data.median_time(entries)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   119
    }
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   120
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   121
    def estimate_threads(job_name: String, hostname: String, threads: Int): Option[Time] = {
79087
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   122
      def try_approximate(data: Timing_Entries): Option[Time] = {
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   123
        val entries =
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   124
          data.by_threads.toList match {
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   125
            case List((i, Timing_Entries(List(entry)))) if i != 1 =>
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   126
              (i, data.mean_time) :: entry.proper_cpu.map(1 -> _).toList
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   127
            case entries => entries.map((threads, data) => threads -> data.mean_time)
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   128
          }
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   129
        if (entries.size < 2) None else Some(approximate_threads(entries, threads))
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   130
      }
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   131
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   132
      for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   133
        data <- data.by_job.get(job_name)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   134
        data <- data.by_hostname.get(hostname)
79087
3620010c410a use cpu time for approximation;
Fabian Huch <huch@in.tum.de>
parents: 79086
diff changeset
   135
        time <- data.by_threads.get(threads).map(_.mean_time).orElse(try_approximate(data))
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   136
      } yield time
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   137
    }
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   138
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   139
    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
   140
      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
   141
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   142
      val estimates =
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   143
        for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   144
          (hostname, data) <- data.by_hostname
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   145
          job_name <- data.by_job.keys
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   146
          from_time <- estimate_threads(job_name, hostname, from)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   147
          to_time <- estimate_threads(job_name, hostname, to)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   148
        } 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
   149
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   150
      if (estimates.nonEmpty) median(estimates)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   151
      else {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   152
        // unify hosts
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   153
        val estimates =
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   154
          for {
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   155
            (job_name, data) <- data.by_job
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   156
            hostname = data.by_hostname.keys.head
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   157
            entries = unify_hosts(job_name, hostname)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   158
            if entries.length > 1
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   159
          } yield
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   160
            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
   161
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   162
        if (estimates.nonEmpty) median(estimates)
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   163
        else from.toDouble / to.toDouble
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   164
      }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   165
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   166
79178
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   167
    private var cache: Map[(String, String, Int), Time] = Map.empty
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   168
    def estimate(job_name: String, hostname: String, threads: Int): Time = {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   169
      def estimate: Time =
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   170
        data.by_job.get(job_name) match {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   171
          case None =>
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   172
            // no data for job, take average of other jobs for given threads
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   173
            val job_estimates = data.by_job.keys.flatMap(estimate_threads(_, hostname, threads))
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   174
            if (job_estimates.nonEmpty) Timing_Data.mean_time(job_estimates)
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   175
            else {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   176
              // no other job to estimate from, use global curve to approximate any other job
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   177
              val (threads1, data1) = data.by_threads.head
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   178
              data1.mean_time.scale(global_threads_factor(threads1, threads))
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   179
            }
79038
cd7c1acc9cf2 better estimation for unknown jobs;
Fabian Huch <huch@in.tum.de>
parents: 79037
diff changeset
   180
79178
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   181
          case Some(data) =>
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   182
            data.by_threads.get(threads) match {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   183
              case None => // interpolate threads
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   184
                estimate_threads(job_name, hostname, threads).getOrElse {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   185
                  // per machine, try to approximate config for threads
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   186
                  val approximated =
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   187
                    for {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   188
                      hostname1 <- data.by_hostname.keys
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   189
                      estimate <- estimate_threads(job_name, hostname1, threads)
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   190
                      factor = hostname_factor(hostname1, hostname)
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   191
                    } yield estimate.scale(factor)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   192
79178
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   193
                  if (approximated.nonEmpty) Timing_Data.mean_time(approximated)
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   194
                  else {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   195
                    // no single machine where config can be approximated, unify data points
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   196
                    val unified_entries = unify_hosts(job_name, hostname)
79037
1b3a6cc4a2bf clarified and tuned timing estimation;
Fabian Huch <huch@in.tum.de>
parents: 79036
diff changeset
   197
79178
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   198
                    if (unified_entries.length > 1) approximate_threads(unified_entries, threads)
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   199
                    else {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   200
                      // only single data point, use global curve to approximate
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   201
                      val (job_threads, job_time) = unified_entries.head
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   202
                      job_time.scale(global_threads_factor(job_threads, threads))
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   203
                    }
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
                }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   206
79178
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   207
              case Some(data) => // time for job/thread exists, interpolate machine
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   208
                data.by_hostname.get(hostname).map(_.mean_time).getOrElse {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   209
                  Timing_Data.median_time(
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   210
                    data.by_hostname.toList.map((hostname1, data) =>
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   211
                      data.mean_time.scale(hostname_factor(hostname1, hostname))))
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   212
                }
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   213
            }
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   214
        }
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   215
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   216
      cache.get(job_name, hostname, threads) match {
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   217
        case Some(time) => time
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   218
        case None =>
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   219
          val time = estimate
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   220
          cache = cache + ((job_name, hostname, threads) -> time)
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   221
          time
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   222
      }
79178
96e5d12c82fd performance tuning: cache estimates;
Fabian Huch <huch@in.tum.de>
parents: 79110
diff changeset
   223
    }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   224
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   225
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   226
  object Timing_Data {
79085
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
   227
    def median_timing(obs: List[Timing]): Timing = obs.sortBy(_.elapsed.ms).apply(obs.length / 2)
79039
Fabian Huch <huch@in.tum.de>
parents: 79038
diff changeset
   228
    def median_time(obs: List[Time]): Time = obs.sortBy(_.ms).apply(obs.length / 2)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   229
    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
   230
79085
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
   231
    private def dummy_entries(host: Host, host_factor: Double) = {
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
   232
      val baseline = Time.minutes(5).scale(host_factor)
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
   233
      val gc = Time.seconds(10).scale(host_factor)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   234
      List(
79103
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   235
        Timing_Entry("dummy", host.name, 1, Timing(baseline, baseline, gc)),
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   236
        Timing_Entry("dummy", host.name, 8, Timing(baseline.scale(0.2), baseline, gc)))
79085
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
   237
    }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   238
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   239
    def make(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   240
      host_infos: Host_Infos,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   241
      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
   242
    ): Timing_Data = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   243
      val hosts = host_infos.hosts
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   244
      val measurements =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   245
        for {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   246
          (meta_info, build_info) <- build_history
79083
2d18d481c115 filter hosts properly;
Fabian Huch <huch@in.tum.de>
parents: 79073
diff changeset
   247
          build_host = meta_info.get(Build_Log.Prop.build_host)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   248
          (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
   249
          if build_info.finished_sessions.contains(job_name)
79083
2d18d481c115 filter hosts properly;
Fabian Huch <huch@in.tum.de>
parents: 79073
diff changeset
   250
          hostname <- session_info.hostname.orElse(build_host).toList
2d18d481c115 filter hosts properly;
Fabian Huch <huch@in.tum.de>
parents: 79073
diff changeset
   251
          host <- hosts.find(_.info.hostname == hostname).toList
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   252
          threads = session_info.threads.getOrElse(host.info.num_cpus)
79085
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
   253
        } yield (job_name, hostname, threads) -> session_info.timing
78845
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
      val entries =
78934
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   256
        if (measurements.isEmpty) {
79084
dd689c4ab688 consistent hosts ordering;
Fabian Huch <huch@in.tum.de>
parents: 79083
diff changeset
   257
          val default_host = host_infos.hosts.sorted(host_infos.host_speeds).last
78934
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   258
          host_infos.hosts.flatMap(host =>
5553a86a1091 proper dummy timing entries;
Fabian Huch <huch@in.tum.de>
parents: 78933
diff changeset
   259
            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
   260
        }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   261
        else
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   262
          measurements.groupMap(_._1)(_._2).toList.map {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   263
            case ((job_name, hostname, threads), timings) =>
79085
cf51ccfd3e39 use full timing information in build schedule;
Fabian Huch <huch@in.tum.de>
parents: 79084
diff changeset
   264
              Timing_Entry(job_name, hostname, threads, median_timing(timings))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   265
          }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   266
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
   267
      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
   268
    }
79090
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   269
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   270
    def load(host_infos: Host_Infos, log_database: SQL.Database): Timing_Data = {
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   271
      val build_history =
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   272
        for {
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   273
          log_name <- log_database.execute_query_statement(
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   274
            Build_Log.private_data.meta_info_table.select(List(Build_Log.Column.log_name)),
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   275
            List.from[String], res => res.string(Build_Log.Column.log_name))
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   276
          meta_info <- Build_Log.private_data.read_meta_info(log_database, log_name)
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   277
          build_info = Build_Log.private_data.read_build_info(log_database, log_name)
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   278
        } yield (meta_info, build_info)
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   279
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   280
      make(host_infos, build_history)
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   281
    }
78845
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
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   284
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   285
  /* host information */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   286
79103
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   287
  case class Host(info: isabelle.Host.Info, build: Build_Cluster.Host) {
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   288
    def name: String = info.hostname
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   289
    def num_cpus: Int = info.num_cpus
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   290
  }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   291
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   292
  object Host_Infos {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   293
    def dummy: Host_Infos =
78846
966aa081929f tuned imports;
wenzelm
parents: 78845
diff changeset
   294
      new Host_Infos(
966aa081929f tuned imports;
wenzelm
parents: 78845
diff changeset
   295
        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
   296
79090
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   297
    def load(build_hosts: List[Build_Cluster.Host], db: SQL.Database): Host_Infos = {
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   298
      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
   299
        val info =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   300
          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
   301
            error("No benchmark for " + quote(build_host.name)))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   302
        Host(info, build_host)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   303
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   304
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   305
      new Host_Infos(build_hosts.map(get_host))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   306
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   307
  }
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
  class Host_Infos private(val hosts: List[Host]) {
79040
Fabian Huch <huch@in.tum.de>
parents: 79039
diff changeset
   310
    require(hosts.nonEmpty)
Fabian Huch <huch@in.tum.de>
parents: 79039
diff changeset
   311
79103
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   312
    private val by_hostname = hosts.map(host => host.name -> host).toMap
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   313
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   314
    def host_factor(from: Host, to: Host): Double =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   315
      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
   316
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   317
    val host_speeds: Ordering[Host] =
79084
dd689c4ab688 consistent hosts ordering;
Fabian Huch <huch@in.tum.de>
parents: 79083
diff changeset
   318
      Ordering.fromLessThan((host1, host2) => host_factor(host1, host2) < 1)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   319
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   320
    def the_host(hostname: String): Host =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   321
      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
   322
    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
   323
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   324
    def num_threads(node_info: Node_Info): Int =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   325
      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
   326
      else the_host(node_info).info.num_cpus
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   327
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   328
    def available(state: Build_Process.State): Resources = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   329
      val allocated =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   330
        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
   331
      Resources(this, allocated)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   332
    }
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
79029
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   336
  /* offline tracking of job configurations and resource allocations */
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   337
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   338
  object Config {
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   339
    def from_job(job: Build_Process.Job): Config = Config(job.name, job.node_info)
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   340
  }
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   341
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   342
  case class Config(job_name: String, node_info: Node_Info) {
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   343
    def job_of(start_time: Time): Build_Process.Job =
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   344
      Build_Process.Job(job_name, "", "", node_info, Date(start_time), None)
Fabian Huch <huch@in.tum.de>
parents: 79028
diff changeset
   345
  }
78845
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
  case class Resources(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   348
    host_infos: Host_Infos,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   349
    allocated_nodes: Map[Host, List[Node_Info]]
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   350
  ) {
79106
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   351
    def unused_nodes(host: Host, threads: Int): List[Node_Info] =
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   352
      if (!available(host, threads)) Nil
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   353
      else {
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   354
        val node = next_node(host, threads)
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   355
        node :: allocate(node).unused_nodes(host, threads)
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   356
      }
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   357
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   358
    def unused_nodes(threads: Int): List[Node_Info] =
91955d607aad proper unused nodes;
Fabian Huch <huch@in.tum.de>
parents: 79105
diff changeset
   359
      host_infos.hosts.flatMap(unused_nodes(_, threads))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   360
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   361
    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
   362
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   363
    def allocate(node: Node_Info): Resources = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   364
      val host = host_infos.the_host(node)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   365
      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
   366
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   367
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   368
    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
   369
      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
   370
      tasks: List[(Build_Process.Task, Int, Int)],
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   371
    ): (List[Config], Resources) =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   372
      tasks match {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   373
        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
   374
        case (task, min_threads, max_threads) :: tasks =>
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   375
          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
   376
            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
   377
              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
   378
                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
   379
                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
   380
                (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
   381
              case None => (None, this)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   382
            }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   383
          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
   384
          (configs ++ config, resources1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   385
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   386
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   387
    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
   388
      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
   389
      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
   390
        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
   391
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   392
      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
   393
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   394
      val available_nodes = host.info.numa_nodes
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   395
      val numa_node =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   396
        if (!host.build.numa) None
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   397
        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
   398
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   399
      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
   400
      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
   401
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   402
      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
   403
79103
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   404
      Node_Info(host.name, numa_node, rel_cpus)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   405
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   406
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   407
    def available(host: Host, threads: Int): Boolean = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   408
      val used = allocated(host)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   409
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   410
      if (used.length >= host.build.jobs) false
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   411
      else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   412
        if (host.info.numa_nodes.length <= 1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   413
          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
   414
        else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   415
          def node_threads(n: Int): Int =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   416
            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
   417
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   418
          host.info.numa_nodes.exists(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   419
            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
   420
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   421
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   422
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   423
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   424
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
  /* schedule generation */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   427
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   428
  object Schedule {
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   429
    case class Node(job_name: String, node_info: Node_Info, start: Date, duration: Time) {
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   430
      def end: Date = Date(start.time + duration)
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   431
    }
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   432
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   433
    type Graph = isabelle.Graph[String, Node]
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   434
  }
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   435
79109
c1255d9870f6 clarified heuristics toString;
Fabian Huch <huch@in.tum.de>
parents: 79108
diff changeset
   436
  case class Schedule(generator: String, start: Date, graph: Schedule.Graph) {
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   437
    def end: Date =
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   438
      if (graph.is_empty) start
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   439
      else graph.maximals.map(graph.get_node).map(_.end).maxBy(_.unix_epoch)
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   440
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   441
    def duration: Time = end.time - start.time
79109
c1255d9870f6 clarified heuristics toString;
Fabian Huch <huch@in.tum.de>
parents: 79108
diff changeset
   442
    def message: String = "Estimated " + duration.message_hms + " build time with " + generator
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   443
  }
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   444
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   445
  case class State(build_state: Build_Process.State, current_time: Time, finished: Schedule) {
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   446
    def start(config: Config): State =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   447
      copy(build_state =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   448
        build_state.copy(running = build_state.running +
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   449
          (config.job_name -> config.job_of(current_time))))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   450
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   451
    def step(timing_data: Timing_Data): State = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   452
      val remaining =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   453
        build_state.running.values.toList.map { job =>
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   454
          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
   455
          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
   456
          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
   457
          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
   458
          job -> remaining
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   459
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   460
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   461
      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
   462
      else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   463
        val (job, elapsed) = remaining.minBy(_._2.ms)
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   464
        val now = current_time + elapsed
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   465
        val node = Schedule.Node(job.name, job.node_info, job.start_date, now - job.start_date.time)
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   466
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   467
        val preds =
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   468
          build_state.sessions.graph.imm_preds(job.name).filter(finished.graph.defined)
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   469
        val graph =
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   470
          preds.foldLeft(finished.graph.new_node(job.name, node))(_.add_edge(_, job.name))
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   471
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   472
        val build_state1 = build_state.remove_running(job.name).remove_pending(job.name)
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   473
        State(build_state1, now, finished.copy(graph = graph))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   474
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   475
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   476
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   477
    def is_finished: Boolean = build_state.pending.isEmpty && build_state.running.isEmpty
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   478
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   479
78932
Fabian Huch <huch@in.tum.de>
parents: 78931
diff changeset
   480
  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
   481
    def next(state: Build_Process.State): List[Config]
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   482
    def build_schedule(build_state: Build_Process.State): Schedule
78931
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   483
  }
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   484
79102
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   485
  abstract class Heuristic(timing_data: Timing_Data) extends Scheduler {
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   486
    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
   487
    val ordered_hosts = host_infos.hosts.sorted(host_infos.host_speeds)
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   488
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   489
    def build_schedule(build_state: Build_Process.State): Schedule = {
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   490
      @tailrec
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   491
      def simulate(state: State): State =
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   492
        if (state.is_finished) state
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   493
        else {
78932
Fabian Huch <huch@in.tum.de>
parents: 78931
diff changeset
   494
          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
   495
          simulate(state1)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   496
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   497
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   498
      val start = Date.now()
79109
c1255d9870f6 clarified heuristics toString;
Fabian Huch <huch@in.tum.de>
parents: 79108
diff changeset
   499
      val end_state =
c1255d9870f6 clarified heuristics toString;
Fabian Huch <huch@in.tum.de>
parents: 79108
diff changeset
   500
        simulate(State(build_state, start.time, Schedule(toString, start, Graph.empty)))
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   501
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   502
      end_state.finished
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   503
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   504
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   505
79107
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   506
  class Default_Heuristic(timing_data: Timing_Data, options: Options)
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   507
    extends Heuristic(timing_data) {
79109
c1255d9870f6 clarified heuristics toString;
Fabian Huch <huch@in.tum.de>
parents: 79108
diff changeset
   508
    override def toString: String = "default build heuristic"
79107
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   509
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   510
    def host_threads(host: Host): Int = {
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   511
      val m = (options ++ host.build.options).int("threads")
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   512
      if (m > 0) m else (host.num_cpus max 1) min 8
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   513
    }
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   514
    
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   515
    def next_jobs(resources: Resources, sorted_jobs: List[String], host: Host): List[Config] =
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   516
      sorted_jobs.zip(resources.unused_nodes(host, host_threads(host))).map(Config(_, _))
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   517
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   518
    def next(state: Build_Process.State): List[Config] = {
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   519
      val sorted_jobs = state.next_ready.sortBy(_.name)(state.sessions.ordering).map(_.name)
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   520
      val resources = host_infos.available(state)
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   521
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   522
      host_infos.hosts.foldLeft((sorted_jobs, List.empty[Config])) {
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   523
        case ((jobs, res), host) =>
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   524
          val configs = next_jobs(resources, jobs, host)
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   525
          val config_jobs = configs.map(_.job_name).toSet
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   526
          (jobs.filterNot(config_jobs.contains), configs ::: res)
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   527
      }._2
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   528
    }
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   529
  }
f5a2f956b531 add heuristic for non-scheduled (standard) build behaviour;
Fabian Huch <huch@in.tum.de>
parents: 79106
diff changeset
   530
78931
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   531
  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
   532
    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
   533
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   534
    def best_result(state: Build_Process.State): (Heuristic, Schedule) =
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   535
      heuristics.map(heuristic =>
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   536
        heuristic -> heuristic.build_schedule(state)).minBy(_._2.duration.ms)
78931
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   537
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   538
    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
   539
79073
b3fee0dafd72 generated build schedule explicitly (e.g., for further analysis);
Fabian Huch <huch@in.tum.de>
parents: 79064
diff changeset
   540
    def build_schedule(state: Build_Process.State): Schedule = best_result(state)._2
78931
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   541
  }
26841d3c568c performance tuning for build schedule: explicit schedule generation, without mixing heuristics;
Fabian Huch <huch@in.tum.de>
parents: 78930
diff changeset
   542
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   543
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   544
  /* heuristics */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   545
79027
d08fb157e300 use proper max threads (limited by available hardware) in heuristics;
Fabian Huch <huch@in.tum.de>
parents: 79026
diff changeset
   546
  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
   547
    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
   548
    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
   549
    max_threads_limit: Int
79102
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   550
  ) extends Heuristic(timing_data) {
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   551
    /* 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
   552
79102
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   553
    val max_threads = host_infos.hosts.map(_.info.num_cpus).max min max_threads_limit
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   554
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   555
    type Node = String
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   556
    val build_graph = sessions_structure.build_graph
79101
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   557
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   558
    val minimals = build_graph.minimals
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   559
    val maximals = build_graph.maximals
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   560
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   561
    def all_preds(node: Node): Set[Node] = build_graph.all_preds(List(node)).toSet
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   562
    val maximals_all_preds = maximals.map(node => node -> all_preds(node)).toMap
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   563
79102
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   564
    def best_time(node: Node): Time = {
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   565
      val host = ordered_hosts.last
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   566
      val threads = timing_data.best_threads(node, max_threads) min host.info.num_cpus
79103
883f61f0beda clarified build schedule host: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79102
diff changeset
   567
      timing_data.estimate(node, host.name, threads)
79102
4d5f878665a3 clarified path heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79101
diff changeset
   568
    }
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   569
    val best_times = build_graph.keys.map(node => node -> best_time(node)).toMap
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   570
79101
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   571
    val succs_max_time_ms = build_graph.node_height(best_times(_).ms)
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   572
    def max_time(node: Node): Time = Time.ms(succs_max_time_ms(node)) + best_times(node)
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   573
    def max_time(task: Build_Process.Task): Time = max_time(task.name)
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   574
79101
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   575
    def path_times(minimals: List[Node]): Map[Node, Time] = {
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   576
      def time_ms(node: Node): Long = best_times(node).ms
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   577
      val path_times_ms = build_graph.reachable_length(time_ms, build_graph.imm_succs, minimals)
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   578
      path_times_ms.view.mapValues(Time.ms).toMap
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   579
    }
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   580
79101
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   581
    def path_max_times(minimals: List[Node]): Map[Node, Time] =
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   582
      path_times(minimals).toList.map((node, time) => node -> (time + max_time(node))).toMap
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   583
79179
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   584
    def parallel_paths(running: List[(Node, Time)], pred: Node => Boolean = _ => true): Int = {
78972
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   585
      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
   586
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   587
      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
   588
        node -> (time - elapsed)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   589
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   590
      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
   591
        if (running.isEmpty) (0, running)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   592
        else {
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   593
          def get_next(node: Node): List[Node] =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   594
            build_graph.imm_succs(node).filter(pred).filter(
79104
e7ab5f4ed401 proper parallel paths;
Fabian Huch <huch@in.tum.de>
parents: 79103
diff changeset
   595
              build_graph.imm_preds(_).intersect(running.keySet) == Set(node)).toList
78972
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   596
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   597
          val (next, elapsed) = running.minBy(_._2.ms)
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   598
          val (remaining, finished) =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   599
            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
   600
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   601
          val running1 =
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   602
            remaining.map(pass_time(elapsed)).toMap ++
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   603
              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
   604
          val (res, running2) = parallel_paths(running1)
79104
e7ab5f4ed401 proper parallel paths;
Fabian Huch <huch@in.tum.de>
parents: 79103
diff changeset
   605
          (res max running.size, running2)
78972
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   606
        }
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   607
79179
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   608
      parallel_paths(running.toMap)._1
78972
7a39f151e9a7 proper parallel paths for timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 78971
diff changeset
   609
    }
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   610
  }
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   611
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   612
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   613
  object Path_Time_Heuristic {
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   614
    sealed trait Critical_Criterion
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   615
    case class Absolute_Time(time: Time) extends Critical_Criterion {
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   616
      override def toString: String = "absolute time (" + time.message_hms + ")"
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   617
    }
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   618
    case class Relative_Time(factor: Double) extends Critical_Criterion {
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   619
      override def toString: String = "relative time (" + factor + ")"
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   620
    }
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   621
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   622
    sealed trait Parallel_Strategy
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   623
    case class Fixed_Thread(threads: Int) extends Parallel_Strategy {
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   624
      override def toString: String = "fixed threads (" + threads + ")"
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   625
    }
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   626
    case class Time_Based_Threads(f: Time => Int) extends Parallel_Strategy {
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   627
      override def toString: String = "time based threads"
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   628
    }
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   629
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   630
    sealed trait Host_Criterion
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   631
    case object Critical_Nodes extends Host_Criterion {
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   632
      override def toString: String = "per critical node"
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   633
    }
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   634
    case class Fixed_Fraction(fraction: Double) extends Host_Criterion {
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   635
      override def toString: String = "fixed fraction (" + fraction + ")"
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   636
    }
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   637
    case class Host_Speed(min_factor: Double) extends Host_Criterion {
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   638
      override def toString: String = "host speed (" + min_factor + ")"
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   639
    }
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   640
  }
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   641
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   642
  class Path_Time_Heuristic(
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   643
    is_critical: Path_Time_Heuristic.Critical_Criterion,
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   644
    parallel_threads: Path_Time_Heuristic.Parallel_Strategy,
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   645
    host_criterion: Path_Time_Heuristic.Host_Criterion,
79019
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   646
    timing_data: Timing_Data,
4df053d29215 introduced path heuristic abstraction;
Fabian Huch <huch@in.tum.de>
parents: 78976
diff changeset
   647
    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
   648
    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
   649
  ) extends Path_Heuristic(timing_data, sessions_structure, max_threads_limit) {
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   650
    import Path_Time_Heuristic.*
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   651
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   652
    override def toString: Node = {
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   653
      val params =
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   654
        List(
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   655
          "critical: " + is_critical,
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   656
          "parallel: " + parallel_threads,
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   657
          "fast hosts: " + host_criterion)
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   658
      "path time heuristic (" + params.mkString(", ") + ")"
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   659
    }
78929
df323f23dfde performance tuning for timing heuristic: pre-calculate graph operations;
Fabian Huch <huch@in.tum.de>
parents: 78928
diff changeset
   660
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
   661
    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
   662
      val resources = host_infos.available(state)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   663
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   664
      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
   665
        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
   666
79028
6bada416ba55 clarified timing data operations: proper estimation (instead of known points);
Fabian Huch <huch@in.tum.de>
parents: 79027
diff changeset
   667
      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
   668
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   669
      val available_nodes =
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   670
        host_infos.available(state.copy(running = Map.empty))
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   671
          .unused_nodes(max_threads)
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   672
          .sortBy(node => host_infos.the_host(node))(host_infos.host_speeds).reverse
79179
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   673
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   674
      def remaining_time(node: Node): (Node, Time) =
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   675
        state.running.get(node) match {
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   676
          case None => node -> best_time(node)
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   677
          case Some(job) =>
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   678
            val estimate =
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   679
              timing_data.estimate(job.name, job.node_info.hostname,
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   680
                host_infos.num_threads(job.node_info))
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   681
            node -> Time.ms((Time.now() - job.start_date.time + estimate).ms max 0)
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   682
        }
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   683
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   684
      val max_parallel = parallel_paths(state.ready.map(_.name).map(remaining_time))
79101
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   685
      val next_sorted = state.next_ready.sortBy(max_time(_).ms).reverse
79088
32e839bb622e tuned heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79087
diff changeset
   686
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   687
      if (max_parallel <= available_nodes.length) {
79101
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   688
        val all_tasks = next_sorted.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
   689
        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
   690
      }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   691
      else {
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   692
        def is_critical(time: Time): Boolean =
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   693
          this.is_critical match {
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   694
            case Absolute_Time(threshold) => time > threshold
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   695
            case Relative_Time(factor) => time > minimals.map(max_time).maxBy(_.ms).scale(factor)
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   696
          }
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   697
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   698
        val critical_minimals = state.ready.filter(task => is_critical(max_time(task))).map(_.name)
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   699
        val critical_nodes =
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   700
          path_max_times(critical_minimals).filter((_, time) => is_critical(time)).keySet
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   701
79101
4e47b34fbb8e clarified graph operations in timing heuristic;
Fabian Huch <huch@in.tum.de>
parents: 79091
diff changeset
   702
        val (critical, other) = next_sorted.partition(task => critical_nodes.contains(task.name))
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   703
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   704
        val critical_tasks = critical.map(task => (task, best_threads(task), best_threads(task)))
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   705
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   706
        def parallel_threads(task: Build_Process.Task): Int =
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   707
          this.parallel_threads match {
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   708
            case Fixed_Thread(threads) => threads
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   709
            case Time_Based_Threads(f) => f(best_time(task.name))
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   710
          }
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   711
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   712
        val other_tasks = other.map(task => (task, parallel_threads(task), best_threads(task)))
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   713
79179
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   714
        val max_critical_parallel =
7ed43417770f proper parallel paths: factor in elapsed time;
Fabian Huch <huch@in.tum.de>
parents: 79178
diff changeset
   715
          parallel_paths(critical_minimals.map(remaining_time), critical_nodes.contains)
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   716
        val max_critical_hosts =
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   717
          available_nodes.take(max_critical_parallel).map(_.hostname).distinct.length
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   718
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   719
        val split =
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   720
          this.host_criterion match {
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   721
            case Critical_Nodes => max_critical_hosts
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   722
            case Fixed_Fraction(fraction) =>
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   723
              ((rev_ordered_hosts.length * fraction).ceil.toInt max 1) min max_critical_hosts
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   724
            case Host_Speed(min_factor) =>
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   725
              val best = rev_ordered_hosts.head._1.info.benchmark_score.get
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   726
              val num_fast =
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   727
                rev_ordered_hosts.count(_._1.info.benchmark_score.exists(_ >= best * min_factor))
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   728
              num_fast min max_critical_hosts
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   729
          }
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   730
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   731
        val (critical_hosts, other_hosts) = rev_ordered_hosts.splitAt(split)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   732
78971
f930d24f1548 scheduled build: allocate cpus more aggressively, to avoid idle threads;
Fabian Huch <huch@in.tum.de>
parents: 78970
diff changeset
   733
        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
   734
        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
   735
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   736
        configs1 ::: configs2
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   737
      }
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
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   742
  /* process for scheduled build */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   743
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
   744
  abstract class Scheduled_Build_Process(
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   745
    build_context: Build.Context,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   746
    build_progress: Progress,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   747
    server: SSH.Server,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   748
  ) extends Build_Process(build_context, build_progress, server) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   749
    protected val start_date = Date.now()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   750
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
   751
    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
   752
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   753
    /* global resources with common close() operation */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   754
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   755
    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
   756
    private final lazy val _log_database: SQL.Database =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   757
      try {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   758
        val db = _log_store.open_database(server = this.server)
78851
db37cae970a6 more robust init_database();
wenzelm
parents: 78849
diff changeset
   759
        _log_store.init_database(db)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   760
        db
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   761
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   762
      catch { case exn: Throwable => close(); throw exn }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   763
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   764
    override def close(): Unit = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   765
      super.close()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   766
      Option(_log_database).foreach(_.close())
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   767
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   768
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   769
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   770
    /* previous results via build log */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   771
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   772
    override def open_build_cluster(): Build_Cluster = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   773
      val build_cluster = super.open_build_cluster()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   774
      build_cluster.init()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   775
      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
   776
        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
   777
        Benchmark.benchmark(benchmark_options, progress)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   778
      }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   779
      build_cluster.benchmark()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   780
      build_cluster
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   781
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   782
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   783
    private val timing_data: Timing_Data = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   784
      val cluster_hosts: List[Build_Cluster.Host] =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   785
        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
   786
        else {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   787
          val local_build_host =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   788
            Build_Cluster.Host(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   789
              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
   790
          local_build_host :: build_context.build_hosts
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   791
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   792
79090
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   793
      val host_infos = Host_Infos.load(cluster_hosts, _host_database)
20be5b925720 clarified load vs. apply vs. make;
Fabian Huch <huch@in.tum.de>
parents: 79089
diff changeset
   794
      Timing_Data.load(host_infos, _log_database)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   795
    }
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
   796
    private val scheduler = init_scheduler(timing_data)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   797
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   798
    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
   799
      val sessions =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   800
        for {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   801
          (session_name, result) <- state.toList
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   802
          if !result.current
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   803
        } yield {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   804
          val info = build_context.sessions_structure(session_name)
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   805
          val entry =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   806
            if (!results.cancelled(session_name)) {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   807
              val status =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   808
                if (result.ok) Build_Log.Session_Status.finished
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   809
                else Build_Log.Session_Status.failed
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   810
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   811
              Build_Log.Session_Entry(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   812
                chapter = info.chapter,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   813
                groups = info.groups,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   814
                hostname = Some(result.node_info.hostname),
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   815
                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
   816
                timing = result.process_result.timing,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   817
                sources = Some(result.output_shasum.digest.toString),
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   818
                status = Some(status))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   819
            }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   820
            else
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   821
              Build_Log.Session_Entry(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   822
                chapter = info.chapter,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   823
                groups = info.groups,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   824
                status = Some(Build_Log.Session_Status.cancelled))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   825
          session_name -> entry
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   826
        }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   827
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   828
      val settings =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   829
        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
   830
          name -> Isabelle_System.getenv(name))
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   831
      val props =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   832
        List(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   833
          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
   834
          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
   835
          Build_Log.Prop.build_host.name -> hostname,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   836
          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
   837
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   838
      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
   839
      val build_info = Build_Log.Build_Info(sessions.toMap)
79089
Fabian Huch <huch@in.tum.de>
parents: 79088
diff changeset
   840
      val log_name = Build_Log.log_filename(engine = build_context.engine.name, date = start_date)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   841
79062
6977fb0153fb clarified modules: Build_Log.private_data provides raw data access without transaction_lock;
wenzelm
parents: 79042
diff changeset
   842
      Build_Log.private_data.update_sessions(
6977fb0153fb clarified modules: Build_Log.private_data provides raw data access without transaction_lock;
wenzelm
parents: 79042
diff changeset
   843
        _log_database, _log_store.cache.compress, log_name.file_name, build_info)
6977fb0153fb clarified modules: Build_Log.private_data provides raw data access without transaction_lock;
wenzelm
parents: 79042
diff changeset
   844
      Build_Log.private_data.update_meta_info(_log_database, log_name.file_name, meta_info)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   845
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   846
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   847
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   848
    /* build process */
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   849
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   850
    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
   851
      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
   852
        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
   853
      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
   854
        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
   855
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   856
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   857
    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
   858
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   859
    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
   860
      val configs =
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   861
        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
   862
        else scheduler.next(state)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   863
      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
   864
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   865
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   866
    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
   867
      state.ancestor_results(session_name) match {
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   868
        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
   869
          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
   870
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   871
          val input_shasum =
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   872
            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
   873
            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
   874
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   875
          val store_heap =
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   876
            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
   877
              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
   878
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   879
          store.check_output(
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   880
            _database_server, session_name,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   881
            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
   882
            sources_shasum = sources_shasum,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   883
            input_shasum = input_shasum,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   884
            fresh_build = build_context.fresh_build,
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   885
            store_heap = store_heap)._1
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   886
        case _ => false
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   887
    }
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   888
78970
5d38b72a1a66 finalize scheduled build only on master node;
Fabian Huch <huch@in.tum.de>
parents: 78969
diff changeset
   889
    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
   890
      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
   891
79020
ef76705bf402 clarified ready vs. next ready;
Fabian Huch <huch@in.tum.de>
parents: 79019
diff changeset
   892
      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
   893
      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
   894
      else {
79020
ef76705bf402 clarified ready vs. next ready;
Fabian Huch <huch@in.tum.de>
parents: 79019
diff changeset
   895
        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
   896
        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
   897
        else {
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   898
          val start = Time.now()
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   899
          val next = scheduler.next(state)
79105
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
   900
          val schedule = scheduler.build_schedule(state)
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   901
          val elapsed = Time.now() - start
78884
0233d5a5a4ca improved build messages;
Fabian Huch <huch@in.tum.de>
parents: 78851
diff changeset
   902
78976
8da0eedd562c tuned message;
Fabian Huch <huch@in.tum.de>
parents: 78975
diff changeset
   903
          val timing_msg = if (elapsed.is_relevant) " (took " + elapsed.message + ")" else ""
79105
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
   904
          progress.echo_if(build_context.master && !cache.is_current_estimate(schedule.end),
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
   905
            schedule.message + timing_msg)
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   906
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   907
          val configs = next.filter(_.node_info.hostname == hostname)
79105
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
   908
          cache = Cache(state, configs, schedule.end)
78969
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   909
          configs.map(_.job_name)
1b05c2b10c9f finalize current sessions before generating schedule;
Fabian Huch <huch@in.tum.de>
parents: 78968
diff changeset
   910
        }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   911
      }
78970
5d38b72a1a66 finalize scheduled build only on master node;
Fabian Huch <huch@in.tum.de>
parents: 78969
diff changeset
   912
    }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   913
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   914
    override def run(): Build.Results = {
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   915
      val results = super.run()
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   916
      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
   917
      results
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   918
    }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   919
  }
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   920
79089
Fabian Huch <huch@in.tum.de>
parents: 79088
diff changeset
   921
  class Engine extends Build.Engine("build_schedule") {
Fabian Huch <huch@in.tum.de>
parents: 79088
diff changeset
   922
79108
Fabian Huch <huch@in.tum.de>
parents: 79107
diff changeset
   923
    def scheduler(timing_data: Timing_Data, context: Build.Context): Scheduler = {
Fabian Huch <huch@in.tum.de>
parents: 79107
diff changeset
   924
      val sessions_structure = context.sessions_structure
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   925
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   926
      val is_criticals =
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   927
        List(
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   928
          Path_Time_Heuristic.Absolute_Time(Time.minutes(5)),
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   929
          Path_Time_Heuristic.Absolute_Time(Time.minutes(10)),
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   930
          Path_Time_Heuristic.Absolute_Time(Time.minutes(20)),
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   931
          Path_Time_Heuristic.Relative_Time(0.5))
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   932
      val parallel_threads =
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   933
        List(
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   934
          Path_Time_Heuristic.Fixed_Thread(1),
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   935
          Path_Time_Heuristic.Time_Based_Threads({
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   936
            case time if time < Time.minutes(1) => 1
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   937
            case time if time < Time.minutes(5) => 4
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   938
            case _ => 8
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   939
          }))
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   940
      val machine_splits =
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   941
        List(
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   942
          Path_Time_Heuristic.Critical_Nodes,
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   943
          Path_Time_Heuristic.Fixed_Fraction(0.3),
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   944
          Path_Time_Heuristic.Host_Speed(0.9))
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   945
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   946
      val path_time_heuristics =
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   947
        for {
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   948
          is_critical <- is_criticals
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   949
          parallel <- parallel_threads
79180
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   950
          machine_split <- machine_splits
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   951
        } yield
229f49204603 clarified build heuristics parameters;
Fabian Huch <huch@in.tum.de>
parents: 79179
diff changeset
   952
          Path_Time_Heuristic(is_critical, parallel, machine_split, timing_data, sessions_structure)
79110
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   953
      val heuristics = Default_Heuristic(timing_data, context.build_options) :: path_time_heuristics
ff68cbfa3550 clarified path time heuristic: configurable parameters for larger search space;
Fabian Huch <huch@in.tum.de>
parents: 79109
diff changeset
   954
79089
Fabian Huch <huch@in.tum.de>
parents: 79088
diff changeset
   955
      new Meta_Heuristic(heuristics)
Fabian Huch <huch@in.tum.de>
parents: 79088
diff changeset
   956
    }
Fabian Huch <huch@in.tum.de>
parents: 79088
diff changeset
   957
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   958
    override def open_build_process(
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   959
      context: Build.Context,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   960
      progress: Progress,
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   961
      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
   962
    ): 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
   963
      new Scheduled_Build_Process(context, progress, server) {
79108
Fabian Huch <huch@in.tum.de>
parents: 79107
diff changeset
   964
        def init_scheduler(timing_data: Timing_Data): Scheduler = scheduler(timing_data, context)
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
   965
      }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   966
  }
79091
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   967
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   968
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   969
  /* build schedule */
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   970
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   971
  def build_schedule(
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   972
    options: Options,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   973
    build_hosts: List[Build_Cluster.Host] = Nil,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   974
    selection: Sessions.Selection = Sessions.Selection.empty,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   975
    progress: Progress = new Progress,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   976
    afp_root: Option[Path] = None,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   977
    dirs: List[Path] = Nil,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   978
    select_dirs: List[Path] = Nil,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   979
    infos: List[Sessions.Info] = Nil,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   980
    numa_shuffling: Boolean = false,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   981
    augment_options: String => List[Options.Spec] = _ => Nil,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   982
    session_setup: (String, Session) => Unit = (_, _) => (),
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   983
    cache: Term.Cache = Term.Cache.make()
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   984
  ): Schedule = {
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   985
    val build_engine = new Engine
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   986
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   987
    val store = build_engine.build_store(options, build_hosts = build_hosts, cache = cache)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   988
    val log_store = Build_Log.store(options, cache = cache)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   989
    val build_options = store.options
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   990
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   991
    def build_schedule(
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   992
      server: SSH.Server,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   993
      database_server: Option[SQL.Database],
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   994
      log_database: PostgreSQL.Database,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   995
      host_database: SQL.Database
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   996
    ): Schedule = {
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   997
      val full_sessions =
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   998
        Sessions.load_structure(build_options, dirs = AFP.make_dirs(afp_root) ::: dirs,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
   999
          select_dirs = select_dirs, infos = infos, augment_options = augment_options)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1000
      val full_sessions_selection = full_sessions.imports_selection(selection)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1001
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1002
      val build_deps =
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1003
        Sessions.deps(full_sessions.selection(selection), progress = progress,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1004
          inlined_files = true).check_errors
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1005
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1006
      val build_context =
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1007
        Build.Context(store, build_engine, build_deps, afp_root = afp_root,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1008
          build_hosts = build_hosts, hostname = Build.hostname(build_options),
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1009
          numa_shuffling = numa_shuffling, max_jobs = 0, session_setup = session_setup,
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1010
          master = true)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1011
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1012
      val cluster_hosts = build_context.build_hosts
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1013
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1014
      val hosts_current =
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1015
        cluster_hosts.forall(host => isabelle.Host.read_info(host_database, host.name).isDefined)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1016
      if (!hosts_current) {
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1017
        val build_cluster = Build_Cluster.make(build_context, progress = progress)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1018
        build_cluster.open()
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1019
        build_cluster.init()
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1020
        build_cluster.benchmark()
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1021
        build_cluster.close()
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1022
      }
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1023
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1024
      val host_infos = Host_Infos.load(cluster_hosts, host_database)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1025
      val timing_data = Timing_Data.load(host_infos, log_database)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1026
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1027
      val sessions = Build_Process.Sessions.empty.init(build_context, database_server, progress)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1028
      def task(session: Build_Job.Session_Context): Build_Process.Task =
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1029
        Build_Process.Task(session.name, session.deps, JSON.Object.empty, build_context.build_uuid)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1030
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1031
      val build_state =
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1032
        Build_Process.State(sessions = sessions, pending = sessions.iterator.map(task).toList)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1033
79108
Fabian Huch <huch@in.tum.de>
parents: 79107
diff changeset
  1034
      val scheduler = build_engine.scheduler(timing_data, build_context)
79105
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
  1035
      def schedule_msg(res: Exn.Result[Schedule]): String =
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
  1036
        res match { case Exn.Res(schedule) => schedule.message case _ => "" }
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
  1037
6e92475ff925 clarified schedule message;
Fabian Huch <huch@in.tum.de>
parents: 79104
diff changeset
  1038
      Timing.timeit(scheduler.build_schedule(build_state), schedule_msg, output = progress.echo(_))
79091
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1039
    }
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1040
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1041
    using(store.open_server()) { server =>
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1042
      using_optional(store.maybe_open_database_server(server = server)) { database_server =>
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1043
        using(log_store.open_database(server = server)) { log_database =>
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1044
          using(store.open_build_database(
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1045
            path = isabelle.Host.private_data.database, server = server)) { host_database =>
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1046
              build_schedule(server, database_server, log_database, host_database)
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1047
          }
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1048
        }
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1049
      }
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1050
    }
06f380099b2e added method to generate build schedules directly;
Fabian Huch <huch@in.tum.de>
parents: 79090
diff changeset
  1051
  }
79181
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1052
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1053
  def write_schedule_graphic(schedule: Schedule, output: Path): Unit = {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1054
    import java.awt.geom.{GeneralPath, Rectangle2D}
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1055
    import java.awt.{BasicStroke, Color, Graphics2D}
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1056
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1057
    val line_height = isabelle.graphview.Metrics.default.height
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1058
    val char_width = isabelle.graphview.Metrics.default.char_width
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1059
    val padding = isabelle.graphview.Metrics.default.space_width
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1060
    val gap = isabelle.graphview.Metrics.default.gap
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1061
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1062
    val graph = schedule.graph
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1063
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1064
    def text_width(text: String): Double = text.length * char_width
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1065
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1066
    val generator_height = line_height + padding
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1067
    val hostname_height = generator_height + line_height + padding
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1068
    def time_height(time: Time): Double = time.seconds
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1069
    def date_height(date: Date): Double = time_height(date.time - schedule.start.time)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1070
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1071
    val hosts = graph.iterator.map(_._2._1).toList.groupBy(_.node_info.hostname)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1072
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1073
    def node_width(node: Schedule.Node): Double = 2 * padding + text_width(node.job_name)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1074
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1075
    case class Range(start: Double, stop: Double) {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1076
      def proper: List[Range] = if (start < stop) List(this) else Nil
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1077
      def width: Double = stop - start
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1078
    }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1079
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1080
    val rel_node_ranges =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1081
      hosts.toList.flatMap { (hostname, nodes) =>
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1082
        val sorted = nodes.sortBy(node => (node.start.time.ms, node.end.time.ms, node.job_name))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1083
        sorted.foldLeft((List.empty[Schedule.Node], Map.empty[Schedule.Node, Range])) {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1084
          case ((nodes, allocated), node) =>
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1085
            val width = node_width(node) + padding
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1086
            val parallel = nodes.filter(_.end.time > node.start.time)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1087
            val (last, slots) =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1088
              parallel.sortBy(allocated(_).start).foldLeft((0D, List.empty[Range])) {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1089
                case ((start, ranges), node1) =>
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1090
                  val node_range = allocated(node1)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1091
                  (node_range.stop, ranges ::: Range(start, node_range.start).proper)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1092
              }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1093
            val start =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1094
              (Range(last, Double.MaxValue) :: slots.filter(_.width >= width)).minBy(_.width).start
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1095
            (node :: parallel, allocated + (node -> Range(start, start + width)))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1096
        }._2
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1097
      }.toMap
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1098
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1099
    def host_width(hostname: String) =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1100
      2 * padding + (hosts(hostname).map(rel_node_ranges(_).stop).max max text_width(hostname))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1101
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1102
    def graph_height(graph: Graph[String, Schedule.Node]): Double =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1103
      date_height(graph.maximals.map(graph.get_node(_).end).maxBy(_.unix_epoch))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1104
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1105
    val height = (hostname_height + 2 * padding + graph_height(graph)).ceil.toInt
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1106
    val (last, host_starts) =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1107
      hosts.keys.foldLeft((0D, Map.empty[String, Double])) {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1108
        case ((previous, starts), hostname) =>
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1109
          (previous + gap + host_width(hostname), starts + (hostname -> previous))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1110
      }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1111
    val width = (last - gap).ceil.toInt
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1112
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1113
    def node_start(node: Schedule.Node): Double =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1114
      host_starts(node.node_info.hostname) + padding + rel_node_ranges(node).start
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1115
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1116
    def paint(gfx: Graphics2D): Unit = {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1117
      gfx.setColor(Color.LIGHT_GRAY)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1118
      gfx.fillRect(0, 0, width, height)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1119
      gfx.setRenderingHints(isabelle.graphview.Metrics.rendering_hints)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1120
      gfx.setFont(isabelle.graphview.Metrics.default.font)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1121
      gfx.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1122
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1123
      draw_string(schedule.generator + ", build time: " + schedule.duration.message_hms, padding, 0)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1124
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1125
      def draw_host(x: Double, hostname: String): Double = {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1126
        val nodes = hosts(hostname).map(_.job_name).toSet
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1127
        val width = host_width(hostname)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1128
        val height = 2 * padding + graph_height(graph.restrict(nodes.contains))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1129
        val padding1 = ((width - text_width(hostname)) / 2) max 0
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1130
        val rect = new Rectangle2D.Double(x, hostname_height, width, height)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1131
        gfx.setColor(Color.BLACK)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1132
        gfx.draw(rect)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1133
        gfx.setColor(Color.GRAY)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1134
        gfx.fill(rect)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1135
        draw_string(hostname, x + padding1, generator_height)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1136
        x + gap + width
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1137
      }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1138
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1139
      def draw_string(str: String, x: Double, y: Double): Unit = {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1140
        gfx.setColor(Color.BLACK)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1141
        gfx.drawString(str, x.toInt, (y + line_height).toInt)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1142
      }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1143
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1144
      def node_rect(node: Schedule.Node): Rectangle2D.Double = {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1145
        val x = node_start(node)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1146
        val y = hostname_height + padding + date_height(node.start)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1147
        val width = node_width(node)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1148
        val height = time_height(node.duration)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1149
        new Rectangle2D.Double(x, y, width, height)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1150
      }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1151
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1152
      def draw_node(node: Schedule.Node): Rectangle2D.Double = {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1153
        val rect = node_rect(node)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1154
        gfx.setColor(Color.BLACK)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1155
        gfx.draw(rect)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1156
        gfx.setColor(Color.WHITE)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1157
        gfx.fill(rect)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1158
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1159
        def add_text(y: Double, text: String): Double =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1160
          if (line_height > rect.height - y || text_width(text) + 2 * padding > rect.width) y
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1161
          else {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1162
            val padding1 = padding min ((rect.height - (y + line_height)) / 2)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1163
            draw_string(text, rect.x + padding, rect.y + y + padding1)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1164
            y + padding1 + line_height
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1165
          }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1166
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1167
        val node_info = node.node_info
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1168
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1169
        val duration_str = "(" + node.duration.message_hms + ")"
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1170
        val node_str =
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1171
          "on " + proper_string(node_info.toString.stripPrefix(node_info.hostname)).getOrElse("all")
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1172
        val start_str = "Start: " + (node.start.time - schedule.start.time).message_hms
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1173
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1174
        List(node.job_name, duration_str, node_str, start_str).foldLeft(0D)(add_text)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1175
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1176
        rect
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1177
      }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1178
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1179
      def draw_arrow(from: Schedule.Node, to: Rectangle2D.Double, curve: Double = 10): Unit = {
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1180
        val from_rect = node_rect(from)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1181
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1182
        val path = new GeneralPath()
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1183
        path.moveTo(from_rect.getCenterX, from_rect.getMaxY)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1184
        path.lineTo(to.getCenterX, to.getMinY)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1185
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1186
        gfx.setColor(Color.BLUE)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1187
        gfx.draw(path)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1188
      }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1189
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1190
      hosts.keys.foldLeft(0D)(draw_host)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1191
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1192
      graph.topological_order.foreach { job_name =>
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1193
        val node = graph.get_node(job_name)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1194
        val rect = draw_node(node)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1195
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1196
        graph.imm_preds(job_name).foreach(pred => draw_arrow(graph.get_node(pred), rect))
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1197
      }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1198
    }
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1199
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1200
    val name = output.file_name
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1201
    if (File.is_png(name)) Graphics_File.write_png(output.file, paint, width, height)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1202
    else if (File.is_pdf(name)) Graphics_File.write_pdf(output.file, paint, width, height)
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1203
    else error("Bad type of file: " + quote(name) + " (.png or .pdf expected)")
9d6d559c9fde added graphical representation of build schedules;
Fabian Huch <huch@in.tum.de>
parents: 79180
diff changeset
  1204
  }
78845
ff96d94957cb add module for faster scheduled builds;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
  1205
}