# HG changeset patch # User Fabian Huch # Date 1697648006 -7200 # Node ID f97e23eaa62880f69cdb726c10d10e63bf584c52 # Parent dd350a41594c52f400ba6ff0a647580296da6046 added Range object to Host, e.g. to parse/unparse NUMA node ranges; diff -r dd350a41594c -r f97e23eaa628 src/Pure/System/host.scala --- a/src/Pure/System/host.scala Wed Oct 18 18:48:49 2023 +0200 +++ b/src/Pure/System/host.scala Wed Oct 18 18:53:26 2023 +0200 @@ -12,6 +12,42 @@ object Host { + + object Range { + val Single = """^(\d+)$""".r + val Multiple = """^(\d+)-(\d+)$""".r + + def apply(range: List[Int]): String = + range match { + case Nil => "" + case x :: xs => + def elem(start: Int, stop: Int): String = + if (start == stop) start.toString else start.toString + "-" + stop.toString + + val (elems, (r0, rn)) = + xs.foldLeft((List.empty[String], (x, x))) { + case ((rs, (r0, rn)), x) => + if (rn + 1 == x) (rs, (r0, x)) else (rs :+ elem(r0, rn), (x, x)) + } + + (elems :+ elem(r0, rn)).mkString(",") + } + + def unapply(s: String): Option[List[Int]] = + space_explode(',', s).foldRight(Option(List.empty[Int])) { + case (Single(Value.Int(i)), Some(elems)) => Some(i :: elems) + case (Multiple(Value.Int(i), Value.Int(j)), Some(elems)) => Some((i to j).toList ::: elems) + case _ => None + } + + def from(s: String) = + s match { + case Range(r) => r + case _ => Nil + } + } + + /* process policy via numactl tool */ def numactl(node: Int): String = "numactl -m" + node + " -N" + node @@ -39,23 +75,18 @@ private val numa_info_linux: Path = Path.explode("/sys/devices/system/node/online") - def numa_nodes(enabled: Boolean = true, ssh: SSH.System = SSH.Local): List[Int] = { - val Single = """^(\d+)$""".r - val Multiple = """^(\d+)-(\d+)$""".r + def parse_numa_info(numa_info: String): List[Int] = + numa_info match { + case Range(nodes) => nodes + case s => error("Cannot parse CPU NUMA node specification: " + quote(s)) + } - def parse(s: String): List[Int] = - s match { - case Single(Value.Int(i)) => List(i) - case Multiple(Value.Int(i), Value.Int(j)) => (i to j).toList - case _ => error("Cannot parse CPU NUMA node specification: " + quote(s)) - } - + def numa_nodes(enabled: Boolean = true, ssh: SSH.System = SSH.Local): List[Int] = { val numa_info = if (ssh.isabelle_platform.is_linux) Some(numa_info_linux) else None for { path <- numa_info.toList if enabled && ssh.is_file(path) - s <- space_explode(',', ssh.read(path).trim) - n <- parse(s) + n <- parse_numa_info(ssh.read(path).trim) } yield n }