Skip to content

Commit 6d9b2ae

Browse files
authored
compilation_runner: Option to keep temporary files (#235)
This allows users to manually re-run commands after the fact to investigate failures.
1 parent 4bcd173 commit 6d9b2ae

File tree

5 files changed

+145
-119
lines changed

5 files changed

+145
-119
lines changed

compiler_opt/rl/compilation_runner.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
'Max duration (in seconds) after which we cancel any compilation job.')
4040
_QUIET = flags.DEFINE_bool(
4141
'quiet', True, 'Whether or not to compile quietly (hiding info logging)')
42+
_KEEP_TEMPS = flags.DEFINE_string(
43+
'keep_temps', None,
44+
'Put temporary files into given directory and keep them past exit.')
4245

4346

4447
def _calculate_reward(policy: float, baseline: float) -> float:
@@ -53,6 +56,30 @@ class RewardStat:
5356
moving_average_reward: float
5457

5558

59+
class NonTemporaryDirectory:
60+
"""Behaves like `tempfile.TemporaryDirectory` but does not clean up the
61+
directory. When python 3.12 is available this class can be replaced with
62+
`TemporaryDirectory(..., delete=False)`"""
63+
64+
def __init__(
65+
self,
66+
suffix: Optional[str] = None,
67+
prefix: Optional[str] = None,
68+
dir: Optional[str] = None, # pylint: disable=redefined-builtin
69+
ignore_cleanup_errors: bool = False):
70+
_ = ignore_cleanup_errors # unused
71+
self.name = tempfile.mkdtemp(suffix, prefix, dir)
72+
73+
def __repr__(self):
74+
return f'<{self.__class__.__name__} {self.name!r}>'
75+
76+
def __enter__(self):
77+
return self.name
78+
79+
def __exit__(self, exc, value, tb):
80+
pass
81+
82+
5683
def _overwrite_trajectory_reward(sequence_example: tf.train.SequenceExample,
5784
reward: float) -> tf.train.SequenceExample:
5885
"""Overwrite the reward in the trace (sequence_example) with the given one.
@@ -376,7 +403,12 @@ def collect_data(self,
376403
compilation_runner.ProcessKilledException is passed through.
377404
ValueError if example under default policy and ml policy does not match.
378405
"""
379-
with tempfile.TemporaryDirectory() as tempdir:
406+
if _KEEP_TEMPS.present:
407+
tempdir_context = NonTemporaryDirectory(dir=_KEEP_TEMPS.value)
408+
else:
409+
tempdir_context = tempfile.TemporaryDirectory()
410+
411+
with tempdir_context as tempdir:
380412
final_cmd_line = loaded_module_spec.build_command_line(tempdir)
381413
# TODO(mtrofin): remove this once the compiler only generates this by
382414
# default
@@ -392,14 +424,17 @@ def collect_data(self,
392424

393425
if reward_stat is None:
394426
default_result = self.compile_fn(
395-
final_cmd_line, tf_policy_path='', reward_only=bool(tf_policy_path))
427+
final_cmd_line,
428+
tf_policy_path='',
429+
reward_only=bool(tf_policy_path),
430+
workdir=tempdir)
396431
reward_stat = {
397432
k: RewardStat(v[1], v[1]) for (k, v) in default_result.items()
398433
}
399434

400435
if tf_policy_path:
401436
policy_result = self.compile_fn(
402-
final_cmd_line, tf_policy_path, reward_only=False)
437+
final_cmd_line, tf_policy_path, reward_only=False, workdir=tempdir)
403438
else:
404439
policy_result = default_result
405440

@@ -444,7 +479,8 @@ def collect_data(self,
444479

445480
def compile_fn(
446481
self, command_line: corpus.FullyQualifiedCmdLine, tf_policy_path: str,
447-
reward_only: bool) -> Dict[str, Tuple[tf.train.SequenceExample, float]]:
482+
reward_only: bool,
483+
workdir: str) -> Dict[str, Tuple[tf.train.SequenceExample, float]]:
448484
"""Compiles for the given IR file under the given policy.
449485
450486
Args:

compiler_opt/rl/compilation_runner_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def _get_sequence_example(feature_value):
7777
return text_format.Parse(sequence_example_text, tf.train.SequenceExample())
7878

7979

80-
def _mock_compile_fn(file_paths, tf_policy_path, reward_only): # pylint: disable=unused-argument
80+
def _mock_compile_fn(file_paths, tf_policy_path, reward_only, workdir): # pylint: disable=unused-argument
8181
del file_paths
8282
if tf_policy_path:
8383
sequence_example = _get_sequence_example(_POLICY_FEATURE_VALUE)

compiler_opt/rl/inlining/inlining_runner.py

Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ def __init__(self, llvm_size_path: str, *args, **kwargs):
4747

4848
def compile_fn(
4949
self, command_line: corpus.FullyQualifiedCmdLine, tf_policy_path: str,
50-
reward_only: bool) -> Dict[str, Tuple[tf.train.SequenceExample, float]]:
50+
reward_only: bool,
51+
workdir: str) -> Dict[str, Tuple[tf.train.SequenceExample, float]]:
5152
"""Run inlining for the given IR file under the given policy.
5253
5354
Args:
@@ -68,56 +69,52 @@ def compile_fn(
6869
RuntimeError: if llvm-size produces unexpected output.
6970
"""
7071

71-
working_dir = tempfile.mkdtemp()
72+
working_dir = tempfile.mkdtemp(dir=workdir)
7273

7374
log_path = os.path.join(working_dir, 'log')
7475
output_native_path = os.path.join(working_dir, 'native')
7576

7677
native_size = 0
77-
try:
78-
cmdline = []
79-
if self._launcher_path:
80-
cmdline.append(self._launcher_path)
81-
cmdline.extend([self._clang_path] + list(command_line) + [
82-
'-mllvm', '-enable-ml-inliner=development', '-mllvm',
83-
'-training-log=' + log_path, '-o', output_native_path
84-
])
85-
if tf_policy_path:
86-
cmdline.extend(
87-
['-mllvm', '-ml-inliner-model-under-training=' + tf_policy_path])
88-
compilation_runner.start_cancellable_process(cmdline,
89-
self._compilation_timeout,
90-
self._cancellation_manager)
91-
cmdline = [self._llvm_size_path, output_native_path]
92-
output_bytes = compilation_runner.start_cancellable_process(
93-
cmdline,
94-
timeout=self._compilation_timeout,
95-
cancellation_manager=self._cancellation_manager,
96-
want_output=True)
97-
if not output_bytes:
98-
raise RuntimeError(f'Empty llvm-size output: {" ".join(cmdline)}')
99-
output = output_bytes.decode('utf-8')
100-
tmp = output.split('\n')
101-
if len(tmp) != 3:
102-
raise RuntimeError(f'Wrong llvm-size output {output}')
103-
tmp = tmp[1].split('\t')
104-
native_size = int(tmp[0])
105-
106-
if native_size == 0:
107-
return {}
108-
109-
if reward_only:
110-
return {_DEFAULT_IDENTIFIER: (None, native_size)}
111-
112-
result = log_reader.read_log_as_sequence_examples(log_path)
113-
if len(result) != 1:
114-
return {}
115-
sequence_example = next(iter(result.values()))
116-
117-
if not sequence_example.HasField('feature_lists'):
118-
return {}
119-
120-
finally:
121-
tf.io.gfile.rmtree(working_dir)
78+
cmdline = []
79+
if self._launcher_path:
80+
cmdline.append(self._launcher_path)
81+
cmdline.extend([self._clang_path] + list(command_line) + [
82+
'-mllvm', '-enable-ml-inliner=development', '-mllvm', '-training-log=' +
83+
log_path, '-o', output_native_path
84+
])
85+
if tf_policy_path:
86+
cmdline.extend(
87+
['-mllvm', '-ml-inliner-model-under-training=' + tf_policy_path])
88+
compilation_runner.start_cancellable_process(cmdline,
89+
self._compilation_timeout,
90+
self._cancellation_manager)
91+
cmdline = [self._llvm_size_path, output_native_path]
92+
output_bytes = compilation_runner.start_cancellable_process(
93+
cmdline,
94+
timeout=self._compilation_timeout,
95+
cancellation_manager=self._cancellation_manager,
96+
want_output=True)
97+
if not output_bytes:
98+
raise RuntimeError(f'Empty llvm-size output: {" ".join(cmdline)}')
99+
output = output_bytes.decode('utf-8')
100+
tmp = output.split('\n')
101+
if len(tmp) != 3:
102+
raise RuntimeError(f'Wrong llvm-size output {output}')
103+
tmp = tmp[1].split('\t')
104+
native_size = int(tmp[0])
105+
106+
if native_size == 0:
107+
return {}
108+
109+
if reward_only:
110+
return {_DEFAULT_IDENTIFIER: (None, native_size)}
111+
112+
result = log_reader.read_log_as_sequence_examples(log_path)
113+
if len(result) != 1:
114+
return {}
115+
sequence_example = next(iter(result.values()))
116+
117+
if not sequence_example.HasField('feature_lists'):
118+
return {}
122119

123120
return {_DEFAULT_IDENTIFIER: (sequence_example, native_size)}

compiler_opt/rl/regalloc/regalloc_runner.py

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class RegAllocRunner(compilation_runner.CompilationRunner):
4242
# construction
4343
def compile_fn(
4444
self, command_line: corpus.FullyQualifiedCmdLine, tf_policy_path: str,
45-
reward_only: bool) -> Dict[str, Tuple[tf.train.SequenceExample, float]]:
45+
reward_only: bool,
46+
workdir: str) -> Dict[str, Tuple[tf.train.SequenceExample, float]]:
4647
"""Run inlining for the given IR file under the given policy.
4748
4849
Args:
@@ -63,43 +64,39 @@ def compile_fn(
6364
RuntimeError: if llvm-size produces unexpected output.
6465
"""
6566

66-
working_dir = tempfile.mkdtemp()
67+
working_dir = tempfile.mkdtemp(dir=workdir)
6768

6869
log_path = os.path.join(working_dir, 'log')
6970
output_native_path = os.path.join(working_dir, 'native')
7071

7172
result = {}
72-
try:
73-
cmdline = []
74-
if self._launcher_path:
75-
cmdline.append(self._launcher_path)
76-
cmdline.extend([self._clang_path] + list(command_line) + [
77-
'-mllvm', '-regalloc-enable-advisor=development', '-mllvm',
78-
'-regalloc-training-log=' + log_path, '-o', output_native_path
79-
])
80-
81-
if tf_policy_path:
82-
cmdline.extend(['-mllvm', '-regalloc-model=' + tf_policy_path])
83-
compilation_runner.start_cancellable_process(cmdline,
84-
self._compilation_timeout,
85-
self._cancellation_manager)
86-
87-
# TODO(#202)
88-
log_result = log_reader.read_log_as_sequence_examples(log_path)
89-
90-
for fct_name, trajectory in log_result.items():
91-
if not trajectory.HasField('feature_lists'):
92-
continue
93-
score = (
94-
trajectory.feature_lists.feature_list['reward'].feature[-1]
95-
.float_list.value[0])
96-
if reward_only:
97-
result[fct_name] = (None, score)
98-
else:
99-
del trajectory.feature_lists.feature_list['reward']
100-
result[fct_name] = (trajectory, score)
101-
102-
finally:
103-
tf.io.gfile.rmtree(working_dir)
73+
cmdline = []
74+
if self._launcher_path:
75+
cmdline.append(self._launcher_path)
76+
cmdline.extend([self._clang_path] + list(command_line) + [
77+
'-mllvm', '-regalloc-enable-advisor=development', '-mllvm',
78+
'-regalloc-training-log=' + log_path, '-o', output_native_path
79+
])
80+
81+
if tf_policy_path:
82+
cmdline.extend(['-mllvm', '-regalloc-model=' + tf_policy_path])
83+
compilation_runner.start_cancellable_process(cmdline,
84+
self._compilation_timeout,
85+
self._cancellation_manager)
86+
87+
# TODO(#202)
88+
log_result = log_reader.read_log_as_sequence_examples(log_path)
89+
90+
for fct_name, trajectory in log_result.items():
91+
if not trajectory.HasField('feature_lists'):
92+
continue
93+
score = (
94+
trajectory.feature_lists.feature_list['reward'].feature[-1].float_list
95+
.value[0])
96+
if reward_only:
97+
result[fct_name] = (None, score)
98+
else:
99+
del trajectory.feature_lists.feature_list['reward']
100+
result[fct_name] = (trajectory, score)
104101

105102
return result

compiler_opt/rl/regalloc_priority/regalloc_priority_runner.py

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -31,50 +31,46 @@ class RegAllocPriorityRunner(compilation_runner.CompilationRunner):
3131

3232
def _compile_fn(
3333
self, file_paths: Tuple[str, ...], tf_policy_path: str, reward_only: bool,
34-
cancellation_manager: Optional[
34+
workdir: str, cancellation_manager: Optional[
3535
compilation_runner.WorkerCancellationManager]
3636
) -> Dict[str, Tuple[tf.train.SequenceExample, float]]:
3737

3838
file_paths = file_paths[0].replace('.bc', '')
39-
working_dir = tempfile.mkdtemp()
39+
working_dir = tempfile.mkdtemp(dir=workdir)
4040

4141
log_path = os.path.join(working_dir, 'log')
4242
output_native_path = os.path.join(working_dir, 'native')
4343

4444
result = {}
45-
try:
46-
command_line = []
47-
if self._launcher_path:
48-
command_line.append(self._launcher_path)
49-
command_line.extend([self._clang_path] + [
50-
'-c', file_paths, '-O3', '-mllvm', '-regalloc-priority-training-log='
51-
+ log_path, '-mllvm', '-regalloc-enable-priority-advisor=development',
52-
'-o', output_native_path
53-
])
45+
command_line = []
46+
if self._launcher_path:
47+
command_line.append(self._launcher_path)
48+
command_line.extend([self._clang_path] + [
49+
'-c', file_paths, '-O3', '-mllvm', '-regalloc-priority-training-log=' +
50+
log_path, '-mllvm', '-regalloc-enable-priority-advisor=development',
51+
'-o', output_native_path
52+
])
5453

55-
if tf_policy_path:
56-
command_line.extend(
57-
['-mllvm', '-regalloc-priority-model=' + tf_policy_path])
58-
compilation_runner.start_cancellable_process(command_line,
59-
self._compilation_timeout,
60-
cancellation_manager)
54+
if tf_policy_path:
55+
command_line.extend(
56+
['-mllvm', '-regalloc-priority-model=' + tf_policy_path])
57+
compilation_runner.start_cancellable_process(command_line,
58+
self._compilation_timeout,
59+
cancellation_manager)
6160

62-
# TODO(#202)
63-
log_result = log_reader.read_log_as_sequence_examples(log_path)
61+
# TODO(#202)
62+
log_result = log_reader.read_log_as_sequence_examples(log_path)
6463

65-
for fct_name, trajectory in log_result.items():
66-
if not trajectory.HasField('feature_lists'):
67-
continue
68-
score = (
69-
trajectory.feature_lists.feature_list['reward'].feature[-1]
70-
.float_list.value[0])
71-
if reward_only:
72-
result[fct_name] = (None, score)
73-
else:
74-
del trajectory.feature_lists.feature_list['reward']
75-
result[fct_name] = (trajectory, score)
76-
77-
finally:
78-
tf.io.gfile.rmtree(working_dir)
64+
for fct_name, trajectory in log_result.items():
65+
if not trajectory.HasField('feature_lists'):
66+
continue
67+
score = (
68+
trajectory.feature_lists.feature_list['reward'].feature[-1].float_list
69+
.value[0])
70+
if reward_only:
71+
result[fct_name] = (None, score)
72+
else:
73+
del trajectory.feature_lists.feature_list['reward']
74+
result[fct_name] = (trajectory, score)
7975

8076
return result

0 commit comments

Comments
 (0)