[GPU] integrate persistent caching for onednn (#12094)

* integrate persistant caching for onednn
* add api to save/load binary file.
This commit is contained in:
Sungeun Kim authored and GitHub committed 2022-07-18 20:13:46 +09:00
1 parent 4e379d63eb
commit 3bd475ad26
4 files changed
+126 -86

No files matched your search

@@ -239,5 +239,18 @@ inline std::basic_string<C> make_plugin_library_name(const std::basic_string<C>&
FileTraits<C>::library_ext();
}
/**
* @brief load binary data from file
* @param path - binary file path to load
* @return binary vector
*/
std::vector<uint8_t> load_binary(const std::string& path);
/**
* @brief save binary data to file
* @param path - binary file path to store
*/
void save_binary(const std::string& path, std::vector<uint8_t> binary);
} // namespace util
} // namespace ov
+47
View File
@@ -370,3 +370,50 @@ std::wstring ov::util::get_ov_lib_path_w() {
}
#endif // OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
std::vector<uint8_t> ov::util::load_binary(const std::string& path) {
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
std::wstring widefilename = ov::util::string_to_wstring(path);
const wchar_t* filename = widefilename.c_str();
FILE* fp = _wfopen(filename, L"rb");
#else
const char* filename = path.c_str();
FILE* fp = fopen(filename, "rb");
#endif
if (fp) {
fseek(fp, 0, SEEK_END);
auto sz = ftell(fp);
if (sz < 0) {
fclose(fp);
return {};
}
auto nsize = static_cast<size_t>(sz);
fseek(fp, 0, SEEK_SET);
std::vector<uint8_t> ret(nsize);
auto res = fread(ret.data(), sizeof(uint8_t), nsize, fp);
(void)res;
fclose(fp);
return ret;
}
return {};
}
void ov::util::save_binary(const std::string& path, std::vector<uint8_t> binary) {
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
std::wstring widefilename = ov::util::string_to_wstring(path);
const wchar_t* filename = widefilename.c_str();
#else
const char* filename = path.c_str();
#endif
std::ofstream out_file(filename, std::ios::out | std::ios::binary);
if (out_file.is_open()) {
out_file.write(reinterpret_cast<const char*>(&binary[0]), binary.size());
} else {
throw std::runtime_error("Could not save binary to " + path);
}
}
@@ -10,6 +10,7 @@
#include "to_string_utils.h"
#include "register.hpp"
#include "utils.hpp"
#include "openvino/util/file_util.hpp"
#include "quantize_inst.h"
#include "reorder_inst.h"
@@ -26,6 +27,8 @@
namespace cldnn {
namespace onednn {
static std::mutex cacheAccessMutex;
template <class PType, class DescType, class PrimDescType = dnnl::primitive_desc, class PrimType = dnnl::primitive>
struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
const typed_program_node<PType>& _outer;
@@ -44,11 +47,64 @@ struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
_outer(arg),
_desc(desc),
_attrs(attrs),
_pd(pd),
_prim(pd) { }
_pd(pd) {
build_primitive();
}
bool is_cpu() const override { return false; }
private:
std::string get_cache_directory() const {
auto path = _outer.get_program().get_engine().configuration().kernels_cache_path;
if (path.empty()) {
return {};
}
if (path.back() != '/' && path.back() != '\\') {
path += "/";
}
return path;
}
std::string generate_cache_path_from_key(std::vector<uint8_t> key) const {
auto path = get_cache_directory();
if (path.empty()) {
return {};
}
std::string key_str(key.begin(), key.end());
size_t hash = std::hash<std::string>()(key_str);
return path + std::to_string(hash) + ".onednn.cl_cache";
}
void build_primitive() {
auto cache_outpath = get_cache_directory();
if (cache_outpath.empty()) {
_prim = PrimType(_pd);
} else {
std::vector<uint8_t> key = _pd.get_cache_blob_id();
assert(!key.empty());
std::vector<uint8_t> cache;
{
std::lock_guard<std::mutex> lock(cacheAccessMutex);
cache = ov::util::load_binary(generate_cache_path_from_key(key));
}
if (cache.empty()) {
_prim = PrimType(_pd);
cache = _prim.get_cache_blob();
{
std::lock_guard<std::mutex> lock(cacheAccessMutex);
ov::util::save_binary(generate_cache_path_from_key(key), cache);
}
} else {
_prim = PrimType(_pd, cache);
}
}
}
protected:
virtual bool optimized_out(typed_primitive_inst<PType>&) const { return false; }
@@ -6,6 +6,7 @@
#include "kernels_cache.hpp"
#include "ocl/ocl_engine.hpp"
#include "intel_gpu/runtime/debug_configuration.hpp"
#include "openvino/util/file_util.hpp"
#include <algorithm>
#include <cassert>
@@ -21,91 +22,9 @@
#include <malloc.h>
#endif
#ifndef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
# ifdef _WIN32
# if defined __INTEL_COMPILER || defined _MSC_VER
# define OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
# endif
# elif defined(__GNUC__) && (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 2)) || defined(__clang__)
# define OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
# endif
#endif
#ifndef _WIN32
#ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
#include <locale>
#include <codecvt>
#endif
#else
#include <Windows.h>
#endif
namespace {
std::mutex cacheAccessMutex;
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
std::wstring multiByteCharToWString(const char* str) {
#ifdef _WIN32
int strSize = static_cast<int>(std::strlen(str));
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, strSize, NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, str, strSize, &wstrTo[0], size_needed);
return wstrTo;
#else
std::wstring_convert<std::codecvt_utf8<wchar_t>> wstring_encoder;
std::wstring result = wstring_encoder.from_bytes(str);
return result;
#endif // _WIN32
}
#endif // defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
static std::vector<unsigned char> loadBinaryFromFile(std::string path) {
std::lock_guard<std::mutex> lock(cacheAccessMutex);
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
std::wstring widefilename = multiByteCharToWString(path.c_str());
const wchar_t* filename = widefilename.c_str();
FILE *fp = _wfopen(filename, L"rb");
#else
const char* filename = path.c_str();
FILE *fp = fopen(filename, "rb");
#endif
if (fp) {
fseek(fp, 0, SEEK_END);
auto sz = ftell(fp);
if (sz < 0) {
fclose(fp);
return {};
}
auto nsize = static_cast<size_t>(sz);
fseek(fp, 0, SEEK_SET);
std::vector<unsigned char> ret(nsize);
auto res = fread(ret.data(), sizeof(unsigned char), nsize, fp);
(void)res;
fclose(fp);
return ret;
}
return {};
}
static void saveBinaryToFile(std::string path, const std::vector<unsigned char> buffer) {
std::lock_guard<std::mutex> lock(cacheAccessMutex);
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
std::wstring widefilename = multiByteCharToWString(path.c_str());
const wchar_t* filename = widefilename.c_str();
#else
const char* filename = path.c_str();
#endif
std::ofstream out_file(filename, std::ios::out | std::ios::binary);
if (out_file.is_open()) {
out_file.write(reinterpret_cast<const char*>(&buffer[0]), buffer.size());
}
}
std::string reorder_options(const std::string& org_options) {
std::stringstream ss(org_options);
std::set<std::string> sorted_options;
@@ -298,7 +217,11 @@ void kernels_cache::build_batch(const engine& build_engine, const batch_program&
if (is_cache_enabled()) {
// Try to load file with name ${hash_value}.cl_cache which contains precompiled kernels for current bucket
// If read is successful, then remove kernels from compilation bucket
auto bin = loadBinaryFromFile(cached_bin_name);
std::vector<uint8_t> bin;
{
std::lock_guard<std::mutex> lock(cacheAccessMutex);
bin = ov::util::load_binary(cached_bin_name);
}
if (!bin.empty()) {
precompiled_kernels.push_back(bin);
}
@@ -329,7 +252,8 @@ void kernels_cache::build_batch(const engine& build_engine, const batch_program&
// Note: Bin file contains full bucket, not separate kernels, so kernels reuse across different models is quite limited
// Bucket size can be changed in get_max_kernels_per_batch() method, but forcing it to 1 will lead to much longer
// compile time.
saveBinaryToFile(cached_bin_name, getProgramBinaries(program));
std::lock_guard<std::mutex> lock(cacheAccessMutex);
ov::util::save_binary(cached_bin_name, getProgramBinaries(program));
}
} else {
cl::Program program(cl_build_engine.get_cl_context(), {cl_build_engine.get_cl_device()}, precompiled_kernels);