Skip to content

Commit 9d9717e

Browse files
committed
Track also private memory size and run heap benchmarks for small benchmarks, on SVM, and on cpython
1 parent afbfb47 commit 9d9717e

File tree

5 files changed

+94
-27
lines changed

5 files changed

+94
-27
lines changed

ci.jsonnet

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,13 @@
391391
for bench in ["warmup"]
392392
} + {
393393
[bench]: bench_task(bench) + platform_spec(no_jobs) + bench_variants({
394-
"vm_name:graalpython_enterprise_interpreter" : {"linux:amd64:jdk-latest" : post_merge + t("00:30:00")},
394+
"vm_name:graalvm_ee_default_interpreter" : {"linux:amd64:jdk-latest" : post_merge + t("01:00:00")},
395+
"vm_name:graalvm_ee_default_interpreter_bc_dsl" : {"linux:amd64:jdk-latest" : post_merge + t("01:00:00")},
396+
"vm_name:graalpython_enterprise_interpreter" : {"linux:amd64:jdk-latest" : daily + t("01:00:00")},
397+
"vm_name:graalpython_enterprise_interpreter_bc_dsl" : {"linux:amd64:jdk-latest" : daily + t("01:00:00")},
398+
"vm_name:cpython" : {"linux:amd64:jdk-latest" : weekly + t("00:30:00")},
395399
}),
396-
for bench in ["heap"]
400+
for bench in ["heap", "micro_small_heap"]
397401
} + {
398402
// interop benchmarks only for graalpython, weekly is enough
399403
[bench]: bench_task(bench) + platform_spec(no_jobs) + bench_variants({

ci/python-bench.libsonnet

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
java_embedding_meso_small: "java-embedding-meso-small:*",
3838
jmh: "python-jmh:GRAALPYTHON_BENCH",
3939
heap: "heap-graalpython:*",
40+
micro_small_heap: "micro-small-heap-graalpython:*",
4041
},
4142

4243
PY_BENCHMARKS:: {

mx.graalpython/live_heap_tracker.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,42 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40-
import sys
41-
import time
42-
40+
from pathlib import Path
4341
import re
4442
import subprocess
43+
import sys
44+
import time
4545

4646
TOTAL_RE = re.compile(r'^Total +\d+ +(\d+)', re.MULTILINE)
47+
PRIVATE_RE = re.compile(r'Private_(?:Clean|Dirty):\s+(\d+) kB')
48+
49+
50+
def jmap(jmap_binary, ppid):
51+
if not jmap_binary:
52+
return 0
53+
try:
54+
jmap_output = subprocess.check_output(
55+
[jmap_binary, '-histo:live', str(ppid)],
56+
universal_newlines=True,
57+
stderr=subprocess.DEVNULL,
58+
)
59+
if match := TOTAL_RE.search(jmap_output):
60+
heap_bytes = int(match.group(1))
61+
return heap_bytes
62+
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
63+
pass
64+
return 0
65+
66+
67+
def uss(ppid):
68+
smap = Path(f"/proc/{ppid}/smaps")
69+
try:
70+
memory_map = smap.read_text()
71+
total_bytes = sum(int(val) * 1024 for val in PRIVATE_RE.findall(memory_map))
72+
return total_bytes
73+
except FileNotFoundError:
74+
pass
75+
return 0
4776

4877

4978
def main():
@@ -54,19 +83,12 @@ def main():
5483
with open(output_file, 'w') as f:
5584
for _ in range(iterations):
5685
proc = subprocess.Popen(benchmark)
86+
ppid = proc.pid
5787
while proc.poll() is None:
5888
time.sleep(0.3)
59-
try:
60-
jmap_output = subprocess.check_output(
61-
[jmap_binary, '-histo:live', str(proc.pid)],
62-
universal_newlines=True,
63-
stderr=subprocess.DEVNULL,
64-
)
65-
if match := TOTAL_RE.search(jmap_output):
66-
heap_bytes = int(match.group(1))
67-
f.write(f'{heap_bytes}\n')
68-
except subprocess.CalledProcessError:
69-
pass
89+
uss_bytes = uss(ppid)
90+
heap_bytes = jmap(jmap_binary, ppid)
91+
f.write(f"{heap_bytes} {uss_bytes}\n")
7092
if proc.returncode != 0:
7193
sys.exit(proc.returncode)
7294

mx.graalpython/mx_graalpython_bench_param.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,5 +340,6 @@ def _pickling_benchmarks(module='pickle'):
340340
"post-startup": [],
341341
"import-a-lot": [],
342342
"allocate-objects": [],
343-
}]
343+
}],
344+
"micro-small-heap": [PATH_MICRO, MICRO_BENCHMARKS_SMALL],
344345
}

mx.graalpython/mx_graalpython_benchmark.py

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -949,9 +949,15 @@ def map_command(self, cmd):
949949
if self.bmSuite:
950950
bench_name = f"{self.bmSuite.name()}-{bench_name}"
951951
ts = datetime.now().strftime("%Y%m%d-%H%M%S")
952-
jmap_command = mx.get_jdk().exe_path('jmap')
952+
vm = self.bmSuite.execution_context.virtual_machine
953+
if isinstance(vm, GraalPythonVm) and vm.launcher_type == "jvm":
954+
jmap_command = mx.get_jdk().exe_path('jmap')
955+
else:
956+
jmap_command = ""
953957
self.out_file = os.path.join(os.getcwd(), f"heap_tracker_{bench_name}_{ts}.txt")
954958
iterations = 3
959+
if "-i" in cmd:
960+
cmd[cmd.index("-i") + 1] = "1"
955961
return [sys.executable, str(DIR / 'live_heap_tracker.py'), self.out_file, str(iterations), jmap_command, *cmd]
956962

957963
def get_rules(self, bmSuiteArgs):
@@ -964,18 +970,41 @@ def __init__(self, tracker, bmSuiteArgs):
964970

965971
def parse(self, text):
966972
with open(self.tracker.out_file) as f:
967-
heap_mb = [int(line.strip()) / (1024 ** 2) for line in f if line]
973+
heap_mb, uss_mb = zip(*(map(lambda i: int(i) / (1024 ** 2), line.split()) for line in f if line))
968974
os.unlink(self.tracker.out_file)
969-
self.tracker.out_file = None
970-
deciles = statistics.quantiles(heap_mb, n=10)
971-
print(f"Heap size deciles (MiB): {deciles}")
975+
heap_deciles = statistics.quantiles(heap_mb, n=10)
976+
uss_deciles = statistics.quantiles(uss_mb, n=10)
977+
print(f"Heap size deciles (MiB): {heap_deciles}")
978+
print(f"USS size deciles (MiB): {uss_deciles}")
979+
# The heap benchmarks are a separate suite, because they are run
980+
# very differently, but we want to be able to conveniently query
981+
# all data about the same suites that we have. So, if this suite
982+
# name ends with "-heap", we drop that so it gets attributed to the
983+
# base suite.
984+
suite = self.tracker.bmSuite.benchSuiteName(self.bmSuiteArgs)
985+
if suite.endswith("-heap"):
986+
suite = suite[:-len("-heap")]
987+
benchmark = f"{suite}.{self.tracker.bmSuite.currently_running_benchmark()}"
988+
vm_flags = ' '.join(self.tracker.bmSuite.vmArgs(self.bmSuiteArgs))
972989
return [
973990
PythonBaseBenchmarkSuite.with_branch_and_commit_dict({
974-
"benchmark": self.tracker.bmSuite.currently_running_benchmark(),
975-
"bench-suite": self.tracker.bmSuite.benchSuiteName(self.bmSuiteArgs),
976-
"config.vm-flags": ' '.join(self.tracker.bmSuite.vmArgs(self.bmSuiteArgs)),
991+
"benchmark": benchmark,
992+
"bench-suite": suite,
993+
"config.vm-flags": vm_flags,
977994
"metric.name": "allocated-memory",
978-
"metric.value": deciles[-1],
995+
"metric.value": heap_deciles[-1],
996+
"metric.unit": "MB",
997+
"metric.type": "numeric",
998+
"metric.score-function": "id",
999+
"metric.better": "lower",
1000+
"metric.iteration": 0
1001+
}),
1002+
PythonBaseBenchmarkSuite.with_branch_and_commit_dict({
1003+
"benchmark": benchmark,
1004+
"bench-suite": suite,
1005+
"config.vm-flags": vm_flags,
1006+
"metric.name": "memory",
1007+
"metric.value": uss_deciles[-1],
9791008
"metric.unit": "MB",
9801009
"metric.type": "numeric",
9811010
"metric.score-function": "id",
@@ -1004,7 +1033,17 @@ def register_tracker(self, name, tracker_type):
10041033
def createCommandLineArgs(self, benchmarks, bmSuiteArgs):
10051034
benchmark = benchmarks[0]
10061035
bench_path = os.path.join(self._bench_path, f'{benchmark}.py')
1007-
return [*self.vmArgs(bmSuiteArgs), bench_path, *self.runArgs(bmSuiteArgs)]
1036+
bench_args = self._benchmarks[benchmark]
1037+
run_args = self.runArgs(bmSuiteArgs)
1038+
cmd_args = []
1039+
if "-i" in bench_args:
1040+
# Need to use the harness to parse
1041+
cmd_args.append(HARNESS_PATH)
1042+
if "-i" not in run_args:
1043+
# Explicit iteration count overrides default
1044+
run_args += bench_args
1045+
cmd_args.append(bench_path)
1046+
return [*self.vmArgs(bmSuiteArgs), *cmd_args, *run_args]
10081047

10091048
def successPatterns(self):
10101049
return []

0 commit comments

Comments
 (0)