mirror of
https://github.com/mongodb/mongo.git
synced 2024-11-28 07:59:02 +01:00
855dfadef0
GitOrigin-RevId: e793d662774ccd3ab6c3f356c2287cf1f7ff9805
162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
from typing import Any, List, Optional, Tuple
|
|
|
|
import SCons.Script
|
|
from typing_extensions import TypedDict
|
|
|
|
from .protocol import BuildMetricsCollector
|
|
|
|
|
|
class _HookedStartTime(float):
|
|
def __init__(self, val) -> None:
|
|
float.__init__(val)
|
|
self.hooked_end_time = None
|
|
|
|
def __rsub__(self, other):
|
|
self.hooked_end_time = other
|
|
return other - float(self)
|
|
|
|
|
|
def _safe_list_get(list_, i, default=None):
|
|
try:
|
|
return list_[i]
|
|
except IndexError:
|
|
return default
|
|
|
|
|
|
class MemoryMetrics(TypedDict):
|
|
pre_read: int
|
|
post_read: int
|
|
pre_build: int
|
|
post_build: int
|
|
|
|
|
|
class TimeMetrics(TypedDict):
|
|
total: int
|
|
sconscript_exec: int
|
|
scons_exec: int
|
|
command_exec: int
|
|
|
|
|
|
class CountsMetrics(TypedDict):
|
|
array_index: int
|
|
item_name: str
|
|
pre_read: int
|
|
post_read: int
|
|
pre_build: int
|
|
post_build: int
|
|
|
|
|
|
class SConsStats(BuildMetricsCollector):
|
|
def __init__(self):
|
|
# hook start_time so we can also capture the end time
|
|
if not isinstance(SCons.Script.start_time, _HookedStartTime):
|
|
SCons.Script.start_time = _HookedStartTime(SCons.Script.start_time)
|
|
|
|
def get_name(self) -> str:
|
|
return "SConsStats"
|
|
|
|
def finalize(self) -> Tuple[str, Any]:
|
|
out = {}
|
|
memory = self._finalize_memory()
|
|
if memory is not None:
|
|
out["memory"] = memory
|
|
time = self._finalize_time()
|
|
if time is not None:
|
|
out["time"] = time
|
|
counts = self._finalize_counts()
|
|
if counts is not None:
|
|
out["counts"] = counts
|
|
return "scons_metrics", out
|
|
|
|
def _finalize_memory(self) -> Optional[MemoryMetrics]:
|
|
memory_stats = SCons.Script.Main.memory_stats.stats
|
|
pre_read = _safe_list_get(memory_stats, 0, 0)
|
|
post_read = _safe_list_get(memory_stats, 1, 0)
|
|
pre_build = _safe_list_get(memory_stats, 2, 0)
|
|
post_build = _safe_list_get(memory_stats, 3, 0)
|
|
if pre_read == 0 and post_read == 0 and pre_build == 0 and post_build == 0:
|
|
print(
|
|
"WARNING: SConsStats read all memory statistics as 0. Did you pass --debug=memory?"
|
|
)
|
|
return None
|
|
return MemoryMetrics(
|
|
pre_read=pre_read, post_read=post_read, pre_build=pre_build, post_build=post_build
|
|
)
|
|
|
|
def _finalize_counts(self) -> Optional[List[CountsMetrics]]:
|
|
count_stats = SCons.Script.Main.count_stats.stats
|
|
if len(count_stats) != 4:
|
|
print(
|
|
f"WARNING: SConsStats expected 4 counts, found {len(count_stats)}. Did you pass --debug=count?"
|
|
)
|
|
return None
|
|
|
|
# This incomprehensible block taken from SCons produces stats_table,
|
|
# a mapping of class name to a list of counts with the same order as
|
|
# count_stats.labels
|
|
# From SCons/Script/Main.py:517
|
|
stats_table = {}
|
|
for s in count_stats:
|
|
for n in [t[0] for t in s]:
|
|
stats_table[n] = [0, 0, 0, 0]
|
|
i = 0
|
|
for s in count_stats:
|
|
for n, c in s:
|
|
stats_table[n][i] = c
|
|
i = i + 1
|
|
# End section copied from SCons
|
|
|
|
out = []
|
|
for key, value in stats_table.items():
|
|
out.append(
|
|
CountsMetrics(
|
|
array_index=len(out),
|
|
item_name=key,
|
|
pre_read=value[0],
|
|
post_read=value[1],
|
|
pre_build=value[2],
|
|
post_build=value[3],
|
|
)
|
|
)
|
|
|
|
return out
|
|
|
|
def _finalize_time(self) -> Optional[TimeMetrics]:
|
|
# unfortunately, much of the SCons time keeping is encased in the
|
|
# main() function with local variables, so we're stuck copying
|
|
# a bit of logic from SCons.Script.Main
|
|
|
|
end_time = SCons.Script.start_time.hooked_end_time
|
|
try:
|
|
total_time = end_time - SCons.Script.start_time
|
|
except TypeError as e:
|
|
if str(e) == "unsupported operand type(s) for -: 'NoneType' and 'float'":
|
|
print(
|
|
"WARNING: SConsStats failed to calculate SCons total time. Did you pass --debug=time?"
|
|
)
|
|
return None
|
|
raise e
|
|
|
|
sconscript_time = SCons.Script.Main.sconscript_time
|
|
|
|
# From SCons/Script/Main.py:1428
|
|
if SCons.Script.Main.num_jobs == 1:
|
|
ct = SCons.Script.Main.cumulative_command_time
|
|
else:
|
|
if (
|
|
SCons.Script.Main.last_command_end is None
|
|
or SCons.Script.Main.first_command_start is None
|
|
):
|
|
ct = 0.0
|
|
else:
|
|
ct = SCons.Script.Main.last_command_end - SCons.Script.Main.first_command_start
|
|
scons_time = total_time - sconscript_time - ct
|
|
# End section copied from SCons
|
|
|
|
return TimeMetrics(
|
|
total=total_time,
|
|
sconscript_exec=sconscript_time,
|
|
scons_exec=scons_time,
|
|
command_exec=ct,
|
|
)
|