benchmarking is... way too hard, truly.

This commit is contained in:
ThePhD 2016-01-10 20:36:37 -05:00
parent cb9b463167
commit 48e2c82203
8 changed files with 318 additions and 108 deletions

View File

@ -1,60 +1,11 @@
#define NONIUS_RUNNER
#include "bench_cpp_function.hpp"
#include "bench_lua_function.hpp"
#include "nonius/nonius.h++"
#include "sol.hpp"
struct sol_function_result_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua;
lua.script( R"(
function r ()
return 1 + 1
end
)" );
sol::function r = lua[ "r" ];
meter.measure( [ & ] ( int run_index ) {
// Measure cost of lua calling and returning a function
return r( );
} );
}
};
struct sol_direct_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua;
lua.script( R"(
function r ()
return 1 + 1
end
)" );
auto fun = [ & ] ( int run_index ) {
// Measure cost of lua calling and returning a function
sol::function r = lua[ "r" ];
return r.call<int>( );
};
meter.measure( fun );
}
};
struct c_direct_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua;
lua.script( R"(
function r ()
return 1 + 1
end
)" );
lua_State* L = lua.lua_state( );
meter.measure( [ & ] ( int run_index ) {
lua_getglobal( L, "r" );
lua_call( L, 0, 1 );
int lua_out = (int)lua_tonumber( L, -1 );
lua_pop( L, 1 );
return lua_out;
} );
}
};
NONIUS_BENCHMARK( "sol - function_result", sol_function_result_bench() );
NONIUS_BENCHMARK( "sol - int", sol_direct_bench() );
NONIUS_BENCHMARK( "C - int", c_direct_bench( ) );
int main( int argc, char* argv[] ) {
using namespace std::literals::string_literals;
std::string configurationname = argv[ 1 ];
std::string platformname = argv[ 2 ];
bench_lua_function( "bench/", configurationname, platformname );
bench_cpp_function( "bench/", configurationname, platformname );
}

92
bench_cpp_function.hpp Normal file
View File

@ -0,0 +1,92 @@
#pragma once
#include "sol.hpp"
#include "nonius/nonius.h++"
static sol::state prepare_cpp_function_state( ) {
sol::state lua;
lua.set_function( "r",
[ ] ( ) {
return 1 + 1;
}
);
return lua;
}
struct sol_fast_function_result_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
int value = r( );
return value;
};
meter.measure( measurement );
}
};
struct sol_fast_direct_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
int value = r.call<int>( );
return value;
};
meter.measure( measurement );
}
};
struct sol_function_result_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::function r = lua[ "r" ];
int value = r( );
return value;
};
meter.measure( measurement );
}
};
struct sol_direct_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::function r = lua[ "r" ];
int value = r.call<int>( );
return value;
};
meter.measure( measurement );
}
};
struct c_direct_cpp_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_cpp_function_state( );
lua_State* L = lua.lua_state( );
auto measurement = [ & ] ( int run_index ) {
lua_getglobal( L, "r" );
lua_call( L, 0, 1 );
int value = (int)lua_tonumber( L, -1 );
lua_pop( L, 1 );
return value;
};
meter.measure( measurement );
}
};
void bench_cpp_function( const std::string& dir, std::string& configurationname, const std::string& platformname ) {
nonius::configuration cfg;
cfg.output_file = dir + "sol.functions (C++ source) - " + configurationname + " " + platformname + ".html";
cfg.title = "sol::function (C++ source) (" + configurationname + " " + platformname + ")";
cfg.samples = 100;
nonius::benchmark benchmarks [] = {
nonius::benchmark( "fast_function - function_result", sol_fast_function_result_cpp_bench( ) ),
nonius::benchmark( "fast_function - call<>", sol_fast_direct_cpp_bench( ) ),
nonius::benchmark( "function - function_result", sol_function_result_cpp_bench( ) ),
nonius::benchmark( "function - call<>", sol_direct_cpp_bench( ) ),
nonius::benchmark( "plain C", c_direct_cpp_bench( ) ),
};
nonius::go( cfg, std::begin( benchmarks ), std::end( benchmarks ), nonius::html_reporter( ) );
}

1
bench_get.hpp Normal file
View File

@ -0,0 +1 @@
#pragma once

92
bench_lua_function.hpp Normal file
View File

@ -0,0 +1,92 @@
#pragma once
#include "sol.hpp"
#include "nonius/nonius.h++"
static sol::state prepare_lua_function_state( ) {
sol::state lua;
lua.script( R"(
function r ()
return 1 + 1
end
)" );
return lua;
}
struct sol_fast_function_result_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
int value = r( );
return value;
};
meter.measure( measurement );
}
};
struct sol_fast_direct_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::fast_function r = lua[ "r" ];
int value = r.call<int>( );
return value;
};
meter.measure( measurement );
}
};
struct sol_function_result_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::function r = lua[ "r" ];
int value = r( );
return value;
};
meter.measure( measurement );
}
};
struct sol_direct_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
auto measurement = [ & ] ( int run_index ) {
sol::function r = lua[ "r" ];
int value = r.call<int>( );
return value;
};
meter.measure( measurement );
}
};
struct c_direct_lua_bench {
void operator () ( nonius::chronometer meter ) const {
sol::state lua = prepare_lua_function_state( );
lua_State* L = lua.lua_state( );
auto measurement = [ & ] ( int run_index ) {
lua_getglobal( L, "r" );
lua_call( L, 0, 1 );
int value = (int)lua_tonumber( L, -1 );
lua_pop( L, 1 );
return value;
};
meter.measure( measurement );
}
};
void bench_lua_function( const std::string& dir, std::string& configurationname, const std::string& platformname ) {
nonius::configuration cfg;
cfg.output_file = dir + "sol.functions (lua source) - " + configurationname + " " + platformname + ".html";
cfg.title = "sol::function (lua source) (" + configurationname + " " + platformname + ")";
cfg.samples = 100;
nonius::benchmark benchmarks [] = {
nonius::benchmark( "fast_function - function_result", sol_fast_function_result_lua_bench( ) ),
nonius::benchmark( "fast_function - call<>", sol_fast_direct_lua_bench( ) ),
nonius::benchmark( "safe_function - function_result", sol_function_result_lua_bench( ) ),
nonius::benchmark( "safe_function - call<>", sol_direct_lua_bench( ) ),
nonius::benchmark( "plain C", c_direct_lua_bench( ) ),
};
nonius::go( cfg, std::begin( benchmarks ), std::end( benchmarks ), nonius::html_reporter( ) );
}

1
bench_set.hpp Normal file
View File

@ -0,0 +1 @@
#pragma once

1
bench_userdata.hpp Normal file
View File

@ -0,0 +1 @@
#pragma once

View File

@ -38,6 +38,7 @@ private:
lua_State* L;
int index;
int returncount;
int popcount;
call_error error;
template <typename T, std::size_t I>
@ -53,7 +54,7 @@ private:
public:
function_result() = default;
function_result(lua_State* L, int index = -1, int returncount = 0, call_error error = call_error::ok): L(L), index(index), returncount(returncount), error(error) {
function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_error error = call_error::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) {
}
function_result(const function_result&) = default;
@ -65,6 +66,7 @@ public:
o.L = nullptr;
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_error::runtime;
}
function_result& operator=(function_result&& o) {
@ -78,6 +80,7 @@ public:
o.L = nullptr;
o.index = 0;
o.returncount = 0;
o.popcount = 0;
o.error = call_error::runtime;
return *this;
}
@ -102,11 +105,92 @@ public:
}
~function_result() {
stack::remove(L, index, error == call_error::ok ? returncount : 1);
stack::remove(L, index, popcount);
}
};
class function : public reference {
class fast_function : public reference {
private:
void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const {
lua_callk( lua_state( ), static_cast<int>( argcount ), static_cast<int>( resultcount ), 0, nullptr );
}
template<std::size_t... I, typename... Ret>
std::tuple<Ret...> invoke( indices<I...>, types<Ret...>, std::ptrdiff_t n ) const {
luacall( n, sizeof...( Ret ), h );
int nreturns = static_cast<int>( sizeof...( Ret ) );
int stacksize = lua_gettop( lua_state( ) );
int firstreturn = std::max( 0, stacksize - nreturns ) + 1;
auto r = std::make_tuple( stack::get<Ret>( lua_state( ), firstreturn + I )... );
lua_pop( lua_state( ), nreturns );
return r;
}
template<std::size_t I, typename Ret>
Ret invoke( indices<I>, types<Ret>, std::ptrdiff_t n ) const {
luacall( n, 1 );
return stack::pop<Ret>( lua_state( ) );
}
template <std::size_t I>
void invoke( indices<I>, types<void>, std::ptrdiff_t n ) const {
luacall( n, 0 );
}
function_result invoke( indices<>, types<>, std::ptrdiff_t n ) const {
int stacksize = lua_gettop( lua_state( ) );
int firstreturn = std::max( 0, stacksize - static_cast<int>( n ) - 1 );
int poststacksize = 0;
int returncount = 0;
try {
luacall( n, LUA_MULTRET );
poststacksize = lua_gettop( lua_state( ) );
returncount = poststacksize - firstreturn;
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch ( const std::exception& error ) {
stack::push( lua_state( ), error.what( ) );
return function_result( lua_state( ), firstreturn, 0, 1, call_error::runtime );
}
catch ( ... ) {
throw;
}
return function_result( lua_state( ), firstreturn, returncount, returncount, call_error::ok );
}
public:
fast_function( ) = default;
fast_function( lua_State* L, int index = -1 ) : reference( L, index ) {
type_assert( L, index, type::function );
}
fast_function( const fast_function& ) = default;
fast_function& operator=( const fast_function& ) = default;
fast_function( fast_function&& ) = default;
fast_function& operator=( fast_function&& ) = default;
template<typename... Args>
function_result operator()( Args&&... args ) const {
return call<>( std::forward<Args>( args )... );
}
template<typename... Ret, typename... Args>
auto operator()( types<Ret...>, Args&&... args ) const
-> decltype( invoke( types<Ret...>( ), types<Ret...>( ), 0, std::declval<handler&>( ) ) ) {
return call<Ret...>( std::forward<Args>( args )... );
}
template<typename... Ret, typename... Args>
auto call( Args&&... args ) const
-> decltype( invoke( types<Ret...>( ), types<Ret...>( ), 0 ) ) {
push( );
int pushcount = stack::push_args( lua_state( ), std::forward<Args>( args )... );
auto tr = types<Ret...>( );
return invoke( tr, tr, pushcount );
}
};
class safe_function : public reference {
private:
static reference& handler_storage() {
static sol::reference h;
@ -125,34 +209,30 @@ public:
private:
struct handler {
const reference& target;
int stack;
handler(const reference& target) : target(target), stack(0) {
int stackindex;
handler(const reference& target) : target(target), stackindex(0) {
if (target.valid()) {
stack = lua_gettop(target.lua_state()) + 1;
stackindex = lua_gettop(target.lua_state()) + 1;
target.push();
}
}
~handler() {
if (stack > 0) {
lua_remove(target.lua_state(), stack);
if (stackindex > 0) {
lua_remove(target.lua_state(), stackindex);
}
}
};
int luacodecall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const {
return lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stack, 0, nullptr);
}
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const {
lua_callk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
int luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const {
return lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr);
}
template<std::size_t... I, typename... Ret>
std::tuple<Ret...> invoke(indices<I...>, types<Ret...>, std::ptrdiff_t n, handler& h) const {
luacall(n, sizeof...(Ret), h);
const int nreturns = static_cast<int>(sizeof...(Ret));
const int stacksize = lua_gettop(lua_state());
const int firstreturn = std::max(0, stacksize - nreturns) + 1;
int nreturns = static_cast<int>(sizeof...(Ret));
int stacksize = lua_gettop(lua_state());
int firstreturn = std::max(0, stacksize - nreturns) + 1;
auto r = std::make_tuple(stack::get<Ret>(lua_state(), firstreturn + I)...);
lua_pop(lua_state(), nreturns);
return r;
@ -170,51 +250,41 @@ private:
}
function_result invoke(indices<>, types<>, std::ptrdiff_t n, handler& h) const {
const bool handlerpushed = error_handler.valid();
const int stacksize = lua_gettop(lua_state());
const int firstreturn = std::max(0, stacksize - static_cast<int>(n) - 1);
int code = LUA_OK;
bool handlerpushed = error_handler.valid();
int stacksize = lua_gettop(lua_state());
int firstreturn = std::max(0, stacksize - static_cast<int>(n) - 1);
int returncount = 0;
call_error code = call_error::ok;
try {
code = luacodecall(n, LUA_MULTRET, h);
}
code = static_cast<call_error>(luacall(n, LUA_MULTRET, h));
int poststacksize = lua_gettop( lua_state( ) );
returncount = poststacksize - firstreturn;
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch (const std::exception& error) {
code = LUA_ERRRUN;
h.stack = 0;
code = call_error::runtime;
h.stackindex = 0;
stack::push(lua_state(), error.what());
}
// TODO: handle idiots?
/*catch (const char* error) {
code = LUA_ERRRUN;
stack::push(lua_state(), error);
}
catch (const std::string& error) {
code = LUA_ERRRUN;
stack::push(lua_state(), error);
}
catch (...) {
code = LUA_ERRRUN;
stack::push( lua_state(), "[sol] an unknownable runtime exception occurred" );
}*/
return function_result( lua_state( ), firstreturn, 0, 1, call_error::runtime );
}
catch (...) {
throw;
}
const int poststacksize = lua_gettop(lua_state());
const int returncount = poststacksize - firstreturn;
return function_result(lua_state(), firstreturn + ( handlerpushed ? 0 : 1 ), returncount, static_cast<call_error>(code));
return function_result(lua_state(), firstreturn + ( handlerpushed ? 0 : 1 ), returncount, returncount, code);
}
public:
sol::reference error_handler;
function() = default;
function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) {
safe_function() = default;
safe_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) {
type_assert(L, index, type::function);
}
function(const function&) = default;
function& operator=(const function&) = default;
function( function&& ) = default;
function& operator=( function&& ) = default;
safe_function(const safe_function&) = default;
safe_function& operator=(const safe_function&) = default;
safe_function( safe_function&& ) = default;
safe_function& operator=( safe_function&& ) = default;
template<typename... Args>
function_result operator()(Args&&... args) const {
@ -234,7 +304,7 @@ public:
push();
int pushcount = stack::push_args(lua_state(), std::forward<Args>(args)...);
auto tr = types<Ret...>();
return invoke(tr, tr, pushcount, h);
return invoke( tr, tr, pushcount, h );
}
};

View File

@ -125,7 +125,9 @@ template <bool>
class table_core;
typedef table_core<false> table;
typedef table_core<true> global_table;
class function;
class fast_function;
class safe_function;
typedef safe_function function;
class object;
template <typename T, typename = void>