src/Pure/System/host.scala
author wenzelm
Sun, 10 Mar 2024 10:50:12 +0100
changeset 79844 ac40138234ce
parent 79821 1734334d3dd4
child 79929 08b83f91a1b2
permissions -rw-r--r--
tuned signature: more uniform SQL.Data instances;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
77475
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/System/host.scala
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
     3
77477
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
     4
Information about compute hosts, including NUMA: Non-Uniform Memory Access of
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
     5
separate CPU nodes.
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
     6
77478
e50cad69cbe7 tuned comments;
wenzelm
parents: 77477
diff changeset
     7
See also https://www.open-mpi.org/projects/hwloc --- notably "lstopo" or
e50cad69cbe7 tuned comments;
wenzelm
parents: 77477
diff changeset
     8
"hwloc-ls" (e.g. via Ubuntu package "hwloc").
77475
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
     9
*/
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    10
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    11
package isabelle
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    12
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    13
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    14
object Host {
78837
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    15
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    16
  object Range {
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    17
    val Single = """^(\d+)$""".r
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    18
    val Multiple = """^(\d+)-(\d+)$""".r
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    19
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    20
    def apply(range: List[Int]): String =
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    21
      range match {
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    22
        case Nil => ""
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    23
        case x :: xs =>
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    24
          def elem(start: Int, stop: Int): String =
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    25
            if (start == stop) start.toString else start.toString + "-" + stop.toString
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    26
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    27
          val (elems, (r0, rn)) =
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    28
            xs.foldLeft((List.empty[String], (x, x))) {
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    29
              case ((rs, (r0, rn)), x) =>
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    30
                if (rn + 1 == x) (rs, (r0, x)) else (rs :+ elem(r0, rn), (x, x))
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    31
            }
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    32
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    33
          (elems :+ elem(r0, rn)).mkString(",")
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    34
      }
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    35
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    36
    def unapply(s: String): Option[List[Int]] =
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    37
      space_explode(',', s).foldRight(Option(List.empty[Int])) {
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    38
        case (Single(Value.Int(i)), Some(elems)) => Some(i :: elems)
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    39
        case (Multiple(Value.Int(i), Value.Int(j)), Some(elems)) => Some((i to j).toList ::: elems)
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    40
        case _ => None
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    41
      }
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    42
78847
3958180eaa72 tuned signature;
wenzelm
parents: 78840
diff changeset
    43
    def from(s: String): List[Int] =
78837
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    44
      s match {
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    45
        case Range(r) => r
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    46
        case _ => Nil
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    47
      }
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    48
  }
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    49
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
    50
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    51
  /* process policy via numactl and taskset tools */
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    52
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    53
  def taskset(cpus: List[Int]): String = "taskset --cpu-list " + Range(cpus)
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    54
  def taskset_ok(cpus: List[Int]): Boolean = Isabelle_System.bash(taskset(cpus) + " true").ok
77549
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    55
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    56
  def numactl(node: Int, rel_cpus: List[Int] = Nil): String =
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    57
    "numactl -m" + node + " -N" + node + if_proper(rel_cpus, " -C+" + Range(rel_cpus))
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    58
  def numactl_ok(node: Int, rel_cpus: List[Int] = Nil): Boolean =
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    59
    Isabelle_System.bash(numactl(node, rel_cpus) + " true").ok
77549
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    60
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    61
  def numa_options(options: Options, numa_node: Option[Int]): Options =
77549
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    62
    numa_node match {
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    63
      case None => options
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    64
      case Some(node) =>
79618
50376abd132d tuned: prefer explicit update operation for immutable options;
wenzelm
parents: 79608
diff changeset
    65
        options.string.update("process_policy", if (numactl_ok(node)) numactl(node) else "")
77549
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    66
    }
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    67
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    68
  def node_options(options: Options, node: Node_Info): Options = {
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    69
    val threads_options =
79718
fba02e281b44 tuned whitespace;
wenzelm
parents: 79618
diff changeset
    70
      if (node.rel_cpus.isEmpty) options
fba02e281b44 tuned whitespace;
wenzelm
parents: 79618
diff changeset
    71
      else options.int.update("threads", node.rel_cpus.length)
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    72
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    73
    node.numa_node match {
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    74
      case None if node.rel_cpus.isEmpty =>
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    75
        threads_options
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    76
      case Some(numa_node) =>
79618
50376abd132d tuned: prefer explicit update operation for immutable options;
wenzelm
parents: 79608
diff changeset
    77
        threads_options.string.update("process_policy",
50376abd132d tuned: prefer explicit update operation for immutable options;
wenzelm
parents: 79608
diff changeset
    78
          if (numactl_ok(numa_node, node.rel_cpus)) numactl(numa_node, node.rel_cpus) else "")
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    79
      case _ =>
79618
50376abd132d tuned: prefer explicit update operation for immutable options;
wenzelm
parents: 79608
diff changeset
    80
        threads_options.string.update("process_policy",
50376abd132d tuned: prefer explicit update operation for immutable options;
wenzelm
parents: 79608
diff changeset
    81
          if (taskset_ok(node.rel_cpus)) taskset(node.rel_cpus) else "")
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    82
    }
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    83
  }
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    84
77549
6339c3a3720b tuned structure;
wenzelm
parents: 77548
diff changeset
    85
77475
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    86
  /* allocated resources */
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    87
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    88
  object Node_Info { def none: Node_Info = Node_Info("", None, Nil) }
77475
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
    89
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    90
  sealed case class Node_Info(hostname: String, numa_node: Option[Int], rel_cpus: List[Int]) {
79821
1734334d3dd4 tuned signature;
wenzelm
parents: 79718
diff changeset
    91
    def numa: Boolean = numa_node.isDefined || rel_cpus.nonEmpty
1734334d3dd4 tuned signature;
wenzelm
parents: 79718
diff changeset
    92
77526
e3ed231fa214 tuned output;
wenzelm
parents: 77525
diff changeset
    93
    override def toString: String =
78839
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    94
      hostname +
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    95
        if_proper(numa_node, "/" + numa_node.get.toString) +
7799ec03b8bd generalized node infos: allow addressing of numa node segments via relative cpus;
Fabian Huch <huch@in.tum.de>
parents: 78838
diff changeset
    96
        if_proper(rel_cpus, "+" + Range(rel_cpus))
77526
e3ed231fa214 tuned output;
wenzelm
parents: 77525
diff changeset
    97
  }
77476
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
    98
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
    99
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   100
  /* statically available resources */
77477
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   101
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   102
  private val numa_info_linux: Path = Path.explode("/sys/devices/system/node/online")
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   103
78837
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
   104
  def parse_numa_info(numa_info: String): List[Int] =
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
   105
    numa_info match {
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
   106
      case Range(nodes) => nodes
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
   107
      case s => error("Cannot parse CPU NUMA node specification: " + quote(s))
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
   108
    }
77477
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   109
78837
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
   110
  def numa_nodes(enabled: Boolean = true, ssh: SSH.System = SSH.Local): List[Int] = {
77477
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   111
    val numa_info = if (ssh.isabelle_platform.is_linux) Some(numa_info_linux) else None
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   112
    for {
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   113
      path <- numa_info.toList
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   114
      if enabled && ssh.is_file(path)
78837
f97e23eaa628 added Range object to Host, e.g. to parse/unparse NUMA node ranges;
Fabian Huch <huch@in.tum.de>
parents: 78435
diff changeset
   115
      n <- parse_numa_info(ssh.read(path).trim)
77477
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   116
    } yield n
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   117
  }
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   118
77548
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   119
  def numa_node0(): Option[Int] =
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   120
    try {
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   121
      numa_nodes() match {
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   122
        case ns if ns.length >= 2 && numactl_ok(ns.head) => Some(ns.head)
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   123
        case _ => None
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   124
      }
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   125
    }
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   126
    catch { case ERROR(_) => None }
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   127
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   128
  object Info {
79602
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   129
    def init(
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   130
      hostname: String = SSH.LOCAL,
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   131
      ssh: SSH.System = SSH.Local,
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   132
      score: Option[Double] = None
79608
f1df99019b50 prefer physical processors (see also 4b014e6c1dfe and 26a43785590b);
wenzelm
parents: 79602
diff changeset
   133
    ): Info = Info(hostname, numa_nodes(ssh = ssh), Multithreading.num_processors(ssh = ssh), score)
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   134
  }
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   135
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   136
  sealed case class Info(
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   137
    hostname: String,
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   138
    numa_nodes: List[Int],
78840
4b528ca25573 added initial version of benchmark module, e.g., to compare performance of different hosts;
Fabian Huch <huch@in.tum.de>
parents: 78839
diff changeset
   139
    num_cpus: Int,
79602
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   140
    benchmark_score: Option[Double]
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   141
  ) {
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   142
    override def toString: String = hostname
9ba800f12785 clarified signature;
wenzelm
parents: 78848
diff changeset
   143
  }
77548
28b94fe1c00f clarified signature;
wenzelm
parents: 77547
diff changeset
   144
77477
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   145
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   146
  /* shuffling of NUMA nodes */
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   147
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   148
  def numa_check(progress: Progress, enabled: Boolean): Boolean = {
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   149
    def warning =
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   150
      numa_nodes() match {
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   151
        case ns if ns.length < 2 => Some("no NUMA nodes available")
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   152
        case ns if !numactl_ok(ns.head) => Some("bad numactl tool")
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   153
        case _ => None
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   154
      }
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   155
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   156
    enabled &&
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   157
      (warning match {
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   158
        case Some(s) =>
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   159
          progress.echo_warning("Shuffling of NUMA CPU nodes is disabled: " + s)
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   160
          false
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   161
        case _ => true
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   162
      })
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   163
  }
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   164
f376aebca9c1 clarified modules;
wenzelm
parents: 77476
diff changeset
   165
77476
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   166
  /* SQL data model */
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   167
78396
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78356
diff changeset
   168
  object private_data extends SQL.Data("isabelle_host") {
78174
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   169
    val database: Path = Path.explode("$ISABELLE_HOME_USER/host.db")
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   170
79844
ac40138234ce tuned signature: more uniform SQL.Data instances;
wenzelm
parents: 79821
diff changeset
   171
    override lazy val tables: SQL.Tables = SQL.Tables(Node_Info.table, Info.table)
77476
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   172
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   173
    object Node_Info {
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   174
      val hostname = SQL.Column.string("hostname").make_primary_key
77525
de6fb423fd4b clarified database content: store actual value instead of index;
wenzelm
parents: 77483
diff changeset
   175
      val numa_next = SQL.Column.int("numa_next")
77476
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   176
78266
d8c99a497502 clarified signature;
wenzelm
parents: 78187
diff changeset
   177
      val table = make_table(List(hostname, numa_next), name = "node_info")
77476
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   178
    }
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   179
77525
de6fb423fd4b clarified database content: store actual value instead of index;
wenzelm
parents: 77483
diff changeset
   180
    def read_numa_next(db: SQL.Database, hostname: String): Int =
77552
080422b3d914 clarified signature: reduce boilerplate;
wenzelm
parents: 77550
diff changeset
   181
      db.execute_query_statementO[Int](
77525
de6fb423fd4b clarified database content: store actual value instead of index;
wenzelm
parents: 77483
diff changeset
   182
        Node_Info.table.select(List(Node_Info.numa_next),
77552
080422b3d914 clarified signature: reduce boilerplate;
wenzelm
parents: 77550
diff changeset
   183
          sql = Node_Info.hostname.where_equal(hostname)),
080422b3d914 clarified signature: reduce boilerplate;
wenzelm
parents: 77550
diff changeset
   184
        res => res.int(Node_Info.numa_next)
080422b3d914 clarified signature: reduce boilerplate;
wenzelm
parents: 77550
diff changeset
   185
      ).getOrElse(0)
77476
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   186
78174
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   187
    def write_numa_next(db: SQL.Database, hostname: String, numa_next: Int): Unit = {
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   188
      db.execute_statement(Node_Info.table.delete(sql = Node_Info.hostname.where_equal(hostname)))
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   189
      db.execute_statement(Node_Info.table.insert(), body =
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   190
        { stmt =>
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   191
          stmt.string(1) = hostname
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   192
          stmt.int(2) = numa_next
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   193
        })
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   194
    }
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   195
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   196
    object Info {
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   197
      val hostname = SQL.Column.string("hostname").make_primary_key
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   198
      val numa_info = SQL.Column.string("numa_info")
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   199
      val num_cpus = SQL.Column.int("num_cpus")
78840
4b528ca25573 added initial version of benchmark module, e.g., to compare performance of different hosts;
Fabian Huch <huch@in.tum.de>
parents: 78839
diff changeset
   200
      val benchmark_score = SQL.Column.double("benchmark_score")
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   201
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   202
      val table =
78840
4b528ca25573 added initial version of benchmark module, e.g., to compare performance of different hosts;
Fabian Huch <huch@in.tum.de>
parents: 78839
diff changeset
   203
        make_table(List(hostname, numa_info, num_cpus, benchmark_score), name = "info")
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   204
    }
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   205
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   206
    def write_info(db: SQL.Database, info: Info): Unit = {
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   207
      db.execute_statement(Info.table.delete(sql = Info.hostname.where_equal(info.hostname)))
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   208
      db.execute_statement(Info.table.insert(), body =
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   209
        { stmt =>
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   210
          stmt.string(1) = info.hostname
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   211
          stmt.string(2) = info.numa_nodes.mkString(",")
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   212
          stmt.int(3) = info.num_cpus
78840
4b528ca25573 added initial version of benchmark module, e.g., to compare performance of different hosts;
Fabian Huch <huch@in.tum.de>
parents: 78839
diff changeset
   213
          stmt.double(4) = info.benchmark_score
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   214
        })
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   215
    }
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   216
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   217
    def read_info(db: SQL.Database, hostname: String): Option[Host.Info] =
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   218
      db.execute_query_statementO[Host.Info](
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   219
        Info.table.select(Info.table.columns.tail, sql = Info.hostname.where_equal(hostname)),
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   220
        { res =>
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   221
          val numa_info = res.string(Info.numa_info)
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   222
          val num_cpus = res.int(Info.num_cpus)
78840
4b528ca25573 added initial version of benchmark module, e.g., to compare performance of different hosts;
Fabian Huch <huch@in.tum.de>
parents: 78839
diff changeset
   223
          val benchmark_score = res.get_double(Info.benchmark_score)
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   224
78840
4b528ca25573 added initial version of benchmark module, e.g., to compare performance of different hosts;
Fabian Huch <huch@in.tum.de>
parents: 78839
diff changeset
   225
          Host.Info(hostname, parse_numa_info(numa_info), num_cpus, benchmark_score)
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   226
        })
78174
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   227
  }
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   228
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   229
  def next_numa_node(
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   230
    db: SQL.Database,
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   231
    hostname: String,
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   232
    available_nodes: List[Int],
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   233
    used_nodes: => Set[Int]
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   234
  ): Option[Int] =
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   235
    if (available_nodes.isEmpty) None
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   236
    else {
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   237
      val available = available_nodes.zipWithIndex
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   238
      val used = used_nodes
78396
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78356
diff changeset
   239
      private_data.transaction_lock(db, create = true, label = "Host.next_numa_node") {
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78356
diff changeset
   240
        val numa_next = private_data.read_numa_next(db, hostname)
78174
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   241
        val numa_index = available.collectFirst({ case (n, i) if n == numa_next => i }).getOrElse(0)
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   242
        val candidates = available.drop(numa_index) ::: available.take(numa_index)
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   243
        val (n, i) =
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   244
          candidates.find({ case (n, i) => i == numa_index && !used(n) }) orElse
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   245
          candidates.find({ case (n, _) => !used(n) }) getOrElse candidates.head
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   246
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   247
        val numa_next1 = available_nodes((i + 1) % available_nodes.length)
78396
7853d9072d1b renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
wenzelm
parents: 78356
diff changeset
   248
        if (numa_next != numa_next1) private_data.write_numa_next(db, hostname, numa_next1)
78174
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   249
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   250
        Some(n)
77476
5f6f567a2661 clarified modules;
wenzelm
parents: 77475
diff changeset
   251
      }
78174
cc0bd66eb498 separate host.db for independent db.transaction_lock;
wenzelm
parents: 77552
diff changeset
   252
    }
78838
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   253
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   254
  def write_info(db: SQL.Database, info: Info): Unit =
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   255
    private_data.transaction_lock(db, create = true, label = "Host.write_info") {
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   256
      private_data.write_info(db, info)
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   257
    }
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   258
  def read_info(db: SQL.Database, hostname: String): Option[Host.Info] =
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   259
    private_data.transaction_lock(db, create = true, label = "Host.read_info") {
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   260
      private_data.read_info(db, hostname)
4b014e6c1dfe add information about static host resources such as available NUMA nodes, cpus, etc. (e.g., for offline build planning);
Fabian Huch <huch@in.tum.de>
parents: 78837
diff changeset
   261
    }
77475
3bc611c80346 clarified modules;
wenzelm
parents:
diff changeset
   262
}