[offload] Add the ability to record and replay IR bitcode modules (#207278)
This PR allows the user to use JIT with kernel record & replay by expanding the latter to also work with IR bitcode images. - Add a new field to `DeviceImageTy` for storing the IR image. - Expand `RecordReplayTy::FileTy` to also include IR bitcode and associate it with the file extension `.bc` - Add the `--load-bitcode` command line option to `llvm-omp-kernel-replay` tool. --------- Co-authored-by: Giorgi Gvalia <gvalia1@llnl.gov>
This commit is contained in:
parent
1529d35adb
commit
16b8129cd7
6 changed files with 91 additions and 5 deletions
|
|
@ -375,6 +375,9 @@ class DeviceImageTy {
|
||||||
/// The managed image data.
|
/// The managed image data.
|
||||||
std::unique_ptr<MemoryBuffer> Image;
|
std::unique_ptr<MemoryBuffer> Image;
|
||||||
|
|
||||||
|
/// An optional buffer for an IR image.
|
||||||
|
std::unique_ptr<MemoryBuffer> DeviceIRImage;
|
||||||
|
|
||||||
/// Reference to the device this image is loaded on.
|
/// Reference to the device this image is loaded on.
|
||||||
GenericDeviceTy &Device;
|
GenericDeviceTy &Device;
|
||||||
|
|
||||||
|
|
@ -402,6 +405,21 @@ public:
|
||||||
return MemoryBufferRef(StringRef((const char *)getStart(), getSize()),
|
return MemoryBufferRef(StringRef((const char *)getStart(), getSize()),
|
||||||
"Image");
|
"Image");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a memory buffer reference to the whole IR image.
|
||||||
|
MemoryBufferRef getIRImageMemoryBuffer() const {
|
||||||
|
if (DeviceIRImage)
|
||||||
|
return MemoryBufferRef(*DeviceIRImage);
|
||||||
|
|
||||||
|
return MemoryBufferRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasIRImage() const { return DeviceIRImage != nullptr; }
|
||||||
|
|
||||||
|
/// Set the IR image.
|
||||||
|
void setIRImage(std::unique_ptr<MemoryBuffer> ImageBuffer) {
|
||||||
|
DeviceIRImage = std::move(ImageBuffer);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Class implementing common functionalities of offload kernels. Each plugin
|
/// Class implementing common functionalities of offload kernels. Each plugin
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,8 @@ public:
|
||||||
EpilogueSnapshot,
|
EpilogueSnapshot,
|
||||||
Descriptor,
|
Descriptor,
|
||||||
Globals,
|
Globals,
|
||||||
Program
|
Program,
|
||||||
|
IRImage
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HandleTy {
|
struct HandleTy {
|
||||||
|
|
@ -296,7 +297,8 @@ private:
|
||||||
Error recordGlobals(StringRef Filename);
|
Error recordGlobals(StringRef Filename);
|
||||||
|
|
||||||
/// Record the device image to a file.
|
/// Record the device image to a file.
|
||||||
Error recordImage(const GenericKernelTy &Kernel, StringRef Filename);
|
Error recordImage(const GenericKernelTy &Kernel, StringRef Filename,
|
||||||
|
StringRef IRImageFilename);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace plugin
|
} // namespace plugin
|
||||||
|
|
|
||||||
|
|
@ -695,6 +695,9 @@ Expected<DeviceImageTy *> GenericDeviceTy::loadBinary(GenericPluginTy &Plugin,
|
||||||
return ImageOrErr.takeError();
|
return ImageOrErr.takeError();
|
||||||
DeviceImageTy *Image = *ImageOrErr;
|
DeviceImageTy *Image = *ImageOrErr;
|
||||||
|
|
||||||
|
if (identify_magic(InputTgtImage) == file_magic::bitcode)
|
||||||
|
Image->setIRImage(MemoryBuffer::getMemBufferCopy(InputTgtImage));
|
||||||
|
|
||||||
// Add the image to list.
|
// Add the image to list.
|
||||||
LoadedImages.push_back(Image);
|
LoadedImages.push_back(Image);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,9 @@ Error NativeRecordReplayTy::recordPrologueImpl(
|
||||||
return Err;
|
return Err;
|
||||||
|
|
||||||
SmallString<128> ImageFilename = getFilename(Instance, FileTy::Program);
|
SmallString<128> ImageFilename = getFilename(Instance, FileTy::Program);
|
||||||
return recordImage(Kernel, ImageFilename.c_str());
|
|
||||||
|
SmallString<128> IRImageFilename = getFilename(Instance, FileTy::IRImage);
|
||||||
|
return recordImage(Kernel, ImageFilename.c_str(), IRImageFilename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Error NativeRecordReplayTy::recordEpilogueImpl(const GenericKernelTy &Kernel,
|
Error NativeRecordReplayTy::recordEpilogueImpl(const GenericKernelTy &Kernel,
|
||||||
|
|
@ -323,6 +325,8 @@ StringRef NativeRecordReplayTy::getExtension(FileTy FileType) {
|
||||||
return "globals";
|
return "globals";
|
||||||
case FileTy::Program:
|
case FileTy::Program:
|
||||||
return "image";
|
return "image";
|
||||||
|
case FileTy::IRImage:
|
||||||
|
return "bc";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -367,13 +371,23 @@ Error NativeRecordReplayTy::recordSnapshot(StringRef Filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Error NativeRecordReplayTy::recordImage(const GenericKernelTy &Kernel,
|
Error NativeRecordReplayTy::recordImage(const GenericKernelTy &Kernel,
|
||||||
StringRef Filename) {
|
StringRef Filename,
|
||||||
|
StringRef IRImageFilename) {
|
||||||
std::error_code EC;
|
std::error_code EC;
|
||||||
raw_fd_ostream OS(Filename, EC);
|
raw_fd_ostream OS(Filename, EC);
|
||||||
if (EC)
|
if (EC)
|
||||||
return Plugin::error(ErrorCode::HOST_IO, "saving image file");
|
return Plugin::error(ErrorCode::HOST_IO, "saving image file");
|
||||||
OS << Kernel.getImage().getMemoryBuffer().getBuffer();
|
OS << Kernel.getImage().getMemoryBuffer().getBuffer();
|
||||||
OS.close();
|
OS.close();
|
||||||
|
|
||||||
|
if (!IRImageFilename.empty() && Kernel.getImage().hasIRImage()) {
|
||||||
|
raw_fd_ostream IROS(IRImageFilename, EC);
|
||||||
|
if (EC)
|
||||||
|
return Plugin::error(ErrorCode::HOST_IO, "saving IR image file");
|
||||||
|
IROS << Kernel.getImage().getIRImageMemoryBuffer().getBuffer();
|
||||||
|
IROS.close();
|
||||||
|
}
|
||||||
|
|
||||||
return Plugin::success();
|
return Plugin::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// clang-format off
|
||||||
|
// RUN: %libomptarget-compilexx-generic -fopenmp-target-jit
|
||||||
|
// RUN: rm -rf %t.testdir
|
||||||
|
// RUN: mkdir -p %t.testdir
|
||||||
|
// RUN: env LIBOMPTARGET_RECORD=1 LIBOMPTARGET_RECORD_MEMSIZE=536870912 LIBOMPTARGET_RECORD_DIR=%t.testdir %libomptarget-run-generic 2>&1 | %fcheck-generic
|
||||||
|
// RUN: ls -t %t.testdir/*.bc | grep .
|
||||||
|
// RUN: ls -t %t.testdir/*.json | sed -n '1p' | grep . | xargs %omp-kernel-replay --load-bitcode --verify
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// REQUIRES: gpu
|
||||||
|
|
||||||
|
// UNSUPPORTED: aarch64-unknown-linux-gnu
|
||||||
|
// UNSUPPORTED: x86_64-unknown-linux-gnu
|
||||||
|
// UNSUPPORTED: s390x-ibm-linux-gnu
|
||||||
|
// UNSUPPORTED: intelgpu
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
size_t Size = 1000;
|
||||||
|
uint64_t *Data = new uint64_t[Size];
|
||||||
|
|
||||||
|
for (size_t I = 0; I < Size; ++I) {
|
||||||
|
Data[I] = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma omp target teams distribute parallel for num_teams(256) \
|
||||||
|
thread_limit(128) map(tofrom : Data[0 : Size])
|
||||||
|
for (size_t I = 0; I < Size; ++I) {
|
||||||
|
Data[I] = 10 + (uint64_t)I;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Sum = 0;
|
||||||
|
for (size_t I = 0; I < Size; ++I) {
|
||||||
|
Sum += Data[I];
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: PASS
|
||||||
|
if (Sum == 509500)
|
||||||
|
printf("PASS\n");
|
||||||
|
|
||||||
|
delete[] Data;
|
||||||
|
}
|
||||||
|
|
@ -68,6 +68,11 @@ static cl::opt<bool>
|
||||||
cl::desc("Ignore thread and team limits (unrecommended)."),
|
cl::desc("Ignore thread and team limits (unrecommended)."),
|
||||||
cl::init(false), cl::cat(ReplayOptions));
|
cl::init(false), cl::cat(ReplayOptions));
|
||||||
|
|
||||||
|
static cl::opt<bool>
|
||||||
|
LoadBitcodeOpt("load-bitcode",
|
||||||
|
cl::desc("Load the recorded IR bitcode image file."),
|
||||||
|
cl::init(false), cl::cat(ReplayOptions));
|
||||||
|
|
||||||
template <typename... ArgsTy>
|
template <typename... ArgsTy>
|
||||||
Error createErr(const char *ErrFmt, ArgsTy &&...Args) {
|
Error createErr(const char *ErrFmt, ArgsTy &&...Args) {
|
||||||
return llvm::createStringError(llvm::inconvertibleErrorCode(), ErrFmt,
|
return llvm::createStringError(llvm::inconvertibleErrorCode(), ErrFmt,
|
||||||
|
|
@ -300,7 +305,7 @@ Error replayKernel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the device image file.
|
// Load the device image file.
|
||||||
Filepath.replace_extension("image");
|
Filepath.replace_extension(LoadBitcodeOpt ? "bc" : "image");
|
||||||
auto ImageBufferOrErr =
|
auto ImageBufferOrErr =
|
||||||
MemoryBuffer::getFile(Filepath.c_str(), /*isText=*/false,
|
MemoryBuffer::getFile(Filepath.c_str(), /*isText=*/false,
|
||||||
/*RequiresNullTerminator=*/false);
|
/*RequiresNullTerminator=*/false);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue