source: icGREP/icgrep-devel/icgrep/toolchain/object_cache.cpp @ 5456

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

Large refactoring step. Removed IR generation code from Kernel (formally KernelBuilder?) and moved it into the new KernelBuilder? class.

File size: 6.3 KB
Line 
1#include "object_cache.h"
2#include <kernels/kernel.h>
3#include <llvm/Support/raw_ostream.h>
4#include <llvm/Support/MemoryBuffer.h>
5#include <llvm/Support/FileSystem.h>
6#include <llvm/Support/Path.h>
7#include <llvm/IR/Module.h>
8#include <sys/file.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <boost/filesystem.hpp>
12#include <ctime>
13
14using namespace llvm;
15
16//===----------------------------------------------------------------------===//
17// Object cache (based on tools/lli/lli.cpp, LLVM 3.6.1)
18//
19// This object cache implementation writes cached objects to disk to the
20// directory specified by CacheDir, using a filename provided in the module
21// descriptor. The cache tries to load a saved object using that path if the
22// file exists.
23//
24
25#define MONTH_1 \
26    ((__DATE__ [0] == 'O' || __DATE__ [0] == 'N' || __DATE__ [0] == 'D') ? '1' : '0')
27#define MONTH_2 \
28    (__DATE__ [2] == 'n' ? (__DATE__ [1] == 'a' ? '1' : '6') \
29    : __DATE__ [2] == 'b' ? '2' \
30    : __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? '3' : '4') \
31    : __DATE__ [2] == 'y' ? '5' \
32    : __DATE__ [2] == 'l' ? '7' \
33    : __DATE__ [2] == 'g' ? '8' \
34    : __DATE__ [2] == 'p' ? '9' \
35    : __DATE__ [2] == 't' ? '0' \
36    : __DATE__ [2] == 'v' ? '1' : '2')
37#define DAY_1 (__DATE__[4] == ' ' ? '0' : __DATE__[4])
38#define DAY_2 (__DATE__[5])
39#define YEAR_1 (__DATE__[9])
40#define YEAR_2 (__DATE__[10])
41#define HOUR_1 (__TIME__[0])
42#define HOUR_2 (__TIME__[1])
43#define MINUTE_1 (__TIME__[3])
44#define MINUTE_2 (__TIME__[4])
45#define SECOND_1 (__TIME__[6])
46#define SECOND_2 (__TIME__[7])
47
48const static auto CACHE_PREFIX = PARABIX_VERSION +
49                          std::string{'@',
50                          MONTH_1, MONTH_2, DAY_1, DAY_2, YEAR_1, YEAR_2,
51                          HOUR_1, HOUR_2, MINUTE_1, MINUTE_2, SECOND_1, SECOND_2,
52                          '_'};
53
54bool ParabixObjectCache::loadCachedObjectFile(const std::unique_ptr<kernel::KernelBuilder> & idb, kernel::Kernel * const kernel) {
55    if (LLVM_LIKELY(kernel->isCachable())) {
56
57        Module * const module = kernel->getModule();
58        assert ("kernel module cannot be null!" && module);
59        const auto moduleId = module->getModuleIdentifier();
60
61        // Have we already seen this module before?
62        if (LLVM_UNLIKELY(mCachedObjectMap.count(moduleId) != 0)) {
63            const auto f = mKernelSignatureMap.find(moduleId);
64            if (f == mKernelSignatureMap.end()) {
65                return kernel->moduleIDisSignature();
66            } else if (kernel->moduleIDisSignature() || (kernel->makeSignature(idb) != f->second)) {
67                return false;
68            }
69            return true;
70        }
71
72        // No, check for an existing cache file.
73        Path objectName(mCachePath);
74        sys::path::append(objectName, CACHE_PREFIX);
75        objectName.append(moduleId);
76        objectName.append(".o");
77
78        auto objectBuffer = MemoryBuffer::getFile(objectName.c_str(), -1, false);
79        if (objectBuffer) {
80            if (!kernel->moduleIDisSignature()) {
81                sys::path::replace_extension(objectName, ".sig");
82                const auto signatureBuffer = MemoryBuffer::getFile(objectName.c_str(), -1, false);
83                if (signatureBuffer) {
84                    const StringRef loadedSig = signatureBuffer.get()->getBuffer();
85                    if (!loadedSig.equals(kernel->makeSignature(idb))) {
86                        return false;
87                    }
88                } else {
89                    report_fatal_error("signature file expected but not found: " + moduleId);
90                    return false;
91                }
92            }
93            // updae the modified time of the file then add it to our cache
94            boost::filesystem::last_write_time(objectName.c_str(), time(0));
95            mCachedObjectMap.emplace(moduleId, std::move(objectBuffer.get()));
96            return true;
97        } else if (!kernel->moduleIDisSignature()) {
98            mKernelSignatureMap.emplace(moduleId, kernel->makeSignature(idb));
99        }
100    }
101    return false;
102}
103
104// A new module has been compiled. If it is cacheable and no conflicting module
105// exists, write it out.
106void ParabixObjectCache::notifyObjectCompiled(const Module * M, MemoryBufferRef Obj) {
107    const auto moduleId = M->getModuleIdentifier();
108    if (mCachedObjectMap.count(moduleId) == 0) {
109
110        Path objectName(mCachePath);
111        sys::path::append(objectName, CACHE_PREFIX);
112        objectName.append(moduleId);
113        objectName.append(".o");
114
115        if (LLVM_LIKELY(!mCachePath.empty())) {
116            sys::fs::create_directories(Twine(mCachePath));
117        }
118
119        std::error_code EC;
120        raw_fd_ostream outfile(objectName, EC, sys::fs::F_None);
121        outfile.write(Obj.getBufferStart(), Obj.getBufferSize());
122        outfile.close();
123
124        // If this kernel has a signature, write it.
125        const auto sig = mKernelSignatureMap.find(moduleId);
126        if (LLVM_UNLIKELY(sig != mKernelSignatureMap.end())) {
127            sys::path::replace_extension(objectName, ".sig");
128            raw_fd_ostream sigfile(objectName, EC, sys::fs::F_None);
129            sigfile << sig->second;
130            sigfile.close();
131        }
132    }
133}
134
135/*  May need this.
136
137void ParabixObjectCache::removeCacheFile(std::string ModuleID) {
138    Path CacheName(CacheDir);
139    if (!getCacheFilename(ModuleID, CacheName)) return;
140    sys::fs::remove(CacheName);
141    // Also remove a signature file, if present.
142    sys::path::replace_extension(CacheName, ".sig");
143    sys::fs::remove(CacheName);
144}
145*/
146
147std::unique_ptr<MemoryBuffer> ParabixObjectCache::getObject(const Module* M) {
148    auto f = mCachedObjectMap.find(M->getModuleIdentifier());
149    if (f == mCachedObjectMap.end()) {
150        return nullptr;
151    }
152    // Return a copy of the buffer, for MCJIT to modify, if necessary.
153    return MemoryBuffer::getMemBufferCopy(f->second.get()->getBuffer());
154}
155
156inline ParabixObjectCache::Path ParabixObjectCache::getDefaultPath() {
157    // $HOME/.cache/parabix/
158    Path cachePath;
159    // TODO use path::user_cache_directory once we have llvm >= 3.7.
160    sys::path::home_directory(cachePath);
161    sys::path::append(cachePath, ".cache", "parabix");
162    return cachePath;
163}
164
165ParabixObjectCache::ParabixObjectCache()
166: mCachePath(std::move(getDefaultPath())) {
167
168}
169
170ParabixObjectCache::ParabixObjectCache(const std::string & dir)
171: mCachePath(dir) {
172
173}
Note: See TracBrowser for help on using the repository browser.