// The native half of the census's residency readout: the process's own bytes,
// so a report can say where the peak is instead of implying that its largest
// named point is that peak (contract: docs/ROADMAP.md, measurement ยง63).
//
// Nothing here reads the engine, and nothing here keeps a structure alive; it
// reads two pseudo-files and returns two numbers. A platform without `/proc`
// compiles mem_rss_other.mbt instead and reports no residency at all.

///|
/// The page size `/proc/self/statm` counts in. Linux on the hosts this project
/// measures is 4096-byte pages; the fallback of a different page size only makes
/// the number wrong by a constant factor, and the contract treats a residency
/// sample as a hint toward where the peak is, not as a byte-exact figure.
const RSS_PAGE_KB : Int32 = 4

///|
/// The process's resident KB right now and its high-water KB, from `/proc`. A
/// zero means "not sampled", and the report prints no resident fields for it.
fn rss_sample() -> (Int32, Int32) {
  let rss = match @io.read_small_file("/proc/self/statm", 256) {
    Some(text) =>
      match statm_resident_pages(text) {
        Some(pages) => pages * RSS_PAGE_KB
        None => 0
      }
    None => 0
  }
  let high = match @io.read_small_file("/proc/self/status", 8192) {
    Some(text) => status_hwm_kb(text)
    None => 0
  }
  (rss, high)
}

///|
/// Field 2 of `/proc/self/statm` (field 1 is the program size in pages).
fn statm_resident_pages(text : String) -> Int32? {
  let mut index = 0
  for field in text.split(" ") {
    let f = field.trim()
    if f == "" {
      continue
    }
    if index == 1 {
      return digits(f.to_owned())
    }
    index += 1
  }
  None
}

///|
/// The `VmHWM:` line of `/proc/self/status`, in kB.
fn status_hwm_kb(text : String) -> Int32 {
  for line in text.split("\n") {
    let l = line.trim()
    if l.has_prefix("VmHWM:") {
      let rest = l[6:].to_owned()
      for field in rest.split(" ") {
        let f = field.trim()
        if f != "" {
          return match digits(f.to_owned()) {
            Some(v) => v
            None => 0
          }
        }
      }
    }
  }
  0
}

///|
/// A run of ASCII digits, or None at the first non-digit.
fn digits(text : String) -> Int32? {
  if text.length() == 0 {
    return None
  }
  let mut v = 0L
  for ch in text {
    let d = ch.to_int() - 48
    if d < 0 || d > 9 {
      return None
    }
    v = v * 10L + d.to_int64()
    if v > 2147483647L {
      return None
    }
  }
  Some(v.to_int())
}