[GPU] integrate persistent caching for onednn (#12094)
* integrate persistant caching for onednn * add api to save/load binary file.
This commit is contained in:
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
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user