From 6b882ac767704d4843db72988ef8229cb935fd33 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 9 Jun 2017 20:12:49 +0200 Subject: [PATCH] Fix slow garbage collect after using a lot of states --- panda/src/pgraph/renderAttrib.cxx | 4 ++++ panda/src/pgraph/renderState.cxx | 4 ++++ panda/src/pgraph/transformState.cxx | 4 ++++ panda/src/putil/simpleHashMap.I | 35 +++++++++++++++++++++++------ panda/src/putil/simpleHashMap.h | 4 +++- 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 3a7b511381..f2425a32ff 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -255,6 +255,10 @@ garbage_collect() { nassertr(_attribs->validate(), 0); #endif + // If we just cleaned up a lot of attribs, see if we can reduce the table in + // size. This will help reduce iteration overhead in the future. + _attribs->consider_shrink_table(); + size_t new_size = _attribs->get_num_entries(); return orig_size - new_size; } diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index d8cd5a6dd3..99e02792b2 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -1001,6 +1001,10 @@ garbage_collect() { nassertr(_states->validate(), 0); #endif + // If we just cleaned up a lot of states, see if we can reduce the table in + // size. This will help reduce iteration overhead in the future. + _states->consider_shrink_table(); + int new_size = _states->get_num_entries(); return orig_size - new_size + num_attribs; } diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index be1ed4a15a..765dafb96a 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -1253,6 +1253,10 @@ garbage_collect() { nassertr(_states->validate(), 0); #endif + // If we just cleaned up a lot of states, see if we can reduce the table in + // size. This will help reduce iteration overhead in the future. + _states->consider_shrink_table(); + int new_size = _states->get_num_entries(); return orig_size - new_size; } diff --git a/panda/src/putil/simpleHashMap.I b/panda/src/putil/simpleHashMap.I index 74245fd606..4b21b02d1e 100644 --- a/panda/src/putil/simpleHashMap.I +++ b/panda/src/putil/simpleHashMap.I @@ -522,27 +522,48 @@ new_table() { template INLINE bool SimpleHashMap:: consider_expand_table() { - if (_num_entries >= (_table_size >> 1)) { - expand_table(); + if (_num_entries < (_table_size >> 1)) { + return false; + } else { + resize_table(_table_size << 1); return true; } - return false; } /** - * Doubles the size of the existing table. + * Shrinks the table if the allocated storage is significantly larger than the + * number of elements in it. Returns true if shrunk, false otherwise. + */ +template +INLINE bool SimpleHashMap:: +consider_shrink_table() { + // If the number of elements gets less than an eighth of the table size, we + // know it's probably time to shrink it down, lest it hurt iteration time. + if (_table_size <= 8 || (_table_size >> 3) < _num_entries) { + return false; + } else { + size_t new_size = _table_size; + do { + new_size >>= 1; + } while ((new_size >> 3) >= _num_entries); + resize_table(new_size); + return true; + } +} + +/** + * Resizes the existing table. */ template void SimpleHashMap:: -expand_table() { +resize_table(size_t new_size) { nassertv(_table_size != 0); SimpleHashMap old_map(_comp); swap(old_map); - // Double the table size. size_t old_table_size = old_map._table_size; - _table_size = (old_table_size << 1); + _table_size = new_size; nassertv(_table == NULL); // We allocate enough bytes for _table_size elements of TableEntry, plus diff --git a/panda/src/putil/simpleHashMap.h b/panda/src/putil/simpleHashMap.h index c1a25fc7f9..928b704e05 100644 --- a/panda/src/putil/simpleHashMap.h +++ b/panda/src/putil/simpleHashMap.h @@ -56,6 +56,8 @@ public: void write(ostream &out) const; bool validate() const; + INLINE bool consider_shrink_table(); + private: class TableEntry; @@ -68,7 +70,7 @@ private: void new_table(); INLINE bool consider_expand_table(); - void expand_table(); + void resize_table(size_t new_size); class TableEntry { public: