From ab430f14da924bc309a690ac901ee6f8fe5b4a29 Mon Sep 17 00:00:00 2001 From: Takanori Nakao Date: Fri, 10 Jul 2015 13:41:45 +0900 Subject: [PATCH] erasure code: shec performance optimization with decoding cache continued from https://github.com/ceph/ceph/pull/4132 Signed-off-by: Takanori Nakao --- src/erasure-code/shec/ErasureCodeShec.cc | 11 + .../shec/ErasureCodeShecTableCache.cc | 256 ++++++++++++++++-- .../shec/ErasureCodeShecTableCache.h | 66 ++++- 3 files changed, 311 insertions(+), 22 deletions(-) diff --git a/src/erasure-code/shec/ErasureCodeShec.cc b/src/erasure-code/shec/ErasureCodeShec.cc index f02a9722682..5dcaf44da12 100644 --- a/src/erasure-code/shec/ErasureCodeShec.cc +++ b/src/erasure-code/shec/ErasureCodeShec.cc @@ -562,6 +562,14 @@ int ErasureCodeShec::shec_make_decoding_matrix(bool prepare, int *want_, int *av } } + if (tcache.getDecodingTableFromCache(decoding_matrix, + dm_row, dm_column, minimum, + technique, + k, m, c, w, + want, avails)) { + return 0; + } + for (unsigned long long pp = 0; pp < (1ull << m); ++pp) { // select parity chunks @@ -755,6 +763,9 @@ int ErasureCodeShec::shec_make_decoding_matrix(bool prepare, int *want_, int *av int ret = jerasure_invert_matrix(tmpmat, decoding_matrix, mindup, w); + tcache.putDecodingTableToCache(decoding_matrix, dm_row, dm_column, minimum, technique, + k, m, c, w, want, avails); + return ret; } diff --git a/src/erasure-code/shec/ErasureCodeShecTableCache.cc b/src/erasure-code/shec/ErasureCodeShecTableCache.cc index 8fb64b2519c..a037892f67c 100644 --- a/src/erasure-code/shec/ErasureCodeShecTableCache.cc +++ b/src/erasure-code/shec/ErasureCodeShecTableCache.cc @@ -23,34 +23,95 @@ #include "common/debug.h" // ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +#define dout_subsys ceph_subsys_osd +#undef dout_prefix +#define dout_prefix _tc_prefix(_dout) +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- + +static ostream& +_tc_prefix(std::ostream* _dout) { + return *_dout << "ErasureCodeShecTableCache: "; +} + +// ----------------------------------------------------------------------------- + ErasureCodeShecTableCache::~ErasureCodeShecTableCache() { Mutex::Locker lock(codec_tables_guard); - codec_technique_tables_t::const_iterator ttables_it; - codec_tables_t::const_iterator tables_it; - codec_tables_t_::const_iterator tables_it_; - codec_tables_t__::const_iterator tables_it__; - codec_table_t::const_iterator table_it; - // clean-up all allocated tables + { + codec_technique_tables_t::const_iterator ttables_it; + codec_tables_t::const_iterator tables_it; + codec_tables_t_::const_iterator tables_it_; + codec_tables_t__::const_iterator tables_it__; + codec_table_t::const_iterator table_it; - for (ttables_it = encoding_table.begin(); ttables_it != encoding_table.end(); ++ttables_it) { - for (tables_it = ttables_it->second.begin(); tables_it != ttables_it->second.end(); ++tables_it) { - for (tables_it_ = tables_it->second.begin(); tables_it_ != tables_it->second.end(); ++tables_it_) { - for (tables_it__ = tables_it_->second.begin(); tables_it__ != tables_it_->second.end(); ++tables_it__) { - for (table_it = tables_it__->second.begin(); table_it != tables_it__->second.end(); ++table_it) { - if (table_it->second) { - if (*(table_it->second)) { - delete *(table_it->second); - } - delete table_it->second; - } - } + for (ttables_it = encoding_table.begin(); ttables_it != encoding_table.end(); ++ttables_it) { + for (tables_it = ttables_it->second.begin(); tables_it != ttables_it->second.end(); ++tables_it) { + for (tables_it_ = tables_it->second.begin(); tables_it_ != tables_it->second.end(); ++tables_it_) { + for (tables_it__ = tables_it_->second.begin(); tables_it__ != tables_it_->second.end(); ++tables_it__) { + for (table_it = tables_it__->second.begin(); table_it != tables_it__->second.end(); ++table_it) { + if (table_it->second) { + if (*(table_it->second)) { + delete *(table_it->second); + } + delete table_it->second; + } + } + } } } } } + + { + std::map::const_iterator lru_map_it; + std::map::const_iterator lru_list_it; + + for (lru_map_it = decoding_tables.begin(); + lru_map_it != decoding_tables.end(); + ++lru_map_it) { + if (lru_map_it->second) { + delete lru_map_it->second; + } + } + + for (lru_list_it = decoding_tables_lru.begin(); + lru_list_it != decoding_tables_lru.end(); + ++lru_list_it) { + if (lru_list_it->second) { + delete lru_list_it->second; + } + } + } +} + +ErasureCodeShecTableCache::lru_map_t* +ErasureCodeShecTableCache::getDecodingTables(int technique) { + // the caller must hold the guard mutex: + // => Mutex::Locker lock(codec_tables_guard); + + // create an lru_map if not yet allocated + if (!decoding_tables[technique]) { + decoding_tables[technique] = new lru_map_t; + } + return decoding_tables[technique]; +} + +ErasureCodeShecTableCache::lru_list_t* +ErasureCodeShecTableCache::getDecodingTablesLru(int technique) { + // the caller must hold the guard mutex: + // => Mutex::Locker lock(codec_tables_guard); + + // create an lru_list if not yet allocated + if (!decoding_tables_lru[technique]) { + decoding_tables_lru[technique] = new lru_list_t; + } + return decoding_tables_lru[technique]; } int** @@ -95,3 +156,162 @@ ErasureCodeShecTableCache::getLock() { return &codec_tables_guard; } + +uint64_t +ErasureCodeShecTableCache::getDecodingCacheSignature(int k, int m, int c, int w, + int *erased, int *avails) { + uint64_t signature = 0; + signature = (uint64_t)k; + signature |= ((uint64_t)m << 6); + signature |= ((uint64_t)c << 12); + signature |= ((uint64_t)w << 18); + + for (int i=0; i < k+m; i++) { + signature |= ((uint64_t)(avails[i] ? 1 : 0) << (24+i)); + } + for (int i=0; i < k+m; i++) { + signature |= ((uint64_t)(erased[i] ? 1 : 0) << (44+i)); + } + return signature; +} + +bool +ErasureCodeShecTableCache::getDecodingTableFromCache(int* decoding_matrix, + int* dm_row, + int* dm_column, + int* minimum, + int technique, + int k, + int m, + int c, + int w, + int* erased, + int* avails) { + // -------------------------------------------------------------------------- + // LRU decoding matrix cache + // -------------------------------------------------------------------------- + + uint64_t signature = getDecodingCacheSignature(k, m, c, w, erased, avails); + Mutex::Locker lock(codec_tables_guard); + + dout(20) << "[ get table ] = " << signature << dendl; + + // we try to fetch a decoding table from an LRU cache + lru_map_t* decode_tbls_map = + getDecodingTables(technique); + + lru_list_t* decode_tbls_lru = + getDecodingTablesLru(technique); + + lru_map_t::iterator decode_tbls_map_it = decode_tbls_map->find(signature); + if (decode_tbls_map_it == decode_tbls_map->end()) { + return false; + } + + dout(20) << "[ cached table ] = " << signature << dendl; + // copy parameters out of the cache + + memcpy(decoding_matrix, + decode_tbls_map_it->second.second.decoding_matrix, + k * k * sizeof(int)); + memcpy(dm_row, + decode_tbls_map_it->second.second.dm_row, + k * sizeof(int)); + memcpy(dm_column, + decode_tbls_map_it->second.second.dm_column, + k * sizeof(int)); + memcpy(minimum, + decode_tbls_map_it->second.second.minimum, + (k+m) * sizeof(int)); + + // find item in LRU queue and push back + decode_tbls_lru->splice(decode_tbls_lru->end(), + *decode_tbls_lru, + decode_tbls_map_it->second.first); + return true; +} + +void +ErasureCodeShecTableCache::putDecodingTableToCache(int* decoding_matrix, + int* dm_row, + int* dm_column, + int* minimum, + int technique, + int k, + int m, + int c, + int w, + int* erased, + int* avails) { + // -------------------------------------------------------------------------- + // LRU decoding matrix cache + // -------------------------------------------------------------------------- + + Mutex::Locker lock(codec_tables_guard); + + uint64_t signature = getDecodingCacheSignature(k, m, c, w, erased, avails); + dout(20) << "[ put table ] = " << signature << dendl; + + // we store a new table to the cache + + // bufferptr cachetable; + + lru_map_t* decode_tbls_map = + getDecodingTables(technique); + + lru_list_t* decode_tbls_lru = + getDecodingTablesLru(technique); + + if (decode_tbls_map->count(signature)) { + dout(20) << "[ already on table ] = " << signature << dendl; + + // find item in LRU queue and push back + decode_tbls_lru->splice(decode_tbls_lru->end(), + *decode_tbls_lru, + (*decode_tbls_map)[signature].first); + return; + } + + // evt. shrink the LRU queue/map + if ((int)decode_tbls_lru->size() >= + ErasureCodeShecTableCache::decoding_tables_lru_length) { + dout(20) << "[ shrink lru ] = " << signature << dendl; + // remove from map + decode_tbls_map->erase(decode_tbls_lru->front()); + // remove from lru + decode_tbls_lru->pop_front(); + } + + { + dout(20) << "[ store table ] = " << signature << dendl; + + decode_tbls_lru->push_back(signature); + + // allocate a new buffer + lru_list_t::iterator it_end = decode_tbls_lru->end(); + it_end--; + + lru_entry_t &map_value = + (*decode_tbls_map)[signature] = + std::make_pair(it_end, DecodingCacheParameter()); + map_value.second.decoding_matrix = new int[k*k]; + map_value.second.dm_row = new int[k]; + map_value.second.dm_column = new int[k]; + map_value.second.minimum = new int[k+m]; + + memcpy(map_value.second.decoding_matrix, + decoding_matrix, + k * k * sizeof(int)); + memcpy(map_value.second.dm_row, + dm_row, + k * sizeof(int)); + memcpy(map_value.second.dm_column, + dm_column, + k * sizeof(int)); + memcpy(map_value.second.minimum, + minimum, + (k+m) * sizeof(int)); + + dout(20) << "[ cache size ] = " << decode_tbls_lru->size() << dendl; + } +} diff --git a/src/erasure-code/shec/ErasureCodeShecTableCache.h b/src/erasure-code/shec/ErasureCodeShecTableCache.h index 21f65bdfa6f..e4eaf0f0eaa 100644 --- a/src/erasure-code/shec/ErasureCodeShecTableCache.h +++ b/src/erasure-code/shec/ErasureCodeShecTableCache.h @@ -31,11 +31,43 @@ class ErasureCodeShecTableCache { // --------------------------------------------------------------------------- // This class implements a table cache for encoding and decoding matrices. // Encoding matrices are shared for the same (k,m,c,w) combination. + // It supplies a decoding matrix lru cache which is shared for identical + // matrix types e.g. there is one cache (lru-list + lru-map) // --------------------------------------------------------------------------- + class DecodingCacheParameter { + public: + int* decoding_matrix; // size: k*k + int* dm_row; // size: k + int* dm_column; // size: k + int* minimum; // size: k+m + DecodingCacheParameter() { + decoding_matrix = 0; + dm_row = 0; + dm_column = 0; + minimum = 0; + } + ~DecodingCacheParameter() { + if (decoding_matrix) { + delete[] decoding_matrix; + } + if (dm_row) { + delete[] dm_row; + } + if (dm_column) { + delete[] dm_column; + } + if (minimum) { + delete[] minimum; + } + } + }; + public: - typedef std::pair::iterator, bufferptr> lru_entry_t; + static const int decoding_tables_lru_length = 10000; + typedef std::pair::iterator, + DecodingCacheParameter> lru_entry_t; typedef std::map< int, int** > codec_table_t; typedef std::map< int, codec_table_t > codec_tables_t__; typedef std::map< int, codec_tables_t__ > codec_tables_t_; @@ -43,6 +75,9 @@ class ErasureCodeShecTableCache { typedef std::map< int, codec_tables_t > codec_technique_tables_t; // int** matrix = codec_technique_tables_t[technique][k][m][c][w] + typedef std::map< uint64_t, lru_entry_t > lru_map_t; + typedef std::list< uint64_t > lru_list_t; + ErasureCodeShecTableCache() : codec_tables_guard("shec-lru-cache") { @@ -52,15 +87,38 @@ class ErasureCodeShecTableCache { Mutex codec_tables_guard; // mutex used to protect modifications in encoding/decoding table maps + bool getDecodingTableFromCache(int* matrix, + int* dm_row, int* dm_column, + int* minimum, + int technique, + int k, int m, int c, int w, + int* want, int* avails); + + void putDecodingTableToCache(int* matrix, + int* dm_row, int* dm_column, + int* minimum, + int technique, + int k, int m, int c, int w, + int* want, int* avails); + int** getEncodingTable(int technique, int k, int m, int c, int w); int** getEncodingTableNoLock(int technique, int k, int m, int c, int w); int* setEncodingTable(int technique, int k, int m, int c, int w, int*); private: - codec_technique_tables_t encoding_table; // encoding coefficients accessed via table[technique][k][m] - + // encoding table accessed via table[matrix][k][m][c][w] + // decoding table cache accessed via map[matrixtype] + // decoding table lru list accessed via list[matrixtype] + codec_technique_tables_t encoding_table; + std::map decoding_tables; + std::map decoding_tables_lru; + + lru_map_t* getDecodingTables(int technique); + lru_list_t* getDecodingTablesLru(int technique); + uint64_t getDecodingCacheSignature(int k, int m, int c, int w, + int *want, int *avails); + Mutex* getLock(); - }; #endif