summaryrefslogtreecommitdiff
path: root/site_scons/site_tools/build_metrics/memory.py
blob: efa8320eae38b7f6a7bb5bf30e8de62afd937ff1 (plain)
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
import threading
import time
import psutil
import sys
from .util import timestamp_now, get_build_metric_dict
from .protocol import BuildMetricsCollector


class MemoryMonitor(BuildMetricsCollector):
    INTERVAL = 0.1  # seconds

    def __init__(self, starting_memory_adjustment=0):
        self._stop = False
        metrics = get_build_metric_dict()
        metrics['system_memory'] = {
            "mem_over_time": [],
            "start_mem": used_memory() - starting_memory_adjustment,
        }

        self._thread = threading.Thread(target=self.memory_monitor, daemon=True)
        self._thread.start()

    def finalize(self):
        self._stop = True
        self._record_data_point()

        metrics = get_build_metric_dict()
        sys_mem = metrics["system_memory"]

        mean = 0
        max_ = 0
        count = 1
        for val in sys_mem["mem_over_time"]:
            max_ = max(val["memory"], max_)
            # iterative mean calculation algorithm from https://stackoverflow.com/a/1934266
            mean += (val["memory"] - mean) / count
            count += 1

        sys_mem["arithmetic_mean"] = mean
        sys_mem["max"] = max_

    def memory_monitor(self):
        while not self._stop:
            time.sleep(self.INTERVAL)
            if self._stop:
                break

            self._record_data_point()

    def _record_data_point(self):
        used_mem = used_memory()
        now_time = timestamp_now()

        metrics = get_build_metric_dict()
        metrics["system_memory"]["mem_over_time"].append(
            {"timestamp": now_time, "memory": used_mem})


def used_memory():
    return psutil.virtual_memory().used