Skip to content

Commit

Permalink
[GR-22095] Enable iterative image builds for PGO.
Browse files Browse the repository at this point in the history
PullRequest: graal/5818
  • Loading branch information
Maja Vukasovic committed Apr 2, 2020
2 parents 2564dd3 + 366081d commit 4b24462
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 38 deletions.
28 changes: 16 additions & 12 deletions substratevm/mx.substratevm/mx_substratevm_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,16 @@ def create_dacapo_classpath(self, dacapo_path, benchmark):
dacapo_nested_resources += self.collect_nested_dependencies(dacapo_dat_resource)
return dacapo_extracted, dacapo_dat_resources, dacapo_nested_resources

def collect_unique_dependencies(self, path, benchmark, exclude_libs):
deps = BaseDaCapoNativeImageBenchmarkSuite.collect_dependencies(path)
# if there are more versions of the same jar, we choose one and omit remaining from the classpath
if benchmark in exclude_libs:
for lib in exclude_libs[benchmark]:
lib_path = mx.join(path, lib)
if lib_path in deps:
deps.remove(mx.join(path, lib))
return deps


_DACAPO_EXTRA_VM_ARGS = {
'avrora': ['-Dnative-image.benchmark.extra-image-build-argument=--initialize-at-build-time=org.apache.derby.jdbc.ClientDriver,'
Expand Down Expand Up @@ -588,6 +598,10 @@ def create_dacapo_classpath(self, dacapo_path, benchmark):
'xalan' : 30, # Needs both xalan.jar and xalan-2.7.2.jar. Different library versions on classpath aren't supported.
}

_daCapo_exclude_lib = {
'h2' : ['derbytools.jar', 'derbyTesting.jar', 'derbyclient.jar', 'derbynet.jar'] # multiple derby classes occurrences on the classpath can cause a security error
}

class DaCapoNativeImageBenchmarkSuite(mx_graal_benchmark.DaCapoBenchmarkSuite, BaseDaCapoNativeImageBenchmarkSuite): #pylint: disable=too-many-ancestors
def name(self):
return 'dacapo-native-image'
Expand Down Expand Up @@ -636,7 +650,7 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs):

def create_classpath(self, benchmark):
dacapo_extracted, dacapo_dat_resources, dacapo_nested_resources = self.create_dacapo_classpath(self.daCapoPath(), benchmark)
dacapo_jars = self.collect_dependencies(os.path.join(dacapo_extracted, 'jar'))
dacapo_jars = super(DaCapoNativeImageBenchmarkSuite, self).collect_unique_dependencies(os.path.join(dacapo_extracted, 'jar'), benchmark, _scala_daCapo_exclude_lib)
cp = ':'.join([dacapo_extracted] + dacapo_jars + dacapo_dat_resources + dacapo_nested_resources)
return cp

Expand Down Expand Up @@ -738,7 +752,7 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs):

def create_classpath(self, benchmark):
dacapo_extracted, dacapo_dat_resources, dacapo_nested_resources = self.create_dacapo_classpath(self.daCapoPath(), benchmark)
dacapo_jars = self.collect_unique_dependencies(os.path.join(dacapo_extracted, 'jar'), benchmark)
dacapo_jars = super(ScalaDaCapoNativeImageBenchmarkSuite, self).collect_unique_dependencies(os.path.join(dacapo_extracted, 'jar'), benchmark, _scala_daCapo_exclude_lib)
cp = ':'.join([self.substitution_path()] + [dacapo_extracted] + dacapo_jars + dacapo_dat_resources + dacapo_nested_resources)
if benchmark == 'scalaxb':
cp += ':' + self.daCapoAdditionalLib()
Expand All @@ -750,15 +764,5 @@ def substitution_path():
root_dir = mx.join(bench_suite.dir, "mxbuild")
return os.path.abspath(mx.join(root_dir, 'java/com.oracle.svm.bench.scaladacapo/bin/'))

def collect_unique_dependencies(self, path, benchmark):
deps = super(ScalaDaCapoNativeImageBenchmarkSuite, self).collect_dependencies(path)
# if there are more versions of the same jar, we choose one and omit remaining from the classpath
if benchmark in _scala_daCapo_exclude_lib:
for lib in _scala_daCapo_exclude_lib[benchmark]:
lib_path = mx.join(path, lib)
if lib_path in deps:
deps.remove(mx.join(path, lib))
return deps


mx_benchmark.add_bm_suite(ScalaDaCapoNativeImageBenchmarkSuite())
69 changes: 43 additions & 26 deletions vm/mx.vm/mx_vm_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def __init__(self):
self.config_dir = None
self.profile_dir = None
self.log_dir = None
self.pgo_iteration_num = None

def parse(self, args):
def add_to_list(arg, name, arg_list):
Expand Down Expand Up @@ -140,6 +141,9 @@ def add_to_list(arg, name, arg_list):
if trimmed_arg.startswith('benchmark-name='):
self.benchmark_name = trimmed_arg[len('benchmark-name='):]
found = True
if trimmed_arg.startswith('instrumentation-iteration-num='):
self.pgo_iteration_num = trimmed_arg[len('instrumentation-iteration-num='):]
found = True
if not found:
mx.abort("Invalid benchmark argument: " + arg)
else:
Expand Down Expand Up @@ -224,7 +228,9 @@ def run_java(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False):
config.output_dir = mx.mkdtemp(suffix='bench-' + executable_name, prefix='native-image', dir=non_tmp_dir)
config.profile_dir = config.output_dir
config.log_dir = config.output_dir
profile_path = os.path.join(config.profile_dir, executable_name + '.iprof')
profile_path_no_extension = os.path.join(config.profile_dir, executable_name)
extension = '.iprof'
profile_path = profile_path_no_extension + extension
image_path = os.path.join(config.output_dir, executable_name)

# Agent configuration and/or HotSpot profiling
Expand Down Expand Up @@ -275,31 +281,39 @@ def run_java(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False):

# PGO instrumentation
i = 0
while i < self.pgo_instrumented_iterations:
instrument_args = ['--pgo-instrument'] + ([] if i == 0 and not self.hotspot_pgo else ['--pgo'])
instrument_image_build_args = base_image_build_args + instrument_args
mx.log('Building the instrumentation image with: ')
mx.log(' ' + ' '.join([pipes.quote(str(arg)) for arg in instrument_image_build_args]))
mx.run(instrument_image_build_args, out=None, err=None, cwd=image_cwd, nonZeroIsFatal=non_zero_is_fatal)

image_run_cmd = [image_path]
image_run_cmd += ['-XX:ProfilesDumpFile=' + profile_path]
if config.extra_profile_run_args:
image_run_cmd += config.extra_profile_run_args
else:
image_run_cmd += image_run_args + config.extra_run_args

mx.log('Running the instrumented image with: ')
mx.log(' ' + ' '.join([pipes.quote(str(arg)) for arg in image_run_cmd]))
inst_stdout_path = os.path.abspath(os.path.join(config.log_dir, executable_name + '-instrument-' + str(i) + '-stdout.log'))
inst_stderr_path = os.path.abspath(os.path.join(config.log_dir, executable_name + '-instrument-' + str(i) + '-stderr.log'))
with open(inst_stdout_path, 'a') as inst_stdout, open(inst_stderr_path, 'a') as inst_stderr:
mx.log('The standard output saved to ' + inst_stdout_path)
mx.log('The standard error saved to ' + inst_stderr_path)
mx.run(image_run_cmd, out=inst_stdout.write,
err=inst_stderr.write, cwd=image_cwd, nonZeroIsFatal=non_zero_is_fatal)

i += 1
instrumented_iterations = self.pgo_instrumented_iterations if config.pgo_iteration_num is None else int(config.pgo_iteration_num)
if not self.hotspot_pgo:
pgo_verification_output_path = os.path.join(config.output_dir, executable_name + '-probabilities.log')
while i < instrumented_iterations:
pgo_args = ['--pgo=' + profile_path, '-H:+VerifyPGOProfiles', '-H:VerificationDumpFile=' + pgo_verification_output_path]
instrument_args = ['--pgo-instrument'] + ([] if i == 0 else pgo_args)
instrument_image_build_args = base_image_build_args + instrument_args
mx.log('Building the instrumentation image with: ')
mx.log(' ' + ' '.join([pipes.quote(str(arg)) for arg in instrument_image_build_args]))
mx.run(instrument_image_build_args, out=None, err=None, cwd=image_cwd, nonZeroIsFatal=non_zero_is_fatal)

image_run_cmd = [image_path]
profile_path = profile_path_no_extension + (str(i) + extension if i > 0 else extension)
image_run_cmd += ['-XX:ProfilesDumpFile=' + profile_path]
if config.extra_profile_run_args:
image_run_cmd += config.extra_profile_run_args
else:
image_run_cmd += image_run_args + config.extra_run_args

mx.log('Running the instrumented image with: ')
mx.log(' ' + ' '.join([pipes.quote(str(arg)) for arg in image_run_cmd]))
inst_stdout_path = os.path.abspath(os.path.join(config.log_dir, executable_name + '-instrument-' + str(i) + '-stdout.log'))
inst_stderr_path = os.path.abspath(os.path.join(config.log_dir, executable_name + '-instrument-' + str(i) + '-stderr.log'))
with open(inst_stdout_path, 'a') as inst_stdout, open(inst_stderr_path, 'a') as inst_stderr:
mx.log('The standard output saved to ' + inst_stdout_path)
mx.log('The standard error saved to ' + inst_stderr_path)
mx.run(image_run_cmd, out=inst_stdout.write,
err=inst_stderr.write, cwd=image_cwd, nonZeroIsFatal=non_zero_is_fatal)

image_size = os.stat(image_path).st_size
mx.log('Produced image size is ' + str(image_size) + ' B')

i += 1

# Build the final image
pgo_verification_output_path = os.path.join(config.output_dir, executable_name + '-probabilities.log')
Expand All @@ -314,6 +328,9 @@ def run_java(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False):
mx.log('Running the produced native executable with: ')
mx.log(' ' + ' '.join([pipes.quote(str(arg)) for arg in image_run_cmd]))
mx.run(image_run_cmd, out=out, err=err, cwd=image_cwd, nonZeroIsFatal=non_zero_is_fatal)
image_path = mx.join(config.output_dir, executable_name)
image_size = os.stat(image_path).st_size
mx.log('Final image size is ' + str(image_size) + ' B')


class NativeImageBuildVm(GraalVm):
Expand Down

0 comments on commit 4b24462

Please sign in to comment.