File: rss.py

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (95 lines) | stat: -rwxr-xr-x 2,713 bytes parent folder | download | duplicates (14)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env python3
# Copyright 2022 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import subprocess
import sys
import time

kDefaultSamplerateSecs = 0.001


def PrintHelp(returncode):
  print(f"""Usage: {sys.argv[0]} [--interval I] [--freq F] [--] COMMAND

Runs COMMAND, and samples its RSS memory usage every I milliseconds (or F \
times per second).
Default sample interval is {kDefaultSamplerateSecs * 1000} ms.
'--' as argument forces all further arguments to be part of COMMAND.
""")
  sys.exit(returncode)


def Main():
  # Parse arguments.
  args = []
  samplerate_secs = kDefaultSamplerateSecs
  idx = 1
  while idx < len(sys.argv):
    arg = sys.argv[idx]
    if arg == "--":
      args += sys.argv[(idx + 1):]
      break
    if arg in ("-h", "--help", "help"):
      PrintHelp(0)
    elif arg in ("--interval", "-I"):
      if idx + 1 >= len(sys.argv):
        PrintHelp(1)
      samplerate_secs = int(sys.argv[idx + 1]) / 1000
      idx += 1  # Skip the value.
    elif arg in ("--freq", "-F"):
      if idx + 1 >= len(sys.argv):
        PrintHelp(1)
      samplerate_secs = 1 / float(sys.argv[idx + 1])
      idx += 1  # Skip the value.
    else:
      # No match for known parameter; assume it's part of the command to run.
      args.append(arg)
    idx += 1  # Go to next arg.

  cmd = " ".join(args)
  print(f"sample rate: {samplerate_secs}")
  print(f"command: {cmd}")

  # Run the child process and observe it.
  process = subprocess.Popen(cmd, shell=True)
  pid = process.pid
  print(f"pid: {pid}")
  statusfile = f"/proc/{pid}/status"
  vmsum = 0
  observed_max = 0
  reported_max = 0
  sample_count = 0
  while process.poll() is None:
    with open(statusfile, 'r') as f:
      for line in f.read().splitlines():
        if line.startswith("VmRSS"):
          rss = int(line.split()[1])
          vmsum += rss
          if rss > observed_max:
            observed_max = rss
        elif line.startswith("VmHWM"):
          peak = int(line.split()[1])
          if peak > reported_max:
            reported_max = peak
      sample_count += 1
    time.sleep(samplerate_secs)

  # Report findings.
  print("\n")
  # TODO(jkummerow): See if this is accurate enough in practice.
  walltime = sample_count * samplerate_secs
  print(f"wall time:    {walltime:.3f} s")  # Sample rate precision!
  print("")
  avg = vmsum / sample_count / 1024
  reported_max /= 1024
  observed_max /= 1024
  print(f"average RSS:  {avg:.2f} MB")
  print(f"reported max: {reported_max:.2f} MB")
  print(f"observed max: {observed_max:.2f} MB")
  sys.exit(process.returncode)


if __name__ == "__main__":
  Main()