source: icGREP/icgrep-devel/icgrep/kernels/object_cache.cpp @ 5402

Last change on this file since 5402 was 5402, checked in by nmedfort, 2 years ago

Moved toolchain and object_cache to kernels directory. Continued work on providing input consumed information.

File size: 5.2 KB
Line 
1#include "object_cache.h"
2#include <llvm/Support/raw_ostream.h>
3#include <llvm/Support/FileSystem.h>
4#include <llvm/Support/Path.h>
5#include <llvm/IR/Module.h>
6#include <string>
7
8using namespace llvm;
9
10//===----------------------------------------------------------------------===//
11// Object cache (based on tools/lli/lli.cpp, LLVM 3.6.1)
12//
13// This object cache implementation writes cached objects to disk to the
14// directory specified by CacheDir, using a filename provided in the module
15// descriptor. The cache tries to load a saved object using that path if the
16// file exists.
17//
18ParabixObjectCache::ParabixObjectCache(const std::string &dir): CacheDir(dir) {}
19
20ParabixObjectCache::ParabixObjectCache() {
21    // $HOME/.cache/icgrep
22    // TODO use path::user_cache_directory once we have llvm >= 3.7.
23    sys::path::home_directory(CacheDir);
24    std::string Version = PARABIX_VERSION;
25    std::string Date = __DATE__;
26    std::string Time = __TIME__;
27    std::string DateStamp = Date.substr(7) + Date.substr(0,3) + (Date[4] == ' ' ? Date.substr(5,1) : Date.substr(4,2));
28    std::string CacheSubDir = "Parabix" + Version + "_" + DateStamp + "@" + Time;
29    sys::path::append(CacheDir, ".cache", CacheSubDir);
30}
31
32ParabixObjectCache::~ParabixObjectCache() {}
33
34// A new module has been compiled.   If it is cacheable and no conflicting module
35// exists, write it out. 
36void ParabixObjectCache::notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) {
37    const std::string &ModuleID = M->getModuleIdentifier();
38    auto f = cachedObjectMap.find(ModuleID);
39    if (f!= cachedObjectMap.end()) return;
40    Path CacheName(CacheDir);
41    if (!getCacheFilename(ModuleID, CacheName)) return;
42    if (!CacheDir.empty())      // Re-creating an existing directory is fine.
43        sys::fs::create_directories(Twine(CacheDir));
44    std::error_code EC;
45    raw_fd_ostream outfile(CacheName, EC, sys::fs::F_None);
46    outfile.write(Obj.getBufferStart(), Obj.getBufferSize());
47    outfile.close();
48    auto s = kernelSignatureMap.find(ModuleID);  // Check for a kernel signature.
49    if (s != kernelSignatureMap.end()) { 
50        if (s->second == ModuleID) return;  // No signature is written when the signature is the ModuleID.
51        sys::path::replace_extension(CacheName, ".sig");
52        raw_fd_ostream sigfile(CacheName, EC, sys::fs::F_None);
53        sigfile << s->second;
54        sigfile.close();
55    }
56}
57
58bool ParabixObjectCache::loadCachedObjectFile(std::string ModuleID, std::string signature) {
59    // Have we already seen this module before.
60    auto s = kernelSignatureMap.find(ModuleID);
61    if (s!= kernelSignatureMap.end()) {
62        if (s->second != signature) {
63
64
65#ifdef OBJECT_CACHE_DEBUG
66            std::cerr << "loadCachedObjectFile:  conflicting signatures for the same moduleID! " << ModuleID << std::endl;
67#endif
68            return false;
69        }
70        // A cached entry exists if it has already been loaded.
71        return cachedObjectMap.count(ModuleID) != 0;
72    }
73    // Confirm that the module is cacheable.
74    Path CachedObjectName(CacheDir);
75    if (!getCacheFilename(ModuleID, CachedObjectName)) {
76        return false;
77    }
78    //
79    // Save the signature.
80    kernelSignatureMap.emplace(ModuleID, signature);
81    //
82    // Now checkfor a cache file.
83    ErrorOr<std::unique_ptr<MemoryBuffer>> KernelObjectBuffer = MemoryBuffer::getFile(CachedObjectName.c_str(), -1, false);
84    if (!KernelObjectBuffer) return false;
85    //
86    if (ModuleID != signature) {
87        // Confirm the signature.
88        sys::path::replace_extension(CachedObjectName, ".sig");
89        ErrorOr<std::unique_ptr<MemoryBuffer>> SignatureBuffer = MemoryBuffer::getFile(CachedObjectName.c_str(), -1, false);
90        if (!SignatureBuffer) {
91            report_fatal_error("signature file expected but not found: " + ModuleID);
92            return false;
93        }
94        StringRef loadedSig = SignatureBuffer.get()->getBuffer(); 
95        if (!loadedSig.equals(signature)) {
96            report_fatal_error("computed signature does not match stored signature: " + ModuleID);
97        }
98    }
99    // Make a copy so that the JIT engine can freely modify it.
100    cachedObjectMap.emplace(ModuleID, std::move(KernelObjectBuffer.get()));
101    return true;
102}
103
104/*  May need this.
105 
106void ParabixObjectCache::removeCacheFile(std::string ModuleID) {
107    Path CacheName(CacheDir);
108    if (!getCacheFilename(ModuleID, CacheName)) return;
109    sys::fs::remove(CacheName);
110    // Also remove a signature file, if present.
111    sys::path::replace_extension(CacheName, ".sig");
112    sys::fs::remove(CacheName);
113}
114*/
115
116std::unique_ptr<MemoryBuffer> ParabixObjectCache::getObject(const Module* M) {
117    const std::string &ModuleID = M->getModuleIdentifier();
118    auto f = cachedObjectMap.find(ModuleID);
119    if (f == cachedObjectMap.end()) {
120        return nullptr;
121    }
122    // Return a copy of the buffer, for MCJIT to modify, if necessary.
123    return MemoryBuffer::getMemBufferCopy(f->second.get()->getBuffer());
124}
125
126bool ParabixObjectCache::getCacheFilename(const std::string &ModID, Path &CacheName) {
127    const std::string Prefix("Parabix:");
128    size_t PrefixLength = Prefix.length();
129    if (ModID.substr(0, PrefixLength) != Prefix)
130        return false;
131    CacheName = CacheDir;
132    sys::path::append(CacheName, ModID.substr(PrefixLength) + ".o");
133    return true;
134}
Note: See TracBrowser for help on using the repository browser.