#include "gpu/intel/conv/jit/lookup_table.hpp"
#include <algorithm>
#include <fstream>
#include <mutex>
#include <vector>
#include "common/utils.hpp"
#include "gpu/intel/jit/utils/utils.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
namespace conv {
namespace jit {
const char **get_lookup_table_entries();
void lookup_table_t::entry_t::stringify(std::ostream &out) const {
key.stringify(out);
out << " ";
params.stringify(out);
}
void lookup_table_t::entry_t::parse(std::istream &in) {
key.parse(in);
params.parse(in);
}
lookup_table_t::lookup_table_t(const char **entries) {
while (*entries) {
lookup_table_t::entry_t e;
istringstream_t iss(*entries);
e.parse(iss);
#ifdef DNNL_DEV_MODE
{
ostringstream_t oss;
e.stringify(oss);
gpu_assert(oss.str() == *entries)
<< "parsed from:\n " << *entries << "\nstringified to\n "
<< oss.str();
}
#endif
set(e.key, e.params);
entries++;
}
}
void lookup_table_t::set(const key_t &key, const blocking_params_t ¶ms) {
auto &desc_entries = data_[key.desc()];
for (auto &e : desc_entries) {
if (e.key == key) {
e.params = params;
return;
}
}
desc_entries.push_back(entry_t {key, params});
}
void lookup_table_t::merge(const lookup_table_t &other) {
for (auto &kv : other.data_) {
for (auto &e : kv.second) {
set(e.key, e.params);
}
}
}
blocking_params_t lookup_table_t::find(const key_t &key) const {
auto entries_it = data_.find(key.desc());
if (entries_it == data_.end()) return blocking_params_t();
auto &desc_entries = entries_it->second;
auto it = desc_entries.begin();
auto best = desc_entries.end();
dim_t best_dist = std::numeric_limits<dim_t>::max();
for (; it != desc_entries.end(); it++) {
if (!it->key.matches(key)) continue;
dim_t dist = it->key.distance(key);
if (dist < best_dist) {
best_dist = dist;
best = it;
}
}
return (best == desc_entries.end()) ? blocking_params_t() : best->params;
}
void lookup_table_t::stringify(std::ostream &out) const {
std::vector<std::string> lines;
for (auto &kv : data_) {
for (auto &e : kv.second) {
ostringstream_t oss;
e.stringify(oss);
lines.push_back(oss.str());
}
}
std::sort(lines.begin(), lines.end());
bool is_first = true;
for (auto &line : lines) {
if (!is_first) out << "\n";
out << line;
is_first = false;
}
}
void lookup_table_t::parse(std::istream &in) {
data_.clear();
std::string line;
while (std::getline(in, line)) {
if (line.empty() || line[0] == '#') continue;
entry_t e;
intel::jit::parse(line, e);
data_[e.key.desc()].push_back(e);
}
}
struct lookup_table_instance_t {
lookup_table_instance_t() {
table = lookup_table_t(get_lookup_table_entries());
#ifdef DNNL_DEV_MODE
table_path = getenv_string_user(env_table_path_name);
#endif
if (!table_path.empty()) {
std::ifstream in(table_path);
if (!in.good()) return;
lookup_table_t file_table;
file_table.parse(in);
table.merge(file_table);
}
}
~lookup_table_instance_t() {
if (table_path.empty()) return;
std::ofstream out(table_path, std::ios::binary);
table.stringify(out);
}
static const char *env_table_path_name;
std::string table_path;
lookup_table_t table;
};
const char *lookup_table_instance_t::env_table_path_name
= "GPU_CONV_LOOKUP_TABLE_PATH";
lookup_table_t &lookup_table_impl(bool read_only = true) {
static lookup_table_instance_t instance;
if (!read_only && instance.table_path.empty()) {
static std::once_flag flag;
std::call_once(flag, [&] {
printf("Warning: %s is not set. All tuning data will be lost.\n",
lookup_table_instance_t::env_table_path_name);
});
}
return instance.table;
}
const lookup_table_t &const_lookup_table() {
return lookup_table_impl();
}
lookup_table_t &lookup_table() {
return lookup_table_impl(false);
}
} } } } } }