14#include "llvm/Config/config.h"
15#if defined(LLVM_HAVE_TFLITE)
36 "training-log", cl::Hidden,
37 cl::desc(
"Path where the development - mode inlining log is saved."));
40 "ml-inliner-model-under-training", cl::Hidden,
41 cl::desc(R
"(Path to SavedModel from the previous training iteration.
42The directory is also expected to contain a JSON specification of the
43outputs expected to be logged, where the first entry must be the
44inlining decision. The file containing the specification should be
45called output_spec.json. The expected JSON value is an array of
46dictionaries. Each dictionary should have 2 keys:
48- "tensor_spec, followed by the TensorSpec description of the
50- "logging_name", a string indicating the name to use when
51logging the output values.
56 "logging_name" : "some_name",
58 "name" : "model_name",
66The first value must always correspond to the decision.)"));
69 "ml-inliner-output-spec-override", cl::Hidden,
70 cl::desc(
"Override the path to the output spec json file. See "
71 "-ml-inliner-model-under-training documentation for the "
72 "specification of that file."));
75 cl::Hidden, cl::init(
"action_"),
76 cl::desc(
"Prefix for feature names."));
82 int64_t DefaultDecision = 0;
86 int64_t AdvisedDecision = 0;
98class TrainingLogger final {
100 TrainingLogger(
StringRef LogFileName,
const ModelUnderTrainingRunner *MUTR);
103 void logInlineEvent(
const InlineEvent &Event,
108 const ModelUnderTrainingRunner *
const MUTR;
109 std::unique_ptr<Logger>
L;
112 size_t DefaultDecisionPos = std::numeric_limits<size_t>::max();
113 size_t DecisionPos = std::numeric_limits<size_t>::max();
143 DevelopmentModeMLInlineAdvisor(
145 std::unique_ptr<MLModelRunner> ModelRunner,
146 std::function<
bool(
CallBase &)> GetDefaultAdvice,
147 std::unique_ptr<TrainingLogger>
Logger);
149 size_t getTotalSizeEstimate();
151 void updateNativeSizeEstimate(int64_t Change) {
152 *CurrentNativeSize += Change;
157 FAM.invalidate(*
F, PA);
160 std::unique_ptr<MLInlineAdvice>
163 std::optional<size_t> getNativeSizeEstimate(
const Function &
F)
const;
166 bool isLogging()
const {
return !!
Logger; }
167 std::unique_ptr<MLInlineAdvice> getMandatoryAdviceImpl(
CallBase &CB)
override;
169 const bool IsDoingInference;
170 std::unique_ptr<TrainingLogger>
Logger;
172 const std::optional<int32_t> InitialNativeSize;
173 std::optional<int32_t> CurrentNativeSize;
180 LoggingMLInlineAdvice(DevelopmentModeMLInlineAdvisor *Advisor,
CallBase &CB,
183 std::optional<size_t> CallerSizeEstimateBefore,
184 std::optional<size_t> CalleeSizeEstimateBefore,
185 bool DefaultDecision,
bool Mandatory =
false)
187 CallerSizeEstimateBefore(CallerSizeEstimateBefore),
188 CalleeSizeEstimateBefore(CalleeSizeEstimateBefore),
189 DefaultDecision(DefaultDecision), Mandatory(Mandatory) {}
191 virtual ~LoggingMLInlineAdvice() =
default;
194 DevelopmentModeMLInlineAdvisor *getAdvisor()
const {
195 return static_cast<DevelopmentModeMLInlineAdvisor *
>(Advisor);
197 void recordInliningImpl()
override {
198 MLInlineAdvice::recordInliningImpl();
199 getAdvisor()->resetNativeSize(Caller);
200 int Reward = std::numeric_limits<int>::max();
201 if (InlineSizeEstimatorAnalysis::isEvaluatorRequested() &&
202 !getAdvisor()->isForcedToStop()) {
203 int NativeSizeAfter = *getAdvisor()->getNativeSizeEstimate(*Caller) +
204 *CalleeSizeEstimateBefore;
205 Reward = NativeSizeAfter -
206 (*CallerSizeEstimateBefore + *CalleeSizeEstimateBefore);
207 getAdvisor()->updateNativeSizeEstimate(Reward);
212 void recordInliningWithCalleeDeletedImpl()
override {
213 MLInlineAdvice::recordInliningWithCalleeDeletedImpl();
214 getAdvisor()->resetNativeSize(Caller);
215 if (InlineSizeEstimatorAnalysis::isEvaluatorRequested() &&
216 !getAdvisor()->isForcedToStop()) {
217 int NativeSizeAfter = *getAdvisor()->getNativeSizeEstimate(*Caller);
218 int Reward = NativeSizeAfter -
219 (*CallerSizeEstimateBefore + *CalleeSizeEstimateBefore);
220 getAdvisor()->updateNativeSizeEstimate(Reward);
227 void recordUnsuccessfulInliningImpl(
const InlineResult &Result)
override {
228 MLInlineAdvice::recordUnsuccessfulInliningImpl(Result);
229 log(NoReward,
false);
232 void recordUnattemptedInliningImpl()
override {
233 MLInlineAdvice::recordUnattemptedInliningImpl();
234 log(NoReward,
false);
237 void log(int64_t Reward,
bool Success) {
241 Event.AdvisedDecision = isInliningRecommended();
242 Event.DefaultDecision = DefaultDecision;
244 Event.Reward = Reward;
245 Logger.logInlineEvent(Event, getAdvisor()->getModelRunner());
248 static const int64_t NoReward = 0;
250 const std::optional<size_t> CallerSizeEstimateBefore;
251 const std::optional<size_t> CalleeSizeEstimateBefore;
252 const int64_t DefaultDecision;
253 const int64_t Mandatory;
256static const std::vector<TensorSpec> TrainingOnlyFeatures{
257 TensorSpec::createSpec<float>(TFFeedPrefix +
"discount", {1}),
258 TensorSpec::createSpec<float>(TFFeedPrefix +
"reward", {1}),
259 TensorSpec::createSpec<int32_t>(TFFeedPrefix +
"step_type", {1})};
261static const std::vector<TensorSpec> getInputFeatures() {
262 std::vector<TensorSpec> InputSpecs;
264 InputSpecs.push_back(TensorSpec::createSpec<int64_t>(
265 TFFeedPrefix + FeatureMap[
I].name(), FeatureMap[
I].shape()));
272TrainingLogger::TrainingLogger(
StringRef LogFileName,
273 const ModelUnderTrainingRunner *MUTR)
274 : LogFileName(LogFileName), MUTR(MUTR) {
281 DefaultDecisionPos = FT.size();
282 FT.push_back(DefaultDecisionSpec);
284 DecisionPos = FT.size();
285 FT.push_back(InlineDecisionSpec);
287 auto OS = std::make_unique<raw_fd_ostream>(TrainingLog, EC);
289 dbgs() << (
EC.message() +
":" + TrainingLog);
291 L = std::make_unique<Logger>(
292 std::move(
OS), FT, TensorSpec::createSpec<int64_t>(RewardName, {1}),
293 InlineSizeEstimatorAnalysis::isEvaluatorRequested());
294 L->switchContext(
"");
298void TrainingLogger::logInlineEvent(
const InlineEvent &Event,
300 L->startObservation();
301 size_t CurrentFeature = 0;
303 L->logTensorValue(CurrentFeature,
304 reinterpret_cast<const char *
>(
308 for (
size_t I = 0;
I < MUTR->extraOutputsForLoggingSpecs().
size(); ++
I) {
309 const char *RawData =
310 reinterpret_cast<const char *
>(MUTR->getUntypedExtraOutputValue(
I));
311 L->logTensorValue(CurrentFeature, RawData);
315 assert(CurrentFeature == DefaultDecisionPos);
316 L->logTensorValue(DefaultDecisionPos,
317 reinterpret_cast<const char *
>(&Event.DefaultDecision));
318 L->logTensorValue(DecisionPos,
319 reinterpret_cast<const char *
>(&Event.AdvisedDecision));
321 if (InlineSizeEstimatorAnalysis::isEvaluatorRequested())
322 L->logReward(Event.Reward);
325 Effects.push_back(Event.Effect);
328DevelopmentModeMLInlineAdvisor::DevelopmentModeMLInlineAdvisor(
330 std::unique_ptr<MLModelRunner> ModelRunner,
331 std::function<
bool(
CallBase &)> GetDefaultAdvice,
332 std::unique_ptr<TrainingLogger>
Logger)
334 IsDoingInference(
isa<ModelUnderTrainingRunner>(getModelRunner())),
336 InitialNativeSize(isLogging() ? getTotalSizeEstimate() : 0),
337 CurrentNativeSize(InitialNativeSize) {
339 assert(IsDoingInference || isLogging());
343DevelopmentModeMLInlineAdvisor::getNativeSizeEstimate(
const Function &
F)
const {
344 if (!InlineSizeEstimatorAnalysis::isEvaluatorRequested())
349 F.getParent()->getContext().emitError(
350 "Native size estimator is not present.");
356std::unique_ptr<MLInlineAdvice>
357DevelopmentModeMLInlineAdvisor::getMandatoryAdviceImpl(
CallBase &CB) {
358 return std::make_unique<LoggingMLInlineAdvice>(
360 CB, getCallerORE(CB),
true,
368std::unique_ptr<MLInlineAdvice>
369DevelopmentModeMLInlineAdvisor::getAdviceFromModel(
371 if (IsDoingInference && !isLogging())
372 return MLInlineAdvisor::getAdviceFromModel(CB, ORE);
374 bool DefaultAdvice = GetDefaultAdvice(CB);
375 auto Recommendation =
376 IsDoingInference ?
static_cast<bool>(ModelRunner->evaluate<int64_t>())
378 return std::make_unique<LoggingMLInlineAdvice>(
380 CB, ORE, Recommendation,
388size_t DevelopmentModeMLInlineAdvisor::getTotalSizeEstimate() {
389 if (!InlineSizeEstimatorAnalysis::isEvaluatorRequested())
393 if (
F.isDeclaration())
395 Ret += *getNativeSizeEstimate(
F);
402 std::function<
bool(
CallBase &)> GetDefaultAdvice) {
403 auto &Ctx =
M.getContext();
404 std::unique_ptr<MLModelRunner> Runner;
405 if (TFModelUnderTrainingPath.empty())
408 Runner = ModelUnderTrainingRunner::createAndEnsureValid(
409 Ctx, TFModelUnderTrainingPath,
DecisionName, getInputFeatures(),
410 TFOutputSpecOverride);
413 std::unique_ptr<TrainingLogger>
Logger;
414 if (!TrainingLog.empty())
415 Logger = std::make_unique<TrainingLogger>(
416 TrainingLog, dyn_cast<ModelUnderTrainingRunner>(Runner.get()));
418 return std::make_unique<DevelopmentModeMLInlineAdvisor>(
419 M,
MAM, std::move(Runner), GetDefaultAdvice, std::move(
Logger));
This file implements the BitVector class.
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
Module.h This file contains the declarations for the Module class.
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A container for analyses that lazily runs them and caches their results.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Function * getCaller()
Helper to get the caller (the parent function).
InlineResult is basically true or false.
Logging utility - given an ordered specification of features, and assuming a scalar reward,...
InlineAdvice that tracks changes post inlining.
MLModelRunner interface: abstraction of a mechanism for evaluating a ML model.
void * getTensorUntyped(size_t Index)
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
void abandon()
Mark an analysis as abandoned.
StringRef - Represent a constant reference to a string, i.e.
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
constexpr size_t NumberOfFeatures
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
const std::vector< TensorSpec > FeatureMap
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
std::unique_ptr< InlineAdvisor > getDevelopmentModeAdvisor(Module &M, ModuleAnalysisManager &MAM, std::function< bool(CallBase &)> GetDefaultAdvice)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Implement std::hash so that hash_code can be used in STL containers.