Skip to content

Instantly share code, notes, and snippets.

@usagi
Last active August 29, 2015 14:00
Show Gist options
  • Select an option

  • Save usagi/11204302 to your computer and use it in GitHub Desktop.

Select an option

Save usagi/11204302 to your computer and use it in GitHub Desktop.
#include <random>
#include <iostream>
#include <iomanip>
#include <vector>
#include <list>
#include <forward_list>
#include <map>
#include <unordered_map>
#include <algorithm>
#include <chrono>
#include <functional>
#include <boost/any.hpp>
#include <boost/property_tree/ptree.hpp>
#include <glm/glm.hpp>
namespace
{
auto print_time
( const std::function
< auto(unsigned long, unsigned long)->void >& f
, unsigned long number_of_steps
, unsigned long number_of_objects
)
-> void
{
using namespace std::chrono;
const auto start = high_resolution_clock::now();
f( number_of_steps, number_of_objects );
const auto delta_time = high_resolution_clock::now() - start;
std::cout << std::fixed << std::setprecision(2);
if ( duration_cast< minutes >( delta_time ) > std::chrono::minutes(1) )
std::cout << " time: " << duration_cast< duration<double, minutes::period> >( delta_time ).count() << " [min.]\n";
else if ( duration_cast< std::chrono::seconds >( delta_time ) > seconds(1) )
std::cout << " time: " << duration_cast< duration<double, seconds::period> >( delta_time ).count() << " [sec.]\n";
else if ( duration_cast< std::chrono::milliseconds >( delta_time ) > milliseconds(1) )
std::cout << " time: " << duration_cast< duration<double, milliseconds::period> >( delta_time ).count() << " [ms]\n";
else if ( duration_cast< std::chrono::microseconds >( delta_time ) > microseconds(1) )
std::cout << " time: " << duration_cast< duration<double, microseconds::period> >( delta_time ).count() << " [us]\n";
else
std::cout << " time: " << duration_cast< duration<double, nanoseconds::period> >( delta_time ).count() << " [ns]\n";
}
class object_t
{
public:
virtual auto mass(const double value) -> void = 0;
virtual auto position(const glm::vec3& value) -> void = 0;
virtual auto position() const -> glm::vec3 = 0;
virtual auto action(const double delta_time, const glm::vec3& force) -> void = 0;
};
class member_variable_object_t
: public object_t
{
double _mass;
glm::vec3 _position;
glm::vec3 _velocity;
public:
auto mass(const double value)
-> void override
{ _mass = value; }
auto position(const glm::vec3& value)
-> void override
{ _position = value; }
auto position() const
-> glm::vec3 override
{ return _position; }
auto action(const double delta_time, const glm::vec3& force)
-> void override
{
const auto vec3_delta_time = glm::vec3( delta_time );
const auto acceleration = force / glm::vec3( _mass );
_velocity += acceleration * vec3_delta_time;
_position += _velocity * vec3_delta_time;
}
};
template < class T_map = std::map<std::string, boost::any> >
class map_string_any_object_t
: public object_t
{
T_map _properties;
public:
explicit map_string_any_object_t()
: _properties
( { { "mass", 0 }
, { "position", glm::vec3() }
, { "velocity", glm::vec3() }
}
)
{ }
auto mass(const double value)
-> void override
{ _properties["mass"] = value; }
auto position(const glm::vec3& value)
-> void override
{ _properties["position"] = value; }
auto position() const
-> glm::vec3 override
{ return boost::any_cast<const glm::vec3>( _properties.at("position") ); }
auto action(const double delta_time, const glm::vec3& force)
-> void override
{
const auto vec3_delta_time = glm::vec3( delta_time );
const auto acceleration = force / glm::vec3( boost::any_cast<double>( _properties["mass"] ) );
const auto velocity = boost::any_cast<glm::vec3&>( _properties["velocity"] ) += acceleration * vec3_delta_time;
boost::any_cast<glm::vec3&>( _properties["position"] ) += velocity * vec3_delta_time;
}
};
class ptree_object_t
: public object_t
{
boost::property_tree::ptree _properties;
public:
explicit ptree_object_t()
{
_properties.put( "mass", 0 );
property_from_glm_vec3( "position", glm::vec3() );
property_from_glm_vec3( "velocity", glm::vec3() );
}
auto mass(const double value)
-> void override
{ _properties.put("mass", value); }
auto position(const glm::vec3& value)
-> void override
{
_properties.put("position.x", value.x);
_properties.put("position.y", value.y);
_properties.put("position.z", value.z);
}
auto position() const
-> glm::vec3 override
{ return glm_vec3_from_property("position"); }
auto action(const double delta_time, const glm::vec3& force)
-> void override
{
const auto vec3_delta_time = glm::vec3( delta_time );
const auto acceleration = force / glm::vec3( _properties.get<double>("mass") );
auto velocity = glm_vec3_from_property("velocity");
velocity += acceleration * vec3_delta_time;
property_from_glm_vec3("velocity", velocity);
auto position = glm_vec3_from_property("position");
position += velocity * vec3_delta_time;
property_from_glm_vec3("position", position);
}
auto glm_vec3_from_property(const std::string& key) const
-> glm::vec3
{
return glm::vec3
( _properties.get<double>( key + ".x" )
, _properties.get<double>( key + ".y" )
, _properties.get<double>( key + ".z" )
);
}
auto property_from_glm_vec3(const std::string& key, const glm::vec3& v)
-> void
{
_properties.put( key + ".x", v.x );
_properties.put( key + ".y", v.y );
_properties.put( key + ".z", v.z );
}
};
template
< template<class T, class Allocator=std::allocator<T> > class T_container
, class T_object
>
auto test
( unsigned long number_of_steps
, unsigned long number_of_objects
)
-> void
{
T_container<T_object> objects( number_of_objects );
std::mt19937 rng( 0 );
std::normal_distribution<double> unorm_distribution( 0.0, 1.0 );
std::normal_distribution<double> snorm_distribution( -1.0, 1.0 );
for ( auto& object : objects )
{
object.mass( unorm_distribution( rng ) );
object.position
( { snorm_distribution( rng )
, snorm_distribution( rng )
, snorm_distribution( rng )
}
);
}
const auto print_normalized_sum_of_positions = [ &objects ]
{
glm::vec3 sum;
for ( const auto object : objects )
sum += object.position();
const auto normalized = glm::normalize( sum );
std::cout
<< std::fixed
<< std::setprecision(3)
<< normalized.x << " "
<< normalized.y << " "
<< normalized.z
<< "\n"
;
};
std::cout << " normalized sum of positions(initial): ";
print_normalized_sum_of_positions();
for ( auto n = 0; n < number_of_steps; ++n )
{
const auto delta_time = unorm_distribution( rng );
for ( auto& object : objects )
object.action
( delta_time
, { snorm_distribution( rng )
, snorm_distribution( rng )
, snorm_distribution( rng )
}
);
}
std::cout << " normalized sum of positions(final) : ";
print_normalized_sum_of_positions();
}
}
auto main(int number_of_arguments, char** arguments)
-> int
{
unsigned long number_of_steps = 1000;
unsigned long number_of_objects = 1000;
std::cout
<< "\n"
" *** property_benchmark *** \n"
" usage: ./a.out [number_of_steps] [number_of_objects]\n"
" defaults are: " << number_of_steps << ", " << number_of_objects << "\n"
" this program benchmarks:\n"
" basic Newton's Equation of motion with Eular's method using:\n"
" 1. objects container types { std::vector, std::list, std::forward_list } \n"
" 2. object owned property types { basic member variable, boost::property_tree::ptree }\n"
;
try
{
if ( number_of_arguments > 1 )
number_of_steps = std::stoul( arguments[1] );
if ( number_of_arguments > 2 )
number_of_objects = std::stoul( arguments[2] );
}
catch( const std::invalid_argument& )
{
std::cerr << " !!! warning: invalid argument. !!!\n";
}
std::cout
<< "\n"
"number_of_steps : " << number_of_steps << "\n"
"number_of_objects: " << number_of_objects << "\n"
;
// test run
std::cout << "\n *** test running std::vector<basic_object_t>(1, 1) ***\n";
print_time( test<std::vector, member_variable_object_t>, 1, 1);
std::cout << "\n === std::vector<member_variable_object_t> ===\n";
print_time( test<std::vector, member_variable_object_t>, number_of_steps, number_of_objects );
std::cout << "\n === std::list<member_variable_object_t> ===\n";
print_time( test<std::list, member_variable_object_t>, number_of_steps, number_of_objects );
std::cout << "\n === std::forward_list<member_variable_object_t> ===\n";
print_time( test<std::forward_list, member_variable_object_t>, number_of_steps, number_of_objects );
std::cout << "\n === std::vector<map_string_any_object_t<>> ===\n";
print_time( test<std::vector, map_string_any_object_t<>>, number_of_steps, number_of_objects );
std::cout << "\n === std::list<map_string_any_object_t<>> ===\n";
print_time( test<std::list, map_string_any_object_t<>>, number_of_steps, number_of_objects );
std::cout << "\n === std::forward_list<map_string_any_object_t<>> ===\n";
print_time( test<std::forward_list, map_string_any_object_t<>>, number_of_steps, number_of_objects );
std::cout << "\n === std::vector<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===\n";
print_time( test<std::vector, map_string_any_object_t<std::unordered_map<std::string, boost::any>>>, number_of_steps, number_of_objects );
std::cout << "\n === std::list<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===\n";
print_time( test<std::list, map_string_any_object_t<std::unordered_map<std::string, boost::any>>>, number_of_steps, number_of_objects );
std::cout << "\n === std::forward_list<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===\n";
print_time( test<std::forward_list, map_string_any_object_t<std::unordered_map<std::string, boost::any>>>, number_of_steps, number_of_objects );
std::cout << "\n === std::vector<map_string_any_object_t<ptree_object_t> ===\n";
print_time( test<std::vector, ptree_object_t>, number_of_steps, number_of_objects );
std::cout << "\n === std::list<map_string_any_object_t<ptree_object_t> ===\n";
print_time( test<std::list, ptree_object_t>, number_of_steps, number_of_objects );
std::cout << "\n === std::forward_list<ptree_object_t> ===\n";
print_time( test<std::forward_list, ptree_object_t>, number_of_steps, number_of_objects );
}
*** property_benchmark ***
usage: ./a.out [number_of_steps] [number_of_objects]
defaults are: 1000, 1000
this program benchmarks:
basic Newton's Equation of motion with Eular's method using:
1. objects container types { std::vector, std::list, std::forward_list }
2. object owned property types { basic member variable, boost::property_tree::ptree }
number_of_steps : 1000
number_of_objects: 1000
*** test running std::vector<basic_object_t>(1, 1) ***
normalized sum of positions(initial): -0.337 -0.336 -0.879
normalized sum of positions(final) : -0.310 -0.361 -0.879
time: 107.10 [us]
=== std::vector<member_variable_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 780.61 [ms]
=== std::list<member_variable_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 774.97 [ms]
=== std::forward_list<member_variable_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 770.73 [ms]
=== std::vector<map_string_any_object_t<>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 1390.85 [ms]
=== std::list<map_string_any_object_t<>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 1402.11 [ms]
=== std::forward_list<map_string_any_object_t<>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 1416.99 [ms]
=== std::vector<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 1447.93 [ms]
=== std::list<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 1412.33 [ms]
=== std::forward_list<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 1453.10 [ms]
=== std::vector<map_string_any_object_t<ptree_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 48.37 [sec.]
=== std::list<map_string_any_object_t<ptree_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 48.76 [sec.]
=== std::forward_list<ptree_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 48.00 [sec.]
*** property_benchmark ***
usage: ./a.out [number_of_steps] [number_of_objects]
defaults are: 1000, 1000
this program benchmarks:
basic Newton's Equation of motion with Eular's method using:
1. objects container types { std::vector, std::list, std::forward_list }
2. object owned property types { basic member variable, boost::property_tree::ptree }
number_of_steps : 1000
number_of_objects: 1000
*** test running std::vector<basic_object_t>(1, 1) ***
normalized sum of positions(initial): -0.337 -0.336 -0.879
normalized sum of positions(final) : -0.310 -0.361 -0.879
time: 81.43 [us]
=== std::vector<member_variable_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 489.11 [ms]
=== std::list<member_variable_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 496.42 [ms]
=== std::forward_list<member_variable_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 501.26 [ms]
=== std::vector<map_string_any_object_t<>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 789.39 [ms]
=== std::list<map_string_any_object_t<>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 772.43 [ms]
=== std::forward_list<map_string_any_object_t<>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 782.61 [ms]
=== std::vector<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 755.05 [ms]
=== std::list<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 762.71 [ms]
=== std::forward_list<map_string_any_object_t<std::unordered_map<std::string, boost::any>>> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 761.94 [ms]
=== std::vector<map_string_any_object_t<ptree_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 26.82 [sec.]
=== std::list<map_string_any_object_t<ptree_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 27.05 [sec.]
=== std::forward_list<ptree_object_t> ===
normalized sum of positions(initial): -0.562 -0.600 -0.570
normalized sum of positions(final) : -0.431 -0.754 -0.495
time: 26.64 [sec.]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment