Skip to content

Commit 2b80bcb

Browse files
OracleLabsAutomationelkorchi
authored andcommitted
[GR-58956] [GR-59164] [GR-58956] Backport to 24.1: Add barista benchmark suite.
PullRequest: graal/19129
2 parents c6cf550 + e091b96 commit 2b80bcb

File tree

8 files changed

+623
-8
lines changed

8 files changed

+623
-8
lines changed

Diff for: common.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"Jsonnet files should not include this file directly but use ci/common.jsonnet instead."
55
],
66

7-
"mx_version": "7.27.5.1",
7+
"mx_version": "7.27.5.3",
88

99
"COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet",
1010
"jdks": {

Diff for: compiler/ci/ci_common/benchmark-builders.jsonnet

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
c.daily + c.opt_post_merge + hw.e3 + jdk + cc.libgraal + bench.dacapo + PR_bench_libgraal,
1515
c.daily + c.opt_post_merge + hw.e3 + jdk + cc.libgraal + bench.scala_dacapo + PR_bench_libgraal,
1616
c.daily + c.opt_post_merge + hw.e3 + jdk + cc.libgraal + bench.renaissance + PR_bench_libgraal,
17+
c.daily + c.opt_post_merge + hw.e3 + jdk + cc.libgraal + bench.barista,
1718
c.daily + c.opt_post_merge + hw.e3 + jdk + cc.libgraal + bench.specjvm2008 + PR_bench_libgraal,
1819
c.on_demand + hw.e3 + jdk + cc.libgraal + bench.dacapo_size_variants,
1920
c.on_demand + hw.e3 + jdk + cc.libgraal + bench.scala_dacapo_size_variants,

Diff for: compiler/ci/ci_common/benchmark-suites.libsonnet

+42-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// convenient sets of benchmark suites for easy reuse
1010
groups:: {
11-
open_suites:: unique_suites([$.awfy, $.dacapo, $.scala_dacapo, $.renaissance]),
11+
open_suites:: unique_suites([$.awfy, $.dacapo, $.scala_dacapo, $.renaissance, $.barista]),
1212
spec_suites:: unique_suites([$.specjvm2008, $.specjbb2015]),
1313
jmh_micros_suites:: unique_suites([$.micros_graal_dist]),
1414
graal_internals_suites:: unique_suites([$.micros_graal_whitebox]),
@@ -112,6 +112,47 @@
112112

113113
renaissance: self.renaissance_template(),
114114

115+
barista_template(suite_version=null, suite_name="barista", max_jdk_version=null, cmd_app_prefix=["hwloc-bind --cpubind node:0.core:0-3.pu:0 --membind node:0"], non_prefix_barista_args=[]):: cc.compiler_benchmark + {
116+
suite:: suite_name,
117+
local barista_version = "v0.2.0",
118+
local suite_version_args = if suite_version != null then ["--bench-suite-version=" + suite_version] else [],
119+
local prefix_barista_arg = if std.length(cmd_app_prefix) > 0 then [std.format("--cmd-app-prefix=%s", std.join(" ", cmd_app_prefix))] else [],
120+
local all_barista_args = prefix_barista_arg + non_prefix_barista_args,
121+
local barista_args_with_separator = if std.length(all_barista_args) > 0 then ["--"] + all_barista_args else [],
122+
downloads+: {
123+
"WRK": { "name": "wrk", "version": "a211dd5", platformspecific: true},
124+
"WRK2": { "name": "wrk2", "version": "2.1", platformspecific: true},
125+
"BARISTA_BENCHMARKS": { "name": "barista", "version": "0.2.0"}
126+
},
127+
packages+: {
128+
maven: "==3.8.6",
129+
"pip:toml": "==0.10.2"
130+
},
131+
setup: [
132+
["set-export", "PATH", "$WRK:$PATH"],
133+
["set-export", "PATH", "$WRK2:$PATH"],
134+
["git", "clone", "--depth", "1", "--branch", barista_version, ["mx", "urlrewrite", "https://github.com/graalvm/barista-suite.git"], "$BARISTA_HOME"],
135+
["cp", "-r", "$BARISTA_BENCHMARKS/*", "$BARISTA_HOME"] // copy the prebuilt jar/nib files
136+
] + super.setup,
137+
run+: [
138+
self.benchmark_cmd + ["barista:*"] + suite_version_args + ["--"] + self.extra_vm_args + barista_args_with_separator
139+
],
140+
notify_emails+: ["[email protected]"],
141+
timelimit: "1:20:00",
142+
should_use_hwloc: false, // hwloc-bind is passed to barista with '--cmd-app-prefix'
143+
environment+: {
144+
BARISTA_HOME: "$BUILD_DIR/barista-suite",
145+
XMX: "500m"
146+
},
147+
min_jdk_version:: 8,
148+
max_jdk_version:: max_jdk_version,
149+
forks_batches:: 3,
150+
bench_forks_per_batch:: 4,
151+
forks_timelimit:: "3:30:00"
152+
},
153+
154+
barista: self.barista_template(),
155+
115156
specjbb2015: cc.compiler_benchmark + c.heap.large_with_large_young_gen + bc.bench_max_threads + {
116157
suite:: "specjbb2015",
117158
downloads+: {

Diff for: sdk/mx.sdk/mx_sdk_benchmark.py

+370
Large diffs are not rendered by default.

Diff for: sdk/mx.sdk/suite.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
# SOFTWARE.
4040
#
4141
suite = {
42-
"mxversion": "7.27.0",
42+
"mxversion": "7.27.5.3",
4343
"name" : "sdk",
4444
"version" : "24.1.2",
4545
"release" : False,

Diff for: substratevm/mx.substratevm/mx_substratevm_benchmark.py

+200
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import os
2929
import tempfile
3030
import zipfile
31+
import re
3132
from glob import glob
33+
from pathlib import Path
3234

3335
import mx
3436
import mx_benchmark
@@ -264,6 +266,204 @@ def successPatterns(self):
264266
mx_benchmark.add_bm_suite(RenaissanceNativeImageBenchmarkSuite())
265267

266268

269+
class BaristaNativeImageBenchmarkSuite(mx_sdk_benchmark.BaristaBenchmarkSuite, mx_sdk_benchmark.NativeImageBenchmarkMixin, mx_sdk_benchmark.NativeImageBundleBasedBenchmarkMixin):
270+
"""Native Image variant of the Barista benchmark suite implementation. A collection of microservice workloads running in native execution mode on the Barista harness.
271+
272+
The run arguments are passed to the Barista harness.
273+
If you want to run something like `hwloc-bind` or `taskset` prefixed before the app image, you should use the '--cmd-app-prefix' Barista harness option.
274+
If you want to pass options to the app image, you should use the '--app-args' Barista harness option.
275+
"""
276+
def __init__(self, custom_harness_command: mx_benchmark.CustomHarnessCommand = None):
277+
if custom_harness_command is None:
278+
custom_harness_command = BaristaNativeImageBenchmarkSuite.BaristaNativeImageCommand()
279+
super().__init__(custom_harness_command)
280+
self._application_nibs = {}
281+
# because of an issue in handling image build args in the intended order [GR-58214]
282+
# we need the image name that is set inside the nib
283+
self._application_fixed_image_names = {}
284+
285+
def name(self):
286+
return "barista-native-image"
287+
288+
def benchSuiteName(self, bmSuiteArgs=None):
289+
return "barista"
290+
291+
def benchmarkName(self):
292+
return self.context.benchmark
293+
294+
def application_nib(self):
295+
if self.benchmarkName() not in self._application_nibs:
296+
# Run subprocess retrieving the application nib from the Barista 'build' script
297+
out = mx.OutputCapture()
298+
mx.run([self.baristaBuilderPath(), "--get-nib", self.baristaHarnessBenchmarkName()], out=out)
299+
# Capture the application nib from the Barista 'build' script output
300+
nib_pattern = r"application nib file path is: ([^\n]+)\n"
301+
nib_match = re.search(nib_pattern, out.data)
302+
if not nib_match:
303+
raise ValueError(f"Could not extract the nib file path from the command output! Expected to match pattern {repr(nib_pattern)}.")
304+
# Cache for future access
305+
self._application_nibs[self.benchmarkName()] = nib_match.group(1)
306+
# Try to capture the fixed image name from the Barista 'build' script output
307+
fixed_image_name_pattern = r"fixed image name is: ([^\n]+)\n"
308+
fixed_image_name_match = re.search(fixed_image_name_pattern, out.data)
309+
# Cache fixed image name, if present
310+
if fixed_image_name_match:
311+
self._application_fixed_image_names[self.benchmarkName()] = fixed_image_name_match.group(1)
312+
return self._application_nibs[self.benchmarkName()]
313+
314+
def application_fixed_image_name(self):
315+
self.application_nib()
316+
return self._application_fixed_image_names.get(self.benchmarkName(), None)
317+
318+
def applicationDist(self):
319+
return Path(self.application_nib()).parent
320+
321+
def uses_bundles(self):
322+
return True
323+
324+
def createCommandLineArgs(self, benchmarks, bmSuiteArgs):
325+
# Pass the VM options, BaristaNativeImageCommand will form the final command.
326+
return self.vmArgs(bmSuiteArgs)
327+
328+
def extra_jvm_arg(self, benchmark, args):
329+
# Added by BaristaNativeImageCommand
330+
return []
331+
332+
def extra_agent_run_arg(self, benchmark, args, image_run_args):
333+
# Added by BaristaNativeImageCommand
334+
return []
335+
336+
def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_run_args):
337+
# Added by BaristaNativeImageCommand
338+
return []
339+
340+
def extra_run_arg(self, benchmark, args, image_run_args):
341+
# Added by BaristaNativeImageCommand
342+
return []
343+
344+
def run(self, benchmarks, bmSuiteArgs) -> mx_benchmark.DataPoints:
345+
return self.intercept_run(super(), benchmarks, bmSuiteArgs)
346+
347+
def ensure_image_is_at_desired_location(self, bmSuiteArgs):
348+
if self.stages_info.requested_stage.is_image() and self.application_fixed_image_name() is not None:
349+
# Because of an issue in handling image build args in the intended order [GR-58214]
350+
# we need to move the image from the path that is set inside the nib to the path expected by our vm.
351+
# This code has no effect if the image is already at the desired location.
352+
vm = self.get_vm_registry().get_vm_from_suite_args(bmSuiteArgs)
353+
if vm.stages_info.should_produce_datapoints(mx_sdk_benchmark.Stage.INSTRUMENT_IMAGE):
354+
desired_image_path = vm.config.instrumented_image_path
355+
elif vm.stages_info.should_produce_datapoints(mx_sdk_benchmark.Stage.IMAGE):
356+
desired_image_path = vm.config.image_path
357+
else:
358+
return
359+
actual_image_path = desired_image_path.parent / self.application_fixed_image_name()
360+
if actual_image_path.is_file() and not desired_image_path.is_file():
361+
mx.move(actual_image_path, desired_image_path)
362+
363+
def runAndReturnStdOut(self, benchmarks, bmSuiteArgs):
364+
retcode, out, dims = super().runAndReturnStdOut(benchmarks, bmSuiteArgs)
365+
self.ensure_image_is_at_desired_location(bmSuiteArgs)
366+
return retcode, out, dims
367+
368+
class BaristaNativeImageCommand(mx_sdk_benchmark.BaristaBenchmarkSuite.BaristaCommand):
369+
"""Maps the command produced by NativeImageVM into a command tailored for the Barista harness.
370+
"""
371+
def _short_load_testing_phases(self):
372+
"""Configures the main barista load-testing phases to be quite short.
373+
374+
Useful for the `agent` and `instrument-run` stages.
375+
"""
376+
return [
377+
"--warmup-iteration-count", "1",
378+
"--warmup-duration", "5",
379+
"--throughput-iteration-count", "0",
380+
"--latency-iteration-count", "0",
381+
]
382+
383+
def _get_built_app_image(self, suite, stage):
384+
"""Retrieves the path to the app image built in the previous stage.
385+
386+
In the case of `instrument-run`, retrieves the image built during `instrument-image`.
387+
In the case of `run`, retrieves the image built during `image`.
388+
"""
389+
vm = suite.context.vm
390+
if stage == mx_sdk_benchmark.Stage.INSTRUMENT_RUN:
391+
return vm.config.instrumented_image_path
392+
else:
393+
return vm.config.image_path
394+
395+
def produce_JVM_harness_command(self, cmd, suite):
396+
"""Maps a JVM command into a command tailored for the Barista harness.
397+
398+
Utilizes the implementation of the ``mx_sdk_benchmark.BaristaBenchmarkSuite.BaristaCommand`` base class
399+
"""
400+
return super().produceHarnessCommand(cmd, suite)
401+
402+
def produceHarnessCommand(self, cmd, suite):
403+
"""Maps a NativeImageVM command into a command tailored for the Barista harness.
404+
405+
This method is invoked only in the `agent`, `instrument-run` and `run` stages, because hooks are
406+
only applied in these stages (defined in ``NativeImageBenchmarkMixin.run_stage``).
407+
In the case of the `agent` stage, relies on the parent ``BaristaCommand`` class for the mapping.
408+
409+
:param list[str] cmd: NativeImageVM command to be mapped.
410+
:param BaristaNativeImageBenchmarkSuite suite: Barista benchmark suite running the benchmark on the Barista harness.
411+
:return: Command tailored for the Barista harness.
412+
:rtype: list[str]
413+
"""
414+
if not isinstance(suite, BaristaNativeImageBenchmarkSuite):
415+
raise TypeError(f"Expected an instance of {BaristaNativeImageBenchmarkSuite.__name__}, instead got an instance of {suite.__class__.__name__}")
416+
417+
stage = suite.stages_info.requested_stage
418+
if stage == mx_sdk_benchmark.Stage.AGENT:
419+
# BaristaCommand works for agent stage, since it's a JVM stage
420+
cmd = self.produce_JVM_harness_command(cmd, suite)
421+
# Make agent run short
422+
cmd += self._short_load_testing_phases()
423+
# Add explicit agent stage args
424+
cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-jvm-arg=", suite.context.bmSuiteArgs)
425+
cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-agent-run-arg=", suite.context.bmSuiteArgs)
426+
return cmd
427+
428+
# Extract app image options and command prefix from the NativeImageVM command
429+
app_image = str(self._get_built_app_image(suite, stage))
430+
try:
431+
index_of_app_image = cmd.index(app_image)
432+
except:
433+
mx.log_error(f"Could not find app image '{app_image}' in {cmd}")
434+
raise
435+
nivm_cmd_prefix = cmd[:index_of_app_image]
436+
nivm_app_options = cmd[index_of_app_image + 1:]
437+
438+
# Get bench name and workload to use in the barista harness - we might have custom named benchmarks that need to be mapped
439+
barista_bench_name = suite.baristaHarnessBenchmarkName()
440+
barista_workload = suite.baristaHarnessBenchmarkWorkload()
441+
442+
# Provide image built in the previous stage to the Barista harnesss using the `--app-executable` option
443+
ni_barista_cmd = [suite.baristaHarnessPath(), "--mode", "native", "--app-executable", app_image]
444+
if barista_workload is not None:
445+
ni_barista_cmd.append(f"--config={barista_workload}")
446+
ni_barista_cmd += suite.runArgs(suite.context.bmSuiteArgs)
447+
ni_barista_cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-jvm-arg=", suite.context.bmSuiteArgs)
448+
if stage == mx_sdk_benchmark.Stage.INSTRUMENT_RUN:
449+
# Make instrument run short
450+
ni_barista_cmd += self._short_load_testing_phases()
451+
# Add explicit instrument stage args
452+
ni_barista_cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-profile-run-arg=", suite.context.bmSuiteArgs) or mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-run-arg=", suite.context.bmSuiteArgs)
453+
else:
454+
# Add explicit run stage args
455+
ni_barista_cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-run-arg=", suite.context.bmSuiteArgs)
456+
if nivm_cmd_prefix:
457+
self._updateCommandOption(ni_barista_cmd, "--cmd-app-prefix", "-p", " ".join(nivm_cmd_prefix))
458+
if nivm_app_options:
459+
self._updateCommandOption(ni_barista_cmd, "--app-args", "-a", " ".join(nivm_app_options))
460+
ni_barista_cmd += [barista_bench_name]
461+
return ni_barista_cmd
462+
463+
464+
mx_benchmark.add_bm_suite(BaristaNativeImageBenchmarkSuite())
465+
466+
267467
class BaseDaCapoNativeImageBenchmarkSuite():
268468

269469
'''`SetBuildInfo` method in DaCapo source reads from the file nested in daCapo jar.

Diff for: substratevm/mx.substratevm/suite.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# pylint: disable=line-too-long
22
suite = {
3-
"mxversion": "7.27.1",
3+
"mxversion": "7.27.5.3",
44
"name": "substratevm",
55
"version" : "24.1.2",
66
"release" : False,

Diff for: vm/mx.vm/mx_vm_benchmark.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def __init__(self, vm: NativeImageVM, bm_suite: BenchmarkSuite | NativeImageBenc
134134
self.bm_suite = bm_suite
135135
self.benchmark_suite_name = bm_suite.benchSuiteName(args)
136136
self.benchmark_name = bm_suite.benchmarkName()
137-
self.executable, self.classpath_arguments, self.modulepath_arguments, self.system_properties, self.image_vm_args, image_run_args, self.split_run = NativeImageVM.extract_benchmark_arguments(args)
137+
self.executable, self.classpath_arguments, self.modulepath_arguments, self.system_properties, self.image_vm_args, image_run_args, self.split_run = NativeImageVM.extract_benchmark_arguments(args, bm_suite.all_command_line_args_are_vm_args())
138138
self.extra_image_build_arguments: List[str] = bm_suite.extra_image_build_argument(self.benchmark_name, args)
139139
# use list() to create fresh copies to safeguard against accidental modification
140140
self.image_run_args = bm_suite.extra_run_arg(self.benchmark_name, args, list(image_run_args))
@@ -720,7 +720,10 @@ def supported_vm_arg_prefixes():
720720
'--patch-module', '--boot-class-path', '--source-path', '-cp', '-classpath', '-p']
721721

722722
@staticmethod
723-
def _split_vm_arguments(args):
723+
def _split_vm_arguments(args, all_args_are_vm_args):
724+
if all_args_are_vm_args:
725+
return args, [], []
726+
724727
i = 0
725728
while i < len(args):
726729
arg = args[i]
@@ -736,7 +739,7 @@ def _split_vm_arguments(args):
736739
mx.abort('No executable found in args: ' + str(args))
737740

738741
@staticmethod
739-
def extract_benchmark_arguments(args):
742+
def extract_benchmark_arguments(args, all_args_are_vm_args):
740743
i = 0
741744
clean_args = args[:]
742745
split_run = None
@@ -750,7 +753,7 @@ def extract_benchmark_arguments(args):
750753
else:
751754
i += 1
752755
clean_args = [x for x in clean_args if "-Dnative-image" not in x]
753-
vm_args, executable, image_run_args = NativeImageVM._split_vm_arguments(clean_args)
756+
vm_args, executable, image_run_args = NativeImageVM._split_vm_arguments(clean_args, all_args_are_vm_args)
754757

755758
classpath_arguments = []
756759
modulepath_arguments = []

0 commit comments

Comments
 (0)