Guest User

Untitled

a guest
Jan 18th, 2023
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.90 KB | Source Code | 0 0
  1. #!/usr/bin/env python3
  2.  
  3.  
  4. import argparse
  5. import logging
  6. import math
  7. import subprocess
  8. import time
  9. from collections import Counter
  10. from typing import List
  11.  
  12.  
  13. logging.basicConfig(format='%(asctime)-15s [%(levelname)s] %(message)s')
  14. LOG = logging.getLogger(__name__)
  15. LOG.setLevel('INFO')
  16.  
  17.  
  18. def get_pid(slot: int) -> int:
  19.     """Get PID of the process running in the slot. Note that this naively assumes
  20.    the process is the worker. If it's a wrapper, the pid obtained here won't
  21.    be the right one for monitoring usage."""
  22.     # Assuming only boinc has such path pattern. Or we should prepend with full
  23.     # boinc data directory path.
  24.     sp = subprocess.run(
  25.         ["pgrep", "-f", f"/slots/{slot}/"],
  26.         stdout=subprocess.PIPE,
  27.     )
  28.     output = sp.stdout.decode("utf-8")
  29.     try:
  30.         pid = int(output)
  31.         LOG.info(f"pid of slot {slot}: {pid}")
  32.         return pid
  33.     except:
  34.         LOG.error(f"Failed to get pid for slot {slot}: {output}")
  35.         raise
  36.  
  37.  
  38. def collect_once(pid: int) -> int:
  39.     sp = subprocess.run(
  40.         ["ps", "--no-headers", "-o", "rss", "--pid", str(pid)],
  41.         stdout=subprocess.PIPE,
  42.     )
  43.     try:
  44.         rss = int(sp.stdout.decode("utf-8"))
  45.         LOG.debug(f"RSS usage of {pid}: {rss}")
  46.     except:
  47.         # Not worth crashing if process happen to exit
  48.         LOG.warning(f"Failed to get RSS for pid {pid}")
  49.         rss = 0
  50.     return rss
  51.  
  52.  
  53. def print_histogram(numbers: List[int], num_buckets: int) -> None:
  54.     numbers = [n for n in numbers if n != 0]
  55.     min_val = min(numbers)
  56.     max_val = max(numbers)
  57.     step = (max_val - min_val + 1) / num_buckets
  58.     buckets = Counter()
  59.     for n in numbers:
  60.         buckets[int((n - min_val) / step)] += 1
  61.  
  62.     count_per_star = max(1, int(max(buckets.values()) / 32))
  63.  
  64.     for i in range(num_buckets):
  65.         lower = math.ceil(min_val + i * step)
  66.         upper = math.floor(min_val + (i + 1) * step)
  67.         stars = "*" * int(buckets[i] / count_per_star)
  68.         print(f"{lower} - {upper}: {stars} ({buckets[i]})")
  69.  
  70.  
  71. def parse_args():
  72.     parser = argparse.ArgumentParser(description="Collect memory usage of a boinc task")
  73.     parser.add_argument("--slot", type=int, required=True, help="Task slot to monitor")
  74.     parser.add_argument(
  75.         "--duration", type=int, default=300, help="Duration of capture in seconds",
  76.     )
  77.     parser.add_argument(
  78.         "--buckets", type=int, default=16, help="Number of buckets for histogram",
  79.     )
  80.     parser.add_argument("--debug", action="store_true", help="Enable deubg logging")
  81.     return parser.parse_args()
  82.  
  83.  
  84. def main():
  85.     args = parse_args()
  86.     if args.debug:
  87.         LOG.setLevel('DEBUG')
  88.  
  89.     pid = get_pid(args.slot)
  90.     rsses = []
  91.     for _ in range(args.duration):
  92.         rsses.append(collect_once(pid))
  93.         time.sleep(1)
  94.  
  95.     print_histogram(rsses, args.buckets)
  96.  
  97.  
  98. if __name__ == "__main__":
  99.     main()
  100.  
Add Comment
Please, Sign In to add comment