M
Melzzzzz
I have measured my implementation of scapegoat tree and boost's.
Surprisingly boost seems to choke on ordered data set insertion.
Yes, scapegoat trees are slowest on ordered insertion, because
of their nature, but *this* slow something must be wrong...
This is time for just 100k ordered elements insertion!
bmaxa@maxa:~/shootout/trees$ time ./boosintr
boost sg_set 14.94 size 100000
my scapegoat 0.06 size 100000
real 0m15.027s
user 0m14.965s
sys 0m0.056s
bench program taken and modified from boosts page about sg_sets:
#include <boost/intrusive/sg_set.hpp>
#include <vector>
#include <algorithm>
#include <cassert>
#include "ScapeGoat.h"
using namespace boost::intrusive;
class MyClass : public bs_set_base_hook<>
{
int int_;
public:
//This is a member hook
bs_set_member_hook<> member_hook_;
MyClass(int i)
: int_(i)
{}
friend bool operator< (const MyClass &a, const MyClass &b)
{ return a.int_ < b.int_; }
friend bool operator> (const MyClass &a, const MyClass &b)
{ return a.int_ > b.int_; }
friend bool operator== (const MyClass &a, const MyClass &b)
{ return a.int_ == b.int_; }
};
//Define an sg_set using the base hook that will store values in reverse order
//and won't execute floating point operations.
typedef sg_set
< MyClass > BaseSet;
int main()
{
typedef std::vector<MyClass>::iterator VectIt;
typedef std::vector<MyClass>::reverse_iterator VectRit;
//Create several MyClass objects, each one with a different value
std::vector<MyClass> values;
for(int i = 0; i < 100000; ++i) values.push_back(MyClass(i));
//std::random_shuffle(values.begin(),values.end());
BaseSet baseset;
ScapeGoat<MyClass,int> goat;
clock_t begin,end;
begin = clock();
for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){
baseset.insert(*it);
}
end = clock();
std::cout<<"boost sg_set "<<((end-begin)/double(CLOCKS_PER_SEC))
<<" size "<<baseset.size()<<"\n";
begin = clock();
for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){
goat.insert(std::make_pair(*it,0));
}
end = clock();
std::cout<<"my scapegoat "<<((end-begin)/double(CLOCKS_PER_SEC))
<<" size "<<goat.size()<<"\n";
//Now test sg_sets
{
BaseSet::iterator bit(baseset.begin()), bitend(baseset.end());
VectIt it(values.begin()), itend(values.end());
ScapeGoat<MyClass,int>::iterator sgi = goat.begin();
//Test the objects inserted in the base hook sg_set
for(; it != itend; ++it, ++bit)
assert(&*bit == &*it);
//Test the objects inserted in the member hook sg_set
for(it = values.begin(); it != itend; ++it, ++sgi)
assert(sgi->first == *it) ;
}
return 0;
}
Surprisingly boost seems to choke on ordered data set insertion.
Yes, scapegoat trees are slowest on ordered insertion, because
of their nature, but *this* slow something must be wrong...
This is time for just 100k ordered elements insertion!
bmaxa@maxa:~/shootout/trees$ time ./boosintr
boost sg_set 14.94 size 100000
my scapegoat 0.06 size 100000
real 0m15.027s
user 0m14.965s
sys 0m0.056s
bench program taken and modified from boosts page about sg_sets:
#include <boost/intrusive/sg_set.hpp>
#include <vector>
#include <algorithm>
#include <cassert>
#include "ScapeGoat.h"
using namespace boost::intrusive;
class MyClass : public bs_set_base_hook<>
{
int int_;
public:
//This is a member hook
bs_set_member_hook<> member_hook_;
MyClass(int i)
: int_(i)
{}
friend bool operator< (const MyClass &a, const MyClass &b)
{ return a.int_ < b.int_; }
friend bool operator> (const MyClass &a, const MyClass &b)
{ return a.int_ > b.int_; }
friend bool operator== (const MyClass &a, const MyClass &b)
{ return a.int_ == b.int_; }
};
//Define an sg_set using the base hook that will store values in reverse order
//and won't execute floating point operations.
typedef sg_set
< MyClass > BaseSet;
int main()
{
typedef std::vector<MyClass>::iterator VectIt;
typedef std::vector<MyClass>::reverse_iterator VectRit;
//Create several MyClass objects, each one with a different value
std::vector<MyClass> values;
for(int i = 0; i < 100000; ++i) values.push_back(MyClass(i));
//std::random_shuffle(values.begin(),values.end());
BaseSet baseset;
ScapeGoat<MyClass,int> goat;
clock_t begin,end;
begin = clock();
for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){
baseset.insert(*it);
}
end = clock();
std::cout<<"boost sg_set "<<((end-begin)/double(CLOCKS_PER_SEC))
<<" size "<<baseset.size()<<"\n";
begin = clock();
for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){
goat.insert(std::make_pair(*it,0));
}
end = clock();
std::cout<<"my scapegoat "<<((end-begin)/double(CLOCKS_PER_SEC))
<<" size "<<goat.size()<<"\n";
//Now test sg_sets
{
BaseSet::iterator bit(baseset.begin()), bitend(baseset.end());
VectIt it(values.begin()), itend(values.end());
ScapeGoat<MyClass,int>::iterator sgi = goat.begin();
//Test the objects inserted in the base hook sg_set
for(; it != itend; ++it, ++bit)
assert(&*bit == &*it);
//Test the objects inserted in the member hook sg_set
for(it = values.begin(); it != itend; ++it, ++sgi)
assert(sgi->first == *it) ;
}
return 0;
}