mirror of git://gcc.gnu.org/git/gcc.git
41975.cc: Add tests to check performance with or without cache of hash code and with...
2011-11-06 François Dumont <fdumont@gcc.gnu.org> * testsuite/performance/23_containers/insert_erase/41975.cc: Add tests to check performance with or without cache of hash code and with string type that has a costlier hash functor than int type. From-SVN: r181037
This commit is contained in:
parent
86951993f8
commit
ba3aa0e6c7
|
@ -1,3 +1,9 @@
|
||||||
|
2011-11-06 François Dumont <fdumont@gcc.gnu.org>
|
||||||
|
|
||||||
|
* testsuite/performance/23_containers/insert_erase/41975.cc: Add
|
||||||
|
tests to check performance with or without cache of hash code and with
|
||||||
|
string type that has a costlier hash functor than int type.
|
||||||
|
|
||||||
2011-11-06 Benjamin Kosnik <bkoz@redhat.com>
|
2011-11-06 Benjamin Kosnik <bkoz@redhat.com>
|
||||||
Andrew MacLeod <amacleod@redhat.com>
|
Andrew MacLeod <amacleod@redhat.com>
|
||||||
|
|
||||||
|
|
|
@ -17,56 +17,167 @@
|
||||||
// with this library; see the file COPYING3. If not see
|
// with this library; see the file COPYING3. If not see
|
||||||
// <http://www.gnu.org/licenses/>.
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <cassert>
|
#include <sstream>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <testsuite_performance.h>
|
#include <testsuite_performance.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Bench using an unordered_set<int>. Hash functor for int is quite
|
||||||
|
// predictable so it helps bench very specific use cases.
|
||||||
|
template<bool use_cache>
|
||||||
|
void bench()
|
||||||
|
{
|
||||||
|
using namespace __gnu_test;
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr << "unordered_set<int> " << (use_cache ? "with" : "without")
|
||||||
|
<< " cache";
|
||||||
|
const std::string desc = ostr.str();
|
||||||
|
|
||||||
|
time_counter time;
|
||||||
|
resource_counter resource;
|
||||||
|
|
||||||
|
const int nb = 200000;
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
std::__unordered_set<int, std::hash<int>, std::equal_to<int>,
|
||||||
|
std::allocator<int>, use_cache> us;
|
||||||
|
for (int i = 0; i != nb; ++i)
|
||||||
|
us.insert(i);
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": first insert";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
// Here is the worst erase use case when hashtable implementation was
|
||||||
|
// something like vector<forward_list<>>. Erasing from the end was very
|
||||||
|
// costly because we need to return the iterator following the erased
|
||||||
|
// one, as the hashtable is getting emptier at each step there are
|
||||||
|
// more and more empty bucket to loop through to reach the end of the
|
||||||
|
// container and find out that it was in fact the last element.
|
||||||
|
for (int j = nb - 1; j >= 0; --j)
|
||||||
|
{
|
||||||
|
auto it = us.find(j);
|
||||||
|
if (it != us.end())
|
||||||
|
us.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": erase from iterator";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
// This is a worst insertion use case for the current implementation as
|
||||||
|
// we insert an element at the begining of the hashtable and then we
|
||||||
|
// insert starting at the end so that each time we need to seek up to the
|
||||||
|
// first bucket to find the first non-empty one.
|
||||||
|
us.insert(0);
|
||||||
|
for (int i = nb - 1; i >= 0; --i)
|
||||||
|
us.insert(i);
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": second insert";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
for (int j = nb - 1; j >= 0; --j)
|
||||||
|
us.erase(j);
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": erase from key";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bench using unordered_set<string> that show how important it is to cache
|
||||||
|
// hash code as computing string hash code is quite expensive compared to
|
||||||
|
// computing it for int.
|
||||||
|
template<bool use_cache>
|
||||||
|
void bench_str()
|
||||||
|
{
|
||||||
|
using namespace __gnu_test;
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr << "unordered_set<string> " << (use_cache ? "with" : "without")
|
||||||
|
<< " cache";
|
||||||
|
const std::string desc = ostr.str();
|
||||||
|
|
||||||
|
time_counter time;
|
||||||
|
resource_counter resource;
|
||||||
|
|
||||||
|
const int nb = 200000;
|
||||||
|
// First generate once strings that are going to be used throughout the
|
||||||
|
// bench:
|
||||||
|
std::vector<std::string> strs;
|
||||||
|
strs.reserve(nb);
|
||||||
|
for (int i = 0; i != nb; ++i)
|
||||||
|
{
|
||||||
|
ostr.str("");
|
||||||
|
ostr << "string #" << i;
|
||||||
|
strs.push_back(ostr.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
std::__unordered_set<std::string, std::hash<std::string>,
|
||||||
|
std::equal_to<std::string>,
|
||||||
|
std::allocator<std::string>, use_cache> us;
|
||||||
|
for (int i = 0; i != nb; ++i)
|
||||||
|
us.insert(strs[i]);
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": first insert";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
for (int j = nb - 1; j >= 0; --j)
|
||||||
|
{
|
||||||
|
auto it = us.find(strs[j]);
|
||||||
|
if (it != us.end())
|
||||||
|
us.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": erase from iterator";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
us.insert(strs[0]);
|
||||||
|
for (int i = nb - 1; i >= 0; --i)
|
||||||
|
us.insert(strs[i]);
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": second insert";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
|
||||||
|
start_counters(time, resource);
|
||||||
|
|
||||||
|
for (int j = nb - 1; j >= 0; --j)
|
||||||
|
us.erase(strs[j]);
|
||||||
|
|
||||||
|
stop_counters(time, resource);
|
||||||
|
ostr.str("");
|
||||||
|
ostr << desc << ": erase from key";
|
||||||
|
report_performance(__FILE__, ostr.str().c_str(), time, resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
using namespace __gnu_test;
|
bench<false>();
|
||||||
|
bench<true>();
|
||||||
time_counter time;
|
bench_str<false>();
|
||||||
resource_counter resource;
|
bench_str<true>();
|
||||||
|
|
||||||
start_counters(time, resource);
|
|
||||||
|
|
||||||
std::unordered_set<int> us;
|
|
||||||
for (int i = 0; i != 5000000; ++i)
|
|
||||||
us.insert(i);
|
|
||||||
|
|
||||||
stop_counters(time, resource);
|
|
||||||
report_performance(__FILE__, "Container generation", time, resource);
|
|
||||||
|
|
||||||
start_counters(time, resource);
|
|
||||||
|
|
||||||
for (int j = 100; j != 0; --j)
|
|
||||||
{
|
|
||||||
auto it = us.begin();
|
|
||||||
while (it != us.end())
|
|
||||||
{
|
|
||||||
if ((*it % j) == 0)
|
|
||||||
it = us.erase(it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_counters(time, resource);
|
|
||||||
report_performance(__FILE__, "Container erase", time, resource);
|
|
||||||
|
|
||||||
start_counters(time, resource);
|
|
||||||
|
|
||||||
us.insert(0);
|
|
||||||
|
|
||||||
for (int i = 0; i != 500; ++i)
|
|
||||||
{
|
|
||||||
auto it = us.begin();
|
|
||||||
++it;
|
|
||||||
assert( it == us.end() );
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_counters(time, resource);
|
|
||||||
report_performance(__FILE__, "Container iteration", time, resource);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue