| //===- 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(); | |
| } |