|  | //===- InteractiveModelRunner.cpp - noop ML model runner   ----------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // A runner that communicates with an external agent via 2 file descriptors. | 
|  | //===----------------------------------------------------------------------===// | 
|  | #include "llvm/Analysis/InteractiveModelRunner.h" | 
|  | #include "llvm/Analysis/MLModelRunner.h" | 
|  | #include "llvm/Analysis/TensorSpec.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/FileSystem.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | static cl::opt<bool> DebugReply( | 
|  | "interactive-model-runner-echo-reply", cl::init(false), cl::Hidden, | 
|  | cl::desc("The InteractiveModelRunner will echo back to stderr " | 
|  | "the data received from the host (for debugging purposes).")); | 
|  |  | 
|  | InteractiveModelRunner::InteractiveModelRunner( | 
|  | LLVMContext &Ctx, const std::vector<TensorSpec> &Inputs, | 
|  | const TensorSpec &Advice, StringRef OutboundName, StringRef InboundName) | 
|  | : MLModelRunner(Ctx, MLModelRunner::Kind::Interactive, Inputs.size()), | 
|  | InputSpecs(Inputs), OutputSpec(Advice), | 
|  | InEC(sys::fs::openFileForRead(InboundName, Inbound)), | 
|  | OutputBuffer(OutputSpec.getTotalTensorBufferSize()) { | 
|  | if (InEC) { | 
|  | Ctx.emitError("Cannot open inbound file: " + InEC.message()); | 
|  | return; | 
|  | } | 
|  | { | 
|  | auto OutStream = std::make_unique<raw_fd_ostream>(OutboundName, OutEC); | 
|  | if (OutEC) { | 
|  | Ctx.emitError("Cannot open outbound file: " + OutEC.message()); | 
|  | return; | 
|  | } | 
|  | Log = std::make_unique<Logger>(std::move(OutStream), InputSpecs, Advice, | 
|  | /*IncludeReward=*/false, Advice); | 
|  | } | 
|  | // Just like in the no inference case, this will allocate an appropriately | 
|  | // sized buffer. | 
|  | for (size_t I = 0; I < InputSpecs.size(); ++I) | 
|  | setUpBufferForTensor(I, InputSpecs[I], nullptr); | 
|  | Log->flush(); | 
|  | } | 
|  |  | 
|  | InteractiveModelRunner::~InteractiveModelRunner() { | 
|  | sys::fs::file_t FDAsOSHandle = sys::fs::convertFDToNativeFile(Inbound); | 
|  | sys::fs::closeFile(FDAsOSHandle); | 
|  | } | 
|  |  | 
|  | void *InteractiveModelRunner::evaluateUntyped() { | 
|  | Log->startObservation(); | 
|  | for (size_t I = 0; I < InputSpecs.size(); ++I) | 
|  | Log->logTensorValue(I, reinterpret_cast<const char *>(getTensorUntyped(I))); | 
|  | Log->endObservation(); | 
|  | Log->flush(); | 
|  |  | 
|  | size_t InsPoint = 0; | 
|  | char *Buff = OutputBuffer.data(); | 
|  | const size_t Limit = OutputBuffer.size(); | 
|  | while (InsPoint < Limit) { | 
|  | auto ReadOrErr = ::sys::fs::readNativeFile( | 
|  | sys::fs::convertFDToNativeFile(Inbound), | 
|  | {Buff + InsPoint, OutputBuffer.size() - InsPoint}); | 
|  | if (ReadOrErr.takeError()) { | 
|  | Ctx.emitError("Failed reading from inbound file"); | 
|  | break; | 
|  | } | 
|  | InsPoint += *ReadOrErr; | 
|  | } | 
|  | if (DebugReply) | 
|  | dbgs() << OutputSpec.name() << ": " | 
|  | << tensorValueToString(OutputBuffer.data(), OutputSpec) << "\n"; | 
|  | return OutputBuffer.data(); | 
|  | } |