Boost logo

Boost Users :

Subject: [Boost-users] large variant performance compared (50 elements)
From: Paul (peebor_at_[hidden])
Date: 2011-01-07 17:45:04


In a project we are using variants holding shared_ptr's. These variants
are typically 20 items large but are growing as the project progresses.
Now it seems that each time we add elements, we fall into issue's
regarding excessive compilation time, huge pdb file or out of heap space
errors on the compiler or linker.

I took some time to compare various approaches using variants, here are
the results:

stdafx.h

#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector/vector100.hpp>
#include <boost/variant/variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>

test.h

class CTest
{
public:
   void foo(const Cs_t& rt);
};

type.h

class C1 { public: int i; };
class C2 { public: int i; };
class C3 { public: int i; };
...
class C50 { public: int i; };

//v1
typedef boost::variant<
   boost::shared_ptr<C1>,
   boost::shared_ptr<C2>,
   <...>
   boost::shared_ptr<C49>,
   boost::shared_ptr<C50>
> v_t;

//v2
typedef boost::mpl::vector50<
   boost::shared_ptr<C1>,
   boost::shared_ptr<C2>,
   <...>
   boost::shared_ptr<C49>,
   boost::shared_ptr<C50>
> Mplv_t;
typedef boost::make_variant_over<Mplv_t>::type v_t;

//v3
typedef boost::variant<
   C1,
   C2,
   <...>
   C49,
   C50
> v_t;

test.cpp

namespace
{
   class CVisit
     : public boost::static_visitor<>
   {
   public:
     template<typename T>
     void operator()(const T& rt) const
     {
       std::cout << typeid(T).name() << std::endl;
     }
   };
}

void CTest::foo(const v_t& v)
{
//A: (invoke visitor directly, no new variant)
   boost::apply_visitor(CVisit(), v);

//B: Copy variant using copy constructor
   v_t v2(v);
   <...>

//C: Copy variant using assignment operator
   v_t v2;
   v2 = v;
   <...>
}

main.cpp

int main(int argc, char* argv[])
{
   CTest t;
   v_t v = boost::shared_ptr<C10>(new C10);
   t.foo(v);
   return 0;
}

Setup:
Boost 1.38
Msvc2005, Release target
Optimize MaxSpeed (/O2)
Debug info enabled (/Zi)
Build time = rebuild solution; cl + link

Variant type: v1 Foo logic:A
Obj size: 2.4MB
Exe size: 348KB
Pdb size: 9.0MB
Build time: 0:49
Peak commit: 500MB

Variant type: v2 Foo logic:A
Obj size: 1.4MB
Exe size: 348KB
Pdb size: 11.7MB
Build time: 1:02
Peak commit: 600MB

Variant type: v3 Foo logic:A
Obj size: 1.9MB
Exe size: 344KB
Pdb size: 3.9MB
Build time: 0:25
Peak commit: 300MB

Variant type: v1 Foo logic:B (copy variant using copy constructor)
Obj size: 3.1MB
Exe size: 352KB
Pdb size: 9.0MB
Build time: 0:50
Peak commit: 500MB

Variant type: v2 Foo logic:B
Obj size: 2.2MB
Exe size: 352KB
Pdb size: 11.7MB
Build time: 1:03
Peak commit: 600MB

Variant type: v3 Foo logic:B
Obj size: 2.1MB
Exe size: 344KB
Pdb size: 3.9MB
Build time: 0:26
Peak commit: 300MB

Variant type: v1 Foo logic:C (copy variant using assignment operator)
Obj size: 71.3MB
Exe size: 356KB
Pdb size: 10.7MB
Build time: 5:18
Peak commit: 1.2GB

Variant type: v2 Foo logic:C
Obj size: 80.6MB
Exe size: 356KB
Pdb size: 13.6MB
Build time: 8:46
Peak commit: 1.4GB

Variant type: v3 Foo logic:C
Obj size: 2.4MB
Exe size: 344KB
Pdb size: 3.9MB
Build time: 0:26
Peak commit: 300MB

Is there any way to explain these (huge) differences and what is preffered?
- Why does the use of assignment operator have such a hugh impact?
- Why the difference between using shared_ptr or not?
- When to use the numbered variant or boost::variant<...>?

Help is greatly appreciated!
Paul


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net