xref: /llvm-project/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp (revision 383419931e5a0d58e6bc1ea898db07b4a967e344)
170f8d0acSMircea Trofin //===- DevelopmentModeInlineAdvisor.cpp - runtime-loadable model runner  --===//
270f8d0acSMircea Trofin //
3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
670f8d0acSMircea Trofin //
770f8d0acSMircea Trofin //===----------------------------------------------------------------------===//
870f8d0acSMircea Trofin //
928bb2193SMircea Trofin // This file implements a model runner using TFLite, allowing the
1070f8d0acSMircea Trofin // loading of a model from a command line option.
1170f8d0acSMircea Trofin //
1270f8d0acSMircea Trofin //===----------------------------------------------------------------------===//
131ee3bb17SMircea Trofin #include "llvm/Analysis/TensorSpec.h"
144fe912f1SNico Weber #include "llvm/Config/config.h"
15edc83a15SKazu Hirata #if defined(LLVM_HAVE_TFLITE)
164fe912f1SNico Weber 
175f4ae564SJan Svoboda #include "llvm/ADT/BitVector.h"
1870f8d0acSMircea Trofin #include "llvm/Analysis/CallGraph.h"
1970f8d0acSMircea Trofin #include "llvm/Analysis/InlineSizeEstimatorAnalysis.h"
2070f8d0acSMircea Trofin #include "llvm/Analysis/MLInlineAdvisor.h"
2104f2712eSMircea Trofin #include "llvm/Analysis/ModelUnderTrainingRunner.h"
22059e0347SMircea Trofin #include "llvm/Analysis/NoInferenceModelRunner.h"
2370f8d0acSMircea Trofin #include "llvm/Analysis/Utils/TFUtils.h"
240cb9746aSMircea Trofin #include "llvm/Analysis/Utils/TrainingLogger.h"
2570f8d0acSMircea Trofin #include "llvm/IR/LLVMContext.h"
26*38341993SMircea Trofin #include "llvm/IR/Module.h"
2770f8d0acSMircea Trofin #include "llvm/Support/CommandLine.h"
2870f8d0acSMircea Trofin #include "llvm/Support/ManagedStatic.h"
2970f8d0acSMircea Trofin 
3070f8d0acSMircea Trofin #include <vector>
319c444f70SKazu Hirata #include <optional>
3270f8d0acSMircea Trofin 
3370f8d0acSMircea Trofin using namespace llvm;
3470f8d0acSMircea Trofin 
3570f8d0acSMircea Trofin static cl::opt<std::string> TrainingLog(
3670f8d0acSMircea Trofin     "training-log", cl::Hidden,
3770f8d0acSMircea Trofin     cl::desc("Path where the development - mode inlining log is saved."));
3870f8d0acSMircea Trofin 
3970f8d0acSMircea Trofin static cl::opt<std::string> TFModelUnderTrainingPath(
4070f8d0acSMircea Trofin     "ml-inliner-model-under-training", cl::Hidden,
4162fc44caSMircea Trofin     cl::desc(R"(Path to SavedModel from the previous training iteration.
4262fc44caSMircea Trofin The directory is also expected to contain a JSON specification of the
4362fc44caSMircea Trofin outputs expected to be logged, where the first entry must be the
4462fc44caSMircea Trofin inlining decision. The file containing the specification should be
4562fc44caSMircea Trofin called output_spec.json. The expected JSON value is an array of
4662fc44caSMircea Trofin dictionaries. Each dictionary should have 2 keys:
4762fc44caSMircea Trofin 
4862fc44caSMircea Trofin - "tensor_spec, followed by the TensorSpec description of the
4962fc44caSMircea Trofin output; and
5062fc44caSMircea Trofin - "logging_name", a string indicating the name to use when
5162fc44caSMircea Trofin logging the output values.
5262fc44caSMircea Trofin 
5362fc44caSMircea Trofin Example:
5462fc44caSMircea Trofin [
5562fc44caSMircea Trofin   {
5662fc44caSMircea Trofin     "logging_name" : "some_name",
5762fc44caSMircea Trofin     "tensor_spec" : {
5862fc44caSMircea Trofin       "name" : "model_name",
5962fc44caSMircea Trofin       "port" : 0,
6062fc44caSMircea Trofin       "shape" : [2, 3],
6162fc44caSMircea Trofin       "type" : "float"
6262fc44caSMircea Trofin       }
6362fc44caSMircea Trofin   }
6462fc44caSMircea Trofin ]
6562fc44caSMircea Trofin 
6662fc44caSMircea Trofin The first value must always correspond to the decision.)"));
6762fc44caSMircea Trofin 
6862fc44caSMircea Trofin static cl::opt<std::string> TFOutputSpecOverride(
6962fc44caSMircea Trofin     "ml-inliner-output-spec-override", cl::Hidden,
7062fc44caSMircea Trofin     cl::desc("Override the path to the output spec json file. See "
7162fc44caSMircea Trofin              "-ml-inliner-model-under-training documentation for the "
7262fc44caSMircea Trofin              "specification of that file."));
7370f8d0acSMircea Trofin 
7470f8d0acSMircea Trofin static cl::opt<std::string> TFFeedPrefix("ml-inliner-trained-model-feed-prefix",
7570f8d0acSMircea Trofin                                          cl::Hidden, cl::init("action_"),
7670f8d0acSMircea Trofin                                          cl::desc("Prefix for feature names."));
7770f8d0acSMircea Trofin 
7870f8d0acSMircea Trofin namespace {
7970f8d0acSMircea Trofin /// An InlineEvent, used by TrainingLogger.
8070f8d0acSMircea Trofin struct InlineEvent {
8170f8d0acSMircea Trofin   /// What the default policy's decision would have been.
8236bb1fb1SMircea Trofin   int64_t DefaultDecision = 0;
8370f8d0acSMircea Trofin 
8470f8d0acSMircea Trofin   /// What we advised. When training off the default policy, this is the same as
8570f8d0acSMircea Trofin   /// DefaultDecision.
8636bb1fb1SMircea Trofin   int64_t AdvisedDecision = 0;
8770f8d0acSMircea Trofin 
8870f8d0acSMircea Trofin   /// What actually happened. This would be 'false' in the case of an inline
8970f8d0acSMircea Trofin   /// error, even if AdvisedDecision were true, otherwise it agrees with
9070f8d0acSMircea Trofin   /// AdvisedDecision.
9170f8d0acSMircea Trofin   bool Effect = false;
9270f8d0acSMircea Trofin 
9370f8d0acSMircea Trofin   /// What the change in size was: size_after - size_before
9470f8d0acSMircea Trofin   int64_t Reward = 0;
9570f8d0acSMircea Trofin };
9670f8d0acSMircea Trofin 
975898be19SMircea Trofin /// Collect data we may use for training a model.
9870f8d0acSMircea Trofin class TrainingLogger final {
9970f8d0acSMircea Trofin public:
10062fc44caSMircea Trofin   TrainingLogger(StringRef LogFileName, const ModelUnderTrainingRunner *MUTR);
10170f8d0acSMircea Trofin 
10270f8d0acSMircea Trofin   /// Log one inlining event.
10370f8d0acSMircea Trofin   void logInlineEvent(const InlineEvent &Event,
10465b6dbf9SMircea Trofin                       const MLModelRunner &ModelRunner);
10570f8d0acSMircea Trofin 
10670f8d0acSMircea Trofin private:
107d5c81be3SMircea Trofin   StringRef LogFileName;
10862fc44caSMircea Trofin   const ModelUnderTrainingRunner *const MUTR;
10936bb1fb1SMircea Trofin   std::unique_ptr<Logger> L;
1105f4ae564SJan Svoboda   BitVector Effects;
11136bb1fb1SMircea Trofin   /// Set these 2 clearly OOB, to make sure we set them later.
11236bb1fb1SMircea Trofin   size_t DefaultDecisionPos = std::numeric_limits<size_t>::max();
11336bb1fb1SMircea Trofin   size_t DecisionPos = std::numeric_limits<size_t>::max();
11470f8d0acSMircea Trofin };
11570f8d0acSMircea Trofin 
11670f8d0acSMircea Trofin /// An extension of the MLInlineAdvisor for the 'development' mode, targeting
11770f8d0acSMircea Trofin /// the offline training scenario. Note that training happens outside of the
11870f8d0acSMircea Trofin /// compiler, this facility is concerned with producing training data ("logs").
11970f8d0acSMircea Trofin /// This InlineAdvisor can operate in the following modes:
12070f8d0acSMircea Trofin ///
12170f8d0acSMircea Trofin /// 1) collect logs for the default policy. This is useful for bootstrapping
12270f8d0acSMircea Trofin /// training, which will be considerably faster by starting from a reasonable
12370f8d0acSMircea Trofin /// policy.
12470f8d0acSMircea Trofin ///
12570f8d0acSMircea Trofin /// 2) collect logs for the ML policy, using a model from a previous
12670f8d0acSMircea Trofin /// training. Potentially, that model uses internally some small random
12770f8d0acSMircea Trofin /// perturbation of its weights, to induce exploration (setting this up is the
12870f8d0acSMircea Trofin /// responsibility of the training algorithm). The logs would then be used to
12970f8d0acSMircea Trofin /// retrain and improve on this model.
13070f8d0acSMircea Trofin ///
13170f8d0acSMircea Trofin /// 3) use the provided model, with no logging. This is useful for end to end
13270f8d0acSMircea Trofin /// validation - the model, in this case, is a release candidate and shouldn't
13370f8d0acSMircea Trofin /// have random perturbations. It is a convenience feature: rather than needing
13470f8d0acSMircea Trofin /// to take the release candidate model and compile it in 'release' mode,
13570f8d0acSMircea Trofin /// validate it, then potentially discard it, it's easier to just pass the model
13670f8d0acSMircea Trofin /// to the compiler, albeit compilation would be slower, as a one-off. Once the
13770f8d0acSMircea Trofin /// model behaves satisfactorily, it can be compiled AOT, for efficiency, in
13870f8d0acSMircea Trofin /// release mode. The expectation is that a well-trained model provides a good
13970f8d0acSMircea Trofin /// policy over a sufficiently diverse codebase, over many changes (i.e.
14070f8d0acSMircea Trofin /// training happens seldom).
14170f8d0acSMircea Trofin class DevelopmentModeMLInlineAdvisor : public MLInlineAdvisor {
14270f8d0acSMircea Trofin public:
14370f8d0acSMircea Trofin   DevelopmentModeMLInlineAdvisor(
14470f8d0acSMircea Trofin       Module &M, ModuleAnalysisManager &MAM,
14570f8d0acSMircea Trofin       std::unique_ptr<MLModelRunner> ModelRunner,
146a120fdd3SMircea Trofin       std::function<bool(CallBase &)> GetDefaultAdvice,
147d5c81be3SMircea Trofin       std::unique_ptr<TrainingLogger> Logger);
14870f8d0acSMircea Trofin 
14970f8d0acSMircea Trofin   size_t getTotalSizeEstimate();
15070f8d0acSMircea Trofin 
updateNativeSizeEstimate(int64_t Change)1518c63df24SMircea Trofin   void updateNativeSizeEstimate(int64_t Change) {
1528c63df24SMircea Trofin     *CurrentNativeSize += Change;
1538c63df24SMircea Trofin   }
15470f8d0acSMircea Trofin   void resetNativeSize(Function *F) {
1550d06b14fSMircea Trofin     PreservedAnalyses PA = PreservedAnalyses::all();
1560d06b14fSMircea Trofin     PA.abandon<InlineSizeEstimatorAnalysis>();
1570d06b14fSMircea Trofin     FAM.invalidate(*F, PA);
15870f8d0acSMircea Trofin   }
15970f8d0acSMircea Trofin 
16070f8d0acSMircea Trofin   std::unique_ptr<MLInlineAdvice>
16170f8d0acSMircea Trofin   getAdviceFromModel(CallBase &CB, OptimizationRemarkEmitter &ORE) override;
16270f8d0acSMircea Trofin 
163d4b6fcb3SFangrui Song   std::optional<size_t> getNativeSizeEstimate(const Function &F) const;
16470f8d0acSMircea Trofin 
16570f8d0acSMircea Trofin private:
166d5c81be3SMircea Trofin   bool isLogging() const { return !!Logger; }
167e8049dc3SMircea Trofin   std::unique_ptr<MLInlineAdvice> getMandatoryAdviceImpl(CallBase &CB) override;
16870f8d0acSMircea Trofin 
16970f8d0acSMircea Trofin   const bool IsDoingInference;
170d5c81be3SMircea Trofin   std::unique_ptr<TrainingLogger> Logger;
17170f8d0acSMircea Trofin 
172d4b6fcb3SFangrui Song   const std::optional<int32_t> InitialNativeSize;
173d4b6fcb3SFangrui Song   std::optional<int32_t> CurrentNativeSize;
17470f8d0acSMircea Trofin };
17570f8d0acSMircea Trofin 
17670f8d0acSMircea Trofin /// A variant of MLInlineAdvice that tracks all non-trivial inlining
17770f8d0acSMircea Trofin /// decisions, for training/logging.
17870f8d0acSMircea Trofin class LoggingMLInlineAdvice : public MLInlineAdvice {
17970f8d0acSMircea Trofin public:
18070f8d0acSMircea Trofin   LoggingMLInlineAdvice(DevelopmentModeMLInlineAdvisor *Advisor, CallBase &CB,
18170f8d0acSMircea Trofin                         OptimizationRemarkEmitter &ORE, bool Recommendation,
1828c63df24SMircea Trofin                         TrainingLogger &Logger,
183d4b6fcb3SFangrui Song                         std::optional<size_t> CallerSizeEstimateBefore,
184d4b6fcb3SFangrui Song                         std::optional<size_t> CalleeSizeEstimateBefore,
1858c63df24SMircea Trofin                         bool DefaultDecision, bool Mandatory = false)
18670f8d0acSMircea Trofin       : MLInlineAdvice(Advisor, CB, ORE, Recommendation), Logger(Logger),
18770f8d0acSMircea Trofin         CallerSizeEstimateBefore(CallerSizeEstimateBefore),
18870f8d0acSMircea Trofin         CalleeSizeEstimateBefore(CalleeSizeEstimateBefore),
18987fb7aa1SMircea Trofin         DefaultDecision(DefaultDecision), Mandatory(Mandatory) {}
19070f8d0acSMircea Trofin 
19170f8d0acSMircea Trofin   virtual ~LoggingMLInlineAdvice() = default;
19270f8d0acSMircea Trofin 
19370f8d0acSMircea Trofin private:
19470f8d0acSMircea Trofin   DevelopmentModeMLInlineAdvisor *getAdvisor() const {
19570f8d0acSMircea Trofin     return static_cast<DevelopmentModeMLInlineAdvisor *>(Advisor);
19670f8d0acSMircea Trofin   }
19770f8d0acSMircea Trofin   void recordInliningImpl() override {
19870f8d0acSMircea Trofin     MLInlineAdvice::recordInliningImpl();
19970f8d0acSMircea Trofin     getAdvisor()->resetNativeSize(Caller);
20070f8d0acSMircea Trofin     int Reward = std::numeric_limits<int>::max();
2018c63df24SMircea Trofin     if (InlineSizeEstimatorAnalysis::isEvaluatorRequested() &&
2028c63df24SMircea Trofin         !getAdvisor()->isForcedToStop()) {
2038c63df24SMircea Trofin       int NativeSizeAfter = *getAdvisor()->getNativeSizeEstimate(*Caller) +
2048c63df24SMircea Trofin                             *CalleeSizeEstimateBefore;
20570f8d0acSMircea Trofin       Reward = NativeSizeAfter -
2068c63df24SMircea Trofin                (*CallerSizeEstimateBefore + *CalleeSizeEstimateBefore);
20770f8d0acSMircea Trofin       getAdvisor()->updateNativeSizeEstimate(Reward);
20870f8d0acSMircea Trofin     }
20970f8d0acSMircea Trofin     log(Reward, /*Success=*/true);
21070f8d0acSMircea Trofin   }
21170f8d0acSMircea Trofin 
21270f8d0acSMircea Trofin   void recordInliningWithCalleeDeletedImpl() override {
21370f8d0acSMircea Trofin     MLInlineAdvice::recordInliningWithCalleeDeletedImpl();
21470f8d0acSMircea Trofin     getAdvisor()->resetNativeSize(Caller);
2158c63df24SMircea Trofin     if (InlineSizeEstimatorAnalysis::isEvaluatorRequested() &&
2168c63df24SMircea Trofin         !getAdvisor()->isForcedToStop()) {
2178c63df24SMircea Trofin       int NativeSizeAfter = *getAdvisor()->getNativeSizeEstimate(*Caller);
21870f8d0acSMircea Trofin       int Reward = NativeSizeAfter -
2198c63df24SMircea Trofin                    (*CallerSizeEstimateBefore + *CalleeSizeEstimateBefore);
22070f8d0acSMircea Trofin       getAdvisor()->updateNativeSizeEstimate(Reward);
22170f8d0acSMircea Trofin       log(Reward, /*Success=*/true);
2221055c5e1SMircea Trofin     } else {
2231055c5e1SMircea Trofin       log(NoReward, /*Success=*/true);
22470f8d0acSMircea Trofin     }
22570f8d0acSMircea Trofin   }
22670f8d0acSMircea Trofin 
22770f8d0acSMircea Trofin   void recordUnsuccessfulInliningImpl(const InlineResult &Result) override {
22870f8d0acSMircea Trofin     MLInlineAdvice::recordUnsuccessfulInliningImpl(Result);
22970f8d0acSMircea Trofin     log(NoReward, /*Success=*/false);
23070f8d0acSMircea Trofin   }
23170f8d0acSMircea Trofin 
23270f8d0acSMircea Trofin   void recordUnattemptedInliningImpl() override {
23370f8d0acSMircea Trofin     MLInlineAdvice::recordUnattemptedInliningImpl();
23470f8d0acSMircea Trofin     log(NoReward, /*Success=*/false);
23570f8d0acSMircea Trofin   }
23670f8d0acSMircea Trofin 
23770f8d0acSMircea Trofin   void log(int64_t Reward, bool Success) {
23887fb7aa1SMircea Trofin     if (Mandatory)
23987fb7aa1SMircea Trofin       return;
24070f8d0acSMircea Trofin     InlineEvent Event;
24170f8d0acSMircea Trofin     Event.AdvisedDecision = isInliningRecommended();
24270f8d0acSMircea Trofin     Event.DefaultDecision = DefaultDecision;
24370f8d0acSMircea Trofin     Event.Effect = Success;
24470f8d0acSMircea Trofin     Event.Reward = Reward;
24570f8d0acSMircea Trofin     Logger.logInlineEvent(Event, getAdvisor()->getModelRunner());
24670f8d0acSMircea Trofin   }
24770f8d0acSMircea Trofin 
24870f8d0acSMircea Trofin   static const int64_t NoReward = 0;
24970f8d0acSMircea Trofin   TrainingLogger &Logger;
250d4b6fcb3SFangrui Song   const std::optional<size_t> CallerSizeEstimateBefore;
251d4b6fcb3SFangrui Song   const std::optional<size_t> CalleeSizeEstimateBefore;
25236bb1fb1SMircea Trofin   const int64_t DefaultDecision;
25336bb1fb1SMircea Trofin   const int64_t Mandatory;
25470f8d0acSMircea Trofin };
25570f8d0acSMircea Trofin 
25604f2712eSMircea Trofin static const std::vector<TensorSpec> TrainingOnlyFeatures{
25771059257SMircea Trofin     TensorSpec::createSpec<float>(TFFeedPrefix + "discount", {1}),
25871059257SMircea Trofin     TensorSpec::createSpec<float>(TFFeedPrefix + "reward", {1}),
25971059257SMircea Trofin     TensorSpec::createSpec<int32_t>(TFFeedPrefix + "step_type", {1})};
26004f2712eSMircea Trofin 
26104f2712eSMircea Trofin static const std::vector<TensorSpec> getInputFeatures() {
26204f2712eSMircea Trofin   std::vector<TensorSpec> InputSpecs;
26304f2712eSMircea Trofin   for (size_t I = 0; I < NumberOfFeatures; ++I)
264c35ad9eeSMircea Trofin     InputSpecs.push_back(TensorSpec::createSpec<int64_t>(
265c35ad9eeSMircea Trofin         TFFeedPrefix + FeatureMap[I].name(), FeatureMap[I].shape()));
26604f2712eSMircea Trofin   append_range(InputSpecs, TrainingOnlyFeatures);
26704f2712eSMircea Trofin   return InputSpecs;
26804f2712eSMircea Trofin }
26904f2712eSMircea Trofin 
27070f8d0acSMircea Trofin } // namespace
27170f8d0acSMircea Trofin 
27262fc44caSMircea Trofin TrainingLogger::TrainingLogger(StringRef LogFileName,
27362fc44caSMircea Trofin                                const ModelUnderTrainingRunner *MUTR)
27462fc44caSMircea Trofin     : LogFileName(LogFileName), MUTR(MUTR) {
27562fc44caSMircea Trofin   // The first output is the inlining decision.
2761ee3bb17SMircea Trofin   std::vector<TensorSpec> FT(FeatureMap.begin(), FeatureMap.end());
27736bb1fb1SMircea Trofin 
2781ee3bb17SMircea Trofin   if (MUTR)
2791ee3bb17SMircea Trofin     append_range(FT, MUTR->extraOutputsForLoggingSpecs());
28036bb1fb1SMircea Trofin 
28136bb1fb1SMircea Trofin   DefaultDecisionPos = FT.size();
282ab2e7666SMircea Trofin   FT.push_back(DefaultDecisionSpec);
28336bb1fb1SMircea Trofin 
28436bb1fb1SMircea Trofin   DecisionPos = FT.size();
2855fd51fcbSMircea Trofin   FT.push_back(InlineDecisionSpec);
2866d11baf0SMircea Trofin   std::error_code EC;
2876d11baf0SMircea Trofin   auto OS = std::make_unique<raw_fd_ostream>(TrainingLog, EC);
2886d11baf0SMircea Trofin   if (EC)
2896d11baf0SMircea Trofin     dbgs() << (EC.message() + ":" + TrainingLog);
29036bb1fb1SMircea Trofin 
29136bb1fb1SMircea Trofin   L = std::make_unique<Logger>(
2926d11baf0SMircea Trofin       std::move(OS), FT, TensorSpec::createSpec<int64_t>(RewardName, {1}),
29336bb1fb1SMircea Trofin       InlineSizeEstimatorAnalysis::isEvaluatorRequested());
2946d11baf0SMircea Trofin   L->switchContext("");
29565b6dbf9SMircea Trofin }
29665b6dbf9SMircea Trofin 
29765b6dbf9SMircea Trofin /// Log one inlining event.
29865b6dbf9SMircea Trofin void TrainingLogger::logInlineEvent(const InlineEvent &Event,
29965b6dbf9SMircea Trofin                                     const MLModelRunner &ModelRunner) {
3006d11baf0SMircea Trofin   L->startObservation();
30136bb1fb1SMircea Trofin   size_t CurrentFeature = 0;
3026d11baf0SMircea Trofin   for (; CurrentFeature < NumberOfFeatures; ++CurrentFeature)
3036d11baf0SMircea Trofin     L->logTensorValue(CurrentFeature,
3046d11baf0SMircea Trofin                       reinterpret_cast<const char *>(
3056d11baf0SMircea Trofin                           ModelRunner.getTensorUntyped(CurrentFeature)));
306211117b6SMircea Trofin 
3071ee3bb17SMircea Trofin   if (MUTR)
3081ee3bb17SMircea Trofin     for (size_t I = 0; I < MUTR->extraOutputsForLoggingSpecs().size(); ++I) {
30962fc44caSMircea Trofin       const char *RawData =
3101ee3bb17SMircea Trofin           reinterpret_cast<const char *>(MUTR->getUntypedExtraOutputValue(I));
3116d11baf0SMircea Trofin       L->logTensorValue(CurrentFeature, RawData);
31236bb1fb1SMircea Trofin       ++CurrentFeature;
31362fc44caSMircea Trofin     }
31436bb1fb1SMircea Trofin 
31536bb1fb1SMircea Trofin   assert(CurrentFeature == DefaultDecisionPos);
3166d11baf0SMircea Trofin   L->logTensorValue(DefaultDecisionPos,
3176d11baf0SMircea Trofin                     reinterpret_cast<const char *>(&Event.DefaultDecision));
3186d11baf0SMircea Trofin   L->logTensorValue(DecisionPos,
3196d11baf0SMircea Trofin                     reinterpret_cast<const char *>(&Event.AdvisedDecision));
3206d11baf0SMircea Trofin   L->endObservation();
32136bb1fb1SMircea Trofin   if (InlineSizeEstimatorAnalysis::isEvaluatorRequested())
3226d11baf0SMircea Trofin     L->logReward(Event.Reward);
32336bb1fb1SMircea Trofin 
32436bb1fb1SMircea Trofin   // For debugging / later use
32536bb1fb1SMircea Trofin   Effects.push_back(Event.Effect);
32665b6dbf9SMircea Trofin }
32765b6dbf9SMircea Trofin 
32870f8d0acSMircea Trofin DevelopmentModeMLInlineAdvisor::DevelopmentModeMLInlineAdvisor(
32970f8d0acSMircea Trofin     Module &M, ModuleAnalysisManager &MAM,
33070f8d0acSMircea Trofin     std::unique_ptr<MLModelRunner> ModelRunner,
331a120fdd3SMircea Trofin     std::function<bool(CallBase &)> GetDefaultAdvice,
332d5c81be3SMircea Trofin     std::unique_ptr<TrainingLogger> Logger)
333ab2e7666SMircea Trofin     : MLInlineAdvisor(M, MAM, std::move(ModelRunner), GetDefaultAdvice),
334a120fdd3SMircea Trofin       IsDoingInference(isa<ModelUnderTrainingRunner>(getModelRunner())),
335d5c81be3SMircea Trofin       Logger(std::move(Logger)),
33670f8d0acSMircea Trofin       InitialNativeSize(isLogging() ? getTotalSizeEstimate() : 0),
33770f8d0acSMircea Trofin       CurrentNativeSize(InitialNativeSize) {
33870f8d0acSMircea Trofin   // We cannot have the case of neither inference nor logging.
33970f8d0acSMircea Trofin   assert(IsDoingInference || isLogging());
34070f8d0acSMircea Trofin }
34170f8d0acSMircea Trofin 
342d4b6fcb3SFangrui Song std::optional<size_t>
34370f8d0acSMircea Trofin DevelopmentModeMLInlineAdvisor::getNativeSizeEstimate(const Function &F) const {
3448c63df24SMircea Trofin   if (!InlineSizeEstimatorAnalysis::isEvaluatorRequested())
3459c444f70SKazu Hirata     return std::nullopt;
34670f8d0acSMircea Trofin   auto &R =
34770f8d0acSMircea Trofin       FAM.getResult<InlineSizeEstimatorAnalysis>(const_cast<Function &>(F));
34870f8d0acSMircea Trofin   if (!R) {
34970f8d0acSMircea Trofin     F.getParent()->getContext().emitError(
35070f8d0acSMircea Trofin         "Native size estimator is not present.");
35170f8d0acSMircea Trofin     return 0;
35270f8d0acSMircea Trofin   }
35370f8d0acSMircea Trofin   return *R;
35470f8d0acSMircea Trofin }
35570f8d0acSMircea Trofin 
35670f8d0acSMircea Trofin std::unique_ptr<MLInlineAdvice>
357e8049dc3SMircea Trofin DevelopmentModeMLInlineAdvisor::getMandatoryAdviceImpl(CallBase &CB) {
35870f8d0acSMircea Trofin   return std::make_unique<LoggingMLInlineAdvice>(
35970f8d0acSMircea Trofin       /*Advisor=*/this,
360e8049dc3SMircea Trofin       /*CB=*/CB, /*ORE=*/getCallerORE(CB), /*Recommendation=*/true,
361e8049dc3SMircea Trofin       /*Logger=*/*Logger,
36270f8d0acSMircea Trofin       /*CallerSizeEstimateBefore=*/getNativeSizeEstimate(*CB.getCaller()),
36370f8d0acSMircea Trofin       /*CalleeSizeEstimateBefore=*/
36470f8d0acSMircea Trofin       getNativeSizeEstimate(*CB.getCalledFunction()),
36587fb7aa1SMircea Trofin       /*DefaultDecision=*/true, /*Mandatory*/ true);
36670f8d0acSMircea Trofin }
36770f8d0acSMircea Trofin 
36870f8d0acSMircea Trofin std::unique_ptr<MLInlineAdvice>
36970f8d0acSMircea Trofin DevelopmentModeMLInlineAdvisor::getAdviceFromModel(
37070f8d0acSMircea Trofin     CallBase &CB, OptimizationRemarkEmitter &ORE) {
37170f8d0acSMircea Trofin   if (IsDoingInference && !isLogging())
37270f8d0acSMircea Trofin     return MLInlineAdvisor::getAdviceFromModel(CB, ORE);
37370f8d0acSMircea Trofin 
37470f8d0acSMircea Trofin   bool DefaultAdvice = GetDefaultAdvice(CB);
375059e0347SMircea Trofin   auto Recommendation =
376059e0347SMircea Trofin       IsDoingInference ? static_cast<bool>(ModelRunner->evaluate<int64_t>())
377059e0347SMircea Trofin                        : DefaultAdvice;
37870f8d0acSMircea Trofin   return std::make_unique<LoggingMLInlineAdvice>(
37970f8d0acSMircea Trofin       /*Advisor=*/this,
38070f8d0acSMircea Trofin       /*CB=*/CB, /*ORE=*/ORE, /*Recommendation=*/Recommendation,
381d5c81be3SMircea Trofin       /*Logger=*/*Logger,
38270f8d0acSMircea Trofin       /*CallerSizeEstimateBefore=*/getNativeSizeEstimate(*CB.getCaller()),
38370f8d0acSMircea Trofin       /*CalleeSizeEstimateBefore=*/
38470f8d0acSMircea Trofin       getNativeSizeEstimate(*CB.getCalledFunction()),
38570f8d0acSMircea Trofin       /*DefaultDecision=*/DefaultAdvice);
38670f8d0acSMircea Trofin }
38770f8d0acSMircea Trofin 
38870f8d0acSMircea Trofin size_t DevelopmentModeMLInlineAdvisor::getTotalSizeEstimate() {
3898c63df24SMircea Trofin   if (!InlineSizeEstimatorAnalysis::isEvaluatorRequested())
3908c63df24SMircea Trofin     return 0;
39170f8d0acSMircea Trofin   size_t Ret = 0;
39270f8d0acSMircea Trofin   for (auto &F : M) {
39370f8d0acSMircea Trofin     if (F.isDeclaration())
39470f8d0acSMircea Trofin       continue;
3958c63df24SMircea Trofin     Ret += *getNativeSizeEstimate(F);
39670f8d0acSMircea Trofin   }
39770f8d0acSMircea Trofin   return Ret;
39870f8d0acSMircea Trofin }
39970f8d0acSMircea Trofin 
40070f8d0acSMircea Trofin std::unique_ptr<InlineAdvisor> llvm::getDevelopmentModeAdvisor(
40170f8d0acSMircea Trofin     Module &M, ModuleAnalysisManager &MAM,
40270f8d0acSMircea Trofin     std::function<bool(CallBase &)> GetDefaultAdvice) {
40370f8d0acSMircea Trofin   auto &Ctx = M.getContext();
40470f8d0acSMircea Trofin   std::unique_ptr<MLModelRunner> Runner;
40570f8d0acSMircea Trofin   if (TFModelUnderTrainingPath.empty())
40604f2712eSMircea Trofin     Runner.reset(new NoInferenceModelRunner(Ctx, getInputFeatures()));
407a120fdd3SMircea Trofin   else
408a120fdd3SMircea Trofin     Runner = ModelUnderTrainingRunner::createAndEnsureValid(
409a120fdd3SMircea Trofin         Ctx, TFModelUnderTrainingPath, DecisionName, getInputFeatures(),
410a120fdd3SMircea Trofin         TFOutputSpecOverride);
411a120fdd3SMircea Trofin   if (!Runner)
41270f8d0acSMircea Trofin     return nullptr;
413d5c81be3SMircea Trofin   std::unique_ptr<TrainingLogger> Logger;
414d5c81be3SMircea Trofin   if (!TrainingLog.empty())
415a120fdd3SMircea Trofin     Logger = std::make_unique<TrainingLogger>(
416a120fdd3SMircea Trofin         TrainingLog, dyn_cast<ModelUnderTrainingRunner>(Runner.get()));
417d5c81be3SMircea Trofin 
41870f8d0acSMircea Trofin   return std::make_unique<DevelopmentModeMLInlineAdvisor>(
419a120fdd3SMircea Trofin       M, MAM, std::move(Runner), GetDefaultAdvice, std::move(Logger));
42070f8d0acSMircea Trofin }
421edc83a15SKazu Hirata #endif // defined(LLVM_HAVE_TFLITE)
422