Skip to content

Commit e67430c

Browse files
committed
[MLGO] ML Regalloc Eviction Advisor
The bulk of the implementation is common between 'release' mode (==AOT-ed model) and 'development' mode (for training), the main difference is that in development mode, we may also log features (for training logs), inject scoring information (currently after the Virtual Register Rewriter) and then produce the log file. This patch also introduces the score injection pass, 'Register Allocation Pass Scoring', which is trivially just logging the score in development mode. Differential Revision: https://reviews.llvm.org/D117147
1 parent 7cca13b commit e67430c

18 files changed

+1668
-4
lines changed

llvm/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,13 @@ if (NOT TENSORFLOW_AOT_PATH STREQUAL "")
897897
set(LLVM_INLINER_MODEL_PATH "autogenerate")
898898
set(LLVM_INLINER_MODEL_AUTOGENERATED 1)
899899
endif()
900+
if (NOT DEFINED LLVM_RAEVICT_MODEL_PATH
901+
OR "${LLVM_RAEVICT_MODEL_PATH}" STREQUAL ""
902+
OR "${LLVM_RAEVICT_MODEL_PATH}" STREQUAL "autogenerate")
903+
set(LLVM_RAEVICT_MODEL_PATH "autogenerate")
904+
set(LLVM_RAEVICT_MODEL_AUTOGENERATED 1)
905+
endif()
906+
900907
endif()
901908

902909
# Configure the three LLVM configuration header files.

llvm/include/llvm/CodeGen/Passes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,10 @@ namespace llvm {
550550
/// The pass transforms amx intrinsics to scalar operation if the function has
551551
/// optnone attribute or it is O0.
552552
FunctionPass *createX86LowerAMXIntrinsicsPass();
553+
554+
/// When learning an eviction policy, extract score(reward) information,
555+
/// otherwise this does nothing
556+
FunctionPass *createRegAllocScoringPass();
553557
} // End llvm namespace
554558

555559
#endif

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ void initializeReassociateLegacyPassPass(PassRegistry&);
380380
void initializeRedundantDbgInstEliminationPass(PassRegistry&);
381381
void initializeRegAllocEvictionAdvisorAnalysisPass(PassRegistry &);
382382
void initializeRegAllocFastPass(PassRegistry&);
383+
void initializeRegAllocScoringPass(PassRegistry &);
383384
void initializeRegBankSelectPass(PassRegistry&);
384385
void initializeRegToMemLegacyPass(PassRegistry&);
385386
void initializeRegUsageInfoCollectorPass(PassRegistry&);
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""Generate a mock model for LLVM tests for Register Allocation.
2+
The generated model is not a neural net - it is just a tf.function with the
3+
correct input and output parameters. By construction, the mock model will always
4+
output the first liverange that can be evicted.
5+
"""
6+
import os
7+
import sys
8+
import tensorflow as tf
9+
POLICY_DECISION_LABEL = 'index_to_evict'
10+
POLICY_OUTPUT_SPEC = """
11+
[
12+
{
13+
"logging_name": "index_to_evict",
14+
"tensor_spec": {
15+
"name": "StatefulPartitionedCall",
16+
"port": 0,
17+
"type": "int64_t",
18+
"shape": [
19+
1
20+
]
21+
}
22+
}
23+
]
24+
"""
25+
PER_REGISTER_INT64_FEATURE_LIST = [
26+
'mask', 'is_hint', 'is_local', 'is_free', 'max_stage', 'min_stage'
27+
]
28+
PER_REGISTER_FLOAT32_FEATURE_LIST = ['nr_urgent',
29+
'weighed_reads_by_max', 'weighed_writes_by_max',
30+
'weighed_read_writes_by_max', 'weighed_indvars_by_max',
31+
'hint_weights_by_max', 'start_bb_freq_by_max', 'end_bb_freq_by_max',
32+
'hottest_bb_freq_by_max', 'liverange_size', 'use_def_density',
33+
'nr_defs_and_uses', 'nr_broken_hints', 'nr_rematerializable'
34+
]
35+
PER_REGISTER_FEATURE_LIST = PER_REGISTER_FLOAT32_FEATURE_LIST + \
36+
PER_REGISTER_INT64_FEATURE_LIST
37+
CONTEXT_FEATURE_LIST = ('progress', 'discount', 'reward', 'step_type')
38+
NUM_REGISTERS = 33
39+
40+
41+
def get_input_signature():
42+
"""Returns (time_step_spec, action_spec) for LLVM register allocation."""
43+
inputs = dict(
44+
(key, tf.TensorSpec(dtype=tf.int64, shape=(NUM_REGISTERS), name=key))
45+
for key in PER_REGISTER_INT64_FEATURE_LIST)
46+
inputs.update(
47+
dict((key,
48+
tf.TensorSpec(dtype=tf.float32, shape=(NUM_REGISTERS), name=key))
49+
for key in PER_REGISTER_FLOAT32_FEATURE_LIST))
50+
inputs['progress'] = tf.TensorSpec(
51+
dtype=tf.float32, shape=(), name='progress')
52+
inputs.update(
53+
dict((key, tf.TensorSpec(dtype=tf.float32, shape=(), name=key))
54+
for key in ['discount', 'reward']))
55+
inputs.update(
56+
dict((key, tf.TensorSpec(dtype=tf.int32, shape=(), name=key))
57+
for key in ['step_type']))
58+
return inputs
59+
60+
61+
def get_output_spec_path(path):
62+
return os.path.join(path, 'output_spec.json')
63+
64+
65+
def build_mock_model(path):
66+
"""Build and save the mock model with the given signature."""
67+
module = tf.Module()
68+
# We have to set this useless variable in order for the TF C API to correctly
69+
# intake it
70+
module.var = tf.Variable(0, dtype=tf.int64)
71+
72+
def action(*inputs):
73+
s1 = tf.reduce_sum([
74+
tf.cast(inputs[0][key], tf.float32) for key in PER_REGISTER_FEATURE_LIST
75+
],
76+
axis=0)
77+
s2 = tf.reduce_sum(
78+
[tf.cast(inputs[0][key], tf.float32) for key in CONTEXT_FEATURE_LIST])
79+
# Add a large number so s won't be 0.
80+
s = s1 + s2 + 123456789.123456789
81+
# Equals to mask feature.
82+
mask_alias = tf.not_equal(s * tf.cast(inputs[0]['mask'], tf.float32), 0)
83+
result = tf.math.argmax(mask_alias, axis=-1) + module.var
84+
return {POLICY_DECISION_LABEL: result}
85+
module.action = tf.function()(action)
86+
action = {
87+
'action': module.action.get_concrete_function(get_input_signature())
88+
}
89+
tf.saved_model.save(module, path, signatures=action)
90+
output_spec_path = get_output_spec_path(path)
91+
with open(output_spec_path, 'w') as f:
92+
print(f'Writing output spec to {output_spec_path}.')
93+
f.write(POLICY_OUTPUT_SPEC)
94+
95+
96+
def main(argv):
97+
assert len(argv) == 2
98+
model_path = argv[1]
99+
build_mock_model(model_path)
100+
101+
102+
if __name__ == '__main__':
103+
main(sys.argv)

llvm/lib/CodeGen/CMakeLists.txt

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
if (DEFINED LLVM_HAVE_TF_AOT OR DEFINED LLVM_HAVE_TF_API)
2+
include(TensorFlowCompile)
3+
set(LLVM_RAEVICT_MODEL_PATH_DEFAULT "models/regalloc-eviction")
4+
5+
# This url points to the most recent most which is known to be compatible with
6+
# LLVM. When better models are published, this url should be updated to aid
7+
# discoverability.
8+
set(LLVM_RAEVICT_MODEL_CURRENT_URL "TO_BE_UPDATED")
9+
10+
if (DEFINED LLVM_HAVE_TF_AOT)
11+
tf_find_and_compile(
12+
${LLVM_RAEVICT_MODEL_PATH}
13+
${LLVM_RAEVICT_MODEL_CURRENT_URL}
14+
${LLVM_RAEVICT_MODEL_PATH_DEFAULT}
15+
"../Analysis/models/gen-regalloc-eviction-test-model.py"
16+
serve
17+
action
18+
RegallocEvictModel
19+
llvm::RegallocEvictModel
20+
)
21+
endif()
22+
23+
if (DEFINED LLVM_HAVE_TF_API)
24+
list(APPEND MLLinkDeps ${tensorflow_c_api} ${tensorflow_fx})
25+
endif()
26+
endif()
27+
128
add_llvm_component_library(LLVMCodeGen
229
AggressiveAntiDepBreaker.cpp
330
AllocationOrder.cpp
@@ -199,6 +226,7 @@ add_llvm_component_library(LLVMCodeGen
199226
WasmEHPrepare.cpp
200227
WinEHPrepare.cpp
201228
XRayInstrumentation.cpp
229+
${GeneratedMLSources}
202230

203231
LiveDebugValues/LiveDebugValues.cpp
204232
LiveDebugValues/VarLocBasedImpl.cpp
@@ -208,10 +236,11 @@ add_llvm_component_library(LLVMCodeGen
208236
${LLVM_MAIN_INCLUDE_DIR}/llvm/CodeGen
209237
${LLVM_MAIN_INCLUDE_DIR}/llvm/CodeGen/PBQP
210238

211-
LINK_LIBS ${LLVM_PTHREAD_LIB}
239+
LINK_LIBS ${LLVM_PTHREAD_LIB} ${MLLinkDeps}
212240

213241
DEPENDS
214242
intrinsics_gen
243+
${MLDeps}
215244

216245
LINK_COMPONENTS
217246
Analysis

0 commit comments

Comments
 (0)