| author | Thomas Lindae <thomas.lindae@in.tum.de> | 
| Wed, 17 Jul 2024 21:02:30 +0200 | |
| changeset 81077 | 664c1a6cc8c1 | 
| parent 79929 | 08b83f91a1b2 | 
| permissions | -rw-r--r-- | 
| 77475 | 1 | /* Title: Pure/System/host.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 77477 | 4 | Information about compute hosts, including NUMA: Non-Uniform Memory Access of | 
| 5 | separate CPU nodes. | |
| 6 | ||
| 77478 | 7 | See also https://www.open-mpi.org/projects/hwloc --- notably "lstopo" or | 
| 8 | "hwloc-ls" (e.g. via Ubuntu package "hwloc"). | |
| 77475 | 9 | */ | 
| 10 | ||
| 11 | package isabelle | |
| 12 | ||
| 13 | ||
| 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: 
78435diff
changeset | 15 | |
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
changeset | 19 | |
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
changeset | 26 | |
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
changeset | 31 | } | 
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 32 | |
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
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: 
78435diff
changeset | 34 | } | 
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 35 | |
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
changeset | 41 | } | 
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 42 | |
| 78847 | 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: 
78435diff
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: 
78435diff
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: 
78435diff
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: 
78435diff
changeset | 47 | } | 
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 48 | } | 
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 49 | |
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 50 | |
| 78839 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
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: 
78838diff
changeset | 52 | |
| 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
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: 
78838diff
changeset | 54 | def taskset_ok(cpus: List[Int]): Boolean = Isabelle_System.bash(taskset(cpus) + " true").ok | 
| 77549 | 55 | |
| 78839 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
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: 
78838diff
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: 
78838diff
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: 
78838diff
changeset | 59 | Isabelle_System.bash(numactl(node, rel_cpus) + " true").ok | 
| 77549 | 60 | |
| 78839 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 61 | def numa_options(options: Options, numa_node: Option[Int]): Options = | 
| 77549 | 62 |     numa_node match {
 | 
| 63 | case None => options | |
| 64 | case Some(node) => | |
| 79618 
50376abd132d
tuned: prefer explicit update operation for immutable options;
 wenzelm parents: 
79608diff
changeset | 65 |         options.string.update("process_policy", if (numactl_ok(node)) numactl(node) else "")
 | 
| 77549 | 66 | } | 
| 67 | ||
| 78839 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
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: 
78838diff
changeset | 69 | val threads_options = | 
| 79718 | 70 | if (node.rel_cpus.isEmpty) options | 
| 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: 
78838diff
changeset | 72 | |
| 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
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: 
78838diff
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: 
78838diff
changeset | 75 | threads_options | 
| 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 76 | case Some(numa_node) => | 
| 79618 
50376abd132d
tuned: prefer explicit update operation for immutable options;
 wenzelm parents: 
79608diff
changeset | 77 |         threads_options.string.update("process_policy",
 | 
| 
50376abd132d
tuned: prefer explicit update operation for immutable options;
 wenzelm parents: 
79608diff
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: 
78838diff
changeset | 79 | case _ => | 
| 79929 
08b83f91a1b2
disable taskset for now: performance impact is negative;
 Fabian Huch <huch@in.tum.de> parents: 
79844diff
changeset | 80 |         // FIXME threads_options.string.update("process_policy",
 | 
| 
08b83f91a1b2
disable taskset for now: performance impact is negative;
 Fabian Huch <huch@in.tum.de> parents: 
79844diff
changeset | 81 | // if (taskset_ok(node.rel_cpus)) taskset(node.rel_cpus) else "") | 
| 
08b83f91a1b2
disable taskset for now: performance impact is negative;
 Fabian Huch <huch@in.tum.de> parents: 
79844diff
changeset | 82 | threads_options | 
| 78839 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 83 | } | 
| 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 84 | } | 
| 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 85 | |
| 77549 | 86 | |
| 77475 | 87 | /* allocated resources */ | 
| 88 | ||
| 78839 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 89 |   object Node_Info { def none: Node_Info = Node_Info("", None, Nil) }
 | 
| 77475 | 90 | |
| 78839 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 91 |   sealed case class Node_Info(hostname: String, numa_node: Option[Int], rel_cpus: List[Int]) {
 | 
| 79821 | 92 | def numa: Boolean = numa_node.isDefined || rel_cpus.nonEmpty | 
| 93 | ||
| 77526 | 94 | 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: 
78838diff
changeset | 95 | hostname + | 
| 
7799ec03b8bd
generalized node infos: allow addressing of numa node segments via relative cpus;
 Fabian Huch <huch@in.tum.de> parents: 
78838diff
changeset | 96 | 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: 
78838diff
changeset | 97 | if_proper(rel_cpus, "+" + Range(rel_cpus)) | 
| 77526 | 98 | } | 
| 77476 | 99 | |
| 100 | ||
| 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: 
78837diff
changeset | 101 | /* statically available resources */ | 
| 77477 | 102 | |
| 103 |   private val numa_info_linux: Path = Path.explode("/sys/devices/system/node/online")
 | |
| 104 | ||
| 78837 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 105 | 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: 
78435diff
changeset | 106 |     numa_info match {
 | 
| 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 107 | 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: 
78435diff
changeset | 108 |       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: 
78435diff
changeset | 109 | } | 
| 77477 | 110 | |
| 78837 
f97e23eaa628
added Range object to Host, e.g. to parse/unparse NUMA node ranges;
 Fabian Huch <huch@in.tum.de> parents: 
78435diff
changeset | 111 |   def numa_nodes(enabled: Boolean = true, ssh: SSH.System = SSH.Local): List[Int] = {
 | 
| 77477 | 112 | val numa_info = if (ssh.isabelle_platform.is_linux) Some(numa_info_linux) else None | 
| 113 |     for {
 | |
| 114 | path <- numa_info.toList | |
| 115 | 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: 
78435diff
changeset | 116 | n <- parse_numa_info(ssh.read(path).trim) | 
| 77477 | 117 | } yield n | 
| 118 | } | |
| 119 | ||
| 77548 | 120 | def numa_node0(): Option[Int] = | 
| 121 |     try {
 | |
| 122 |       numa_nodes() match {
 | |
| 123 | case ns if ns.length >= 2 && numactl_ok(ns.head) => Some(ns.head) | |
| 124 | case _ => None | |
| 125 | } | |
| 126 | } | |
| 127 |     catch { case ERROR(_) => None }
 | |
| 128 | ||
| 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: 
78837diff
changeset | 129 |   object Info {
 | 
| 79602 | 130 | def init( | 
| 131 | hostname: String = SSH.LOCAL, | |
| 132 | ssh: SSH.System = SSH.Local, | |
| 133 | score: Option[Double] = None | |
| 79608 
f1df99019b50
prefer physical processors (see also 4b014e6c1dfe and 26a43785590b);
 wenzelm parents: 
79602diff
changeset | 134 | ): 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: 
78837diff
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: 
78837diff
changeset | 136 | |
| 
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: 
78837diff
changeset | 137 | 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: 
78837diff
changeset | 138 | 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: 
78837diff
changeset | 139 | 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: 
78839diff
changeset | 140 | num_cpus: Int, | 
| 79602 | 141 | benchmark_score: Option[Double] | 
| 142 |   ) {
 | |
| 143 | override def toString: String = hostname | |
| 144 | } | |
| 77548 | 145 | |
| 77477 | 146 | |
| 147 | /* shuffling of NUMA nodes */ | |
| 148 | ||
| 149 |   def numa_check(progress: Progress, enabled: Boolean): Boolean = {
 | |
| 150 | def warning = | |
| 151 |       numa_nodes() match {
 | |
| 152 |         case ns if ns.length < 2 => Some("no NUMA nodes available")
 | |
| 153 |         case ns if !numactl_ok(ns.head) => Some("bad numactl tool")
 | |
| 154 | case _ => None | |
| 155 | } | |
| 156 | ||
| 157 | enabled && | |
| 158 |       (warning match {
 | |
| 159 | case Some(s) => | |
| 160 |           progress.echo_warning("Shuffling of NUMA CPU nodes is disabled: " + s)
 | |
| 161 | false | |
| 162 | case _ => true | |
| 163 | }) | |
| 164 | } | |
| 165 | ||
| 166 | ||
| 77476 | 167 | /* SQL data model */ | 
| 168 | ||
| 78396 
7853d9072d1b
renamed object Data to private_data, to emphasize its intended scope (but it is publicly accessible in the database);
 wenzelm parents: 
78356diff
changeset | 169 |   object private_data extends SQL.Data("isabelle_host") {
 | 
| 78174 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 170 |     val database: Path = Path.explode("$ISABELLE_HOME_USER/host.db")
 | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 171 | |
| 79844 
ac40138234ce
tuned signature: more uniform SQL.Data instances;
 wenzelm parents: 
79821diff
changeset | 172 | override lazy val tables: SQL.Tables = SQL.Tables(Node_Info.table, Info.table) | 
| 77476 | 173 | |
| 174 |     object Node_Info {
 | |
| 175 |       val hostname = SQL.Column.string("hostname").make_primary_key
 | |
| 77525 
de6fb423fd4b
clarified database content: store actual value instead of index;
 wenzelm parents: 
77483diff
changeset | 176 |       val numa_next = SQL.Column.int("numa_next")
 | 
| 77476 | 177 | |
| 78266 | 178 | val table = make_table(List(hostname, numa_next), name = "node_info") | 
| 77476 | 179 | } | 
| 180 | ||
| 77525 
de6fb423fd4b
clarified database content: store actual value instead of index;
 wenzelm parents: 
77483diff
changeset | 181 | def read_numa_next(db: SQL.Database, hostname: String): Int = | 
| 77552 | 182 | db.execute_query_statementO[Int]( | 
| 77525 
de6fb423fd4b
clarified database content: store actual value instead of index;
 wenzelm parents: 
77483diff
changeset | 183 | Node_Info.table.select(List(Node_Info.numa_next), | 
| 77552 | 184 | sql = Node_Info.hostname.where_equal(hostname)), | 
| 185 | res => res.int(Node_Info.numa_next) | |
| 186 | ).getOrElse(0) | |
| 77476 | 187 | |
| 78174 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 188 |     def write_numa_next(db: SQL.Database, hostname: String, numa_next: Int): Unit = {
 | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 189 | 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: 
77552diff
changeset | 190 | db.execute_statement(Node_Info.table.insert(), body = | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 191 |         { stmt =>
 | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 192 | stmt.string(1) = hostname | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 193 | stmt.int(2) = numa_next | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 194 | }) | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 195 | } | 
| 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: 
78837diff
changeset | 196 | |
| 
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: 
78837diff
changeset | 197 |     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: 
78837diff
changeset | 198 |       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: 
78837diff
changeset | 199 |       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: 
78837diff
changeset | 200 |       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: 
78839diff
changeset | 201 |       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: 
78837diff
changeset | 202 | |
| 
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: 
78837diff
changeset | 203 | 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: 
78839diff
changeset | 204 | 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: 
78837diff
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: 
78837diff
changeset | 206 | |
| 
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: 
78837diff
changeset | 207 |     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: 
78837diff
changeset | 208 | 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: 
78837diff
changeset | 209 | 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: 
78837diff
changeset | 210 |         { 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: 
78837diff
changeset | 211 | 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: 
78837diff
changeset | 212 |           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: 
78837diff
changeset | 213 | 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: 
78839diff
changeset | 214 | 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: 
78837diff
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: 
78837diff
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: 
78837diff
changeset | 217 | |
| 
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: 
78837diff
changeset | 218 | 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: 
78837diff
changeset | 219 | 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: 
78837diff
changeset | 220 | 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: 
78837diff
changeset | 221 |         { 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: 
78837diff
changeset | 222 | 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: 
78837diff
changeset | 223 | 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: 
78839diff
changeset | 224 | 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: 
78837diff
changeset | 225 | |
| 78840 
4b528ca25573
added initial version of benchmark module, e.g., to compare performance of different hosts;
 Fabian Huch <huch@in.tum.de> parents: 
78839diff
changeset | 226 | 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: 
78837diff
changeset | 227 | }) | 
| 78174 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 228 | } | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 229 | |
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 230 | def next_numa_node( | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 231 | db: SQL.Database, | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 232 | hostname: String, | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 233 | available_nodes: List[Int], | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 234 | used_nodes: => Set[Int] | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 235 | ): Option[Int] = | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 236 | if (available_nodes.isEmpty) None | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 237 |     else {
 | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 238 | val available = available_nodes.zipWithIndex | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 239 | 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: 
78356diff
changeset | 240 |       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: 
78356diff
changeset | 241 | val numa_next = private_data.read_numa_next(db, hostname) | 
| 78174 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 242 |         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: 
77552diff
changeset | 243 | val candidates = available.drop(numa_index) ::: available.take(numa_index) | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 244 | val (n, i) = | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 245 |           candidates.find({ case (n, i) => i == numa_index && !used(n) }) orElse
 | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 246 |           candidates.find({ case (n, _) => !used(n) }) getOrElse candidates.head
 | 
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 247 | |
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 248 | 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: 
78356diff
changeset | 249 | 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: 
77552diff
changeset | 250 | |
| 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 251 | Some(n) | 
| 77476 | 252 | } | 
| 78174 
cc0bd66eb498
separate host.db for independent db.transaction_lock;
 wenzelm parents: 
77552diff
changeset | 253 | } | 
| 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: 
78837diff
changeset | 254 | |
| 
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: 
78837diff
changeset | 255 | 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: 
78837diff
changeset | 256 |     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: 
78837diff
changeset | 257 | 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: 
78837diff
changeset | 258 | } | 
| 
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: 
78837diff
changeset | 259 | 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: 
78837diff
changeset | 260 |     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: 
78837diff
changeset | 261 | 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: 
78837diff
changeset | 262 | } | 
| 77475 | 263 | } |