Add benchmark.cpp and timer related support files

git-svn-id: http://svn.boost.org/svn/boost/sandbox/endian@74296 b8fc166d-592f-0410-95f2-cb63ce0dd405
This commit is contained in:
bemandawes
2011-09-07 13:24:21 +00:00
parent 50f08cac6f
commit 4955da9ba5
8 changed files with 726 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
// boost/endian/detail/config.hpp ----------------------------------------------------//
// Copyright Beman Dawes 2003, 2010
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//--------------------------------------------------------------------------------------//
#ifndef BOOST_ENDIAN_CONFIG_HPP
#define BOOST_ENDIAN_CONFIG_HPP
// This header implements separate compilation features as described in
// http://www.boost.org/more/separate_compilation.html
#include <boost/config.hpp>
#include <boost/system/api_config.hpp> // for BOOST_POSIX_API or BOOST_WINDOWS_API
// throw an exception ----------------------------------------------------------------//
//
// Exceptions were originally thrown via boost::throw_exception().
// As throw_exception() became more complex, it caused user error reporting
// to be harder to interpret, since the exception reported became much more complex.
// The immediate fix was to throw directly, wrapped in a macro to make any later change
// easier.
#define BOOST_ENDIAN_THROW(EX) throw EX
// enable dynamic linking -------------------------------------------------------------//
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_ENDIAN_DYN_LINK)
# if defined(BOOST_ENDIAN_SOURCE)
# define BOOST_ENDIAN_DECL BOOST_SYMBOL_EXPORT
# else
# define BOOST_ENDIAN_DECL BOOST_SYMBOL_IMPORT
# endif
#else
# define BOOST_ENDIAN_DECL
#endif
// enable automatic library variant selection ----------------------------------------//
#if !defined(BOOST_ENDIAN_SOURCE) && !defined(BOOST_ALL_NO_LIB) \
&& !defined(BOOST_ENDIAN_NO_LIB)
//
// Set the name of our library, this will get undef'ed by auto_link.hpp
// once it's done with it:
//
#define BOOST_LIB_NAME boost_endian
//
// If we're importing code from a dll, then tell auto_link.hpp about it:
//
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_ENDIAN_DYN_LINK)
# define BOOST_DYN_LINK
#endif
//
// And include the header that does the work:
//
#include <boost/config/auto_link.hpp>
#endif // auto-linking disabled
#endif // BOOST_ENDIAN_CONFIG_HPP

View File

@@ -0,0 +1,118 @@
// boost timer.hpp ---------------------------------------------------------//
// Copyright Beman Dawes 1994-2007
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
// See http://www.boost.org/libs/system for documentation.
#ifndef BOOST_ENDIAN_TIMER_HPP
#define BOOST_ENDIAN_TIMER_HPP
#include <boost/config/warning_disable.hpp>
#include <boost/endian/detail/config.hpp>
#include <boost/system/error_code.hpp>
#include <boost/cstdint.hpp>
#include <string>
#include <cstring>
#include <ostream>
#include <boost/config/abi_prefix.hpp> // must be the last #include
namespace boost
{
namespace endian
{
typedef boost::int_least64_t microsecond_t;
struct times_t
{
microsecond_t wall;
microsecond_t user;
microsecond_t system;
void clear() { wall = user = system = 0LL; }
};
// low-level functions -------------------------------------------------//
BOOST_ENDIAN_DECL
void times(times_t& result); // throws on error
BOOST_ENDIAN_DECL
system::error_code& times(times_t& result, system::error_code& ec); // never throws
// timer ---------------------------------------------------------------//
// unless otherwise specified, all functions throw on error
class BOOST_ENDIAN_DECL timer
{
public:
timer() : m_flags(m_stopped) { start(); }
timer(const std::nothrow_t&) : m_flags(static_cast<m_flags_t>(m_stopped
| m_nothrow)) { start(); }
~timer() {} // never throws
void start();
const times_t& stop();
bool stopped() const { return m_flags& m_stopped; }
void elapsed(times_t& result); // does not stop()
private:
times_t m_times;
enum m_flags_t { m_stopped=1, m_nothrow=2 };
m_flags_t m_flags;
};
// run_timer -----------------------------------------------------------//
// unless otherwise specified, all functions throw on error
class BOOST_ENDIAN_DECL run_timer : public timer
{
public:
// each constructor has two overloads to avoid an explicit default to
// std::cout, which in turn would require including <iostream> with its
// high associated cost even when the standard streams are not used.
explicit run_timer(int places = 2);
run_timer(int places, std::ostream& os)
: m_places(places), m_os(os), m_format(0) {}
explicit run_timer(const std::string& format, int places = 2);
run_timer(const std::string& format, int places, std::ostream& os)
: m_places(places), m_os(os), m_format(new char[format.size()+1])
{ std::strcpy(m_format, format.c_str()); }
~run_timer() // never throws
{
system::error_code ec;
if(!stopped())
report(ec);
delete [] m_format;
}
void report();
system::error_code
report(system::error_code& ec); // never throws
private:
int m_places;
std::ostream& m_os;
char* m_format; // doesn't use std::string as VC++ too painful
// across DLL boundaries due to warning C4251
};
} // namespace endian
} // namespace boost
#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
#endif // BOOST_ENDIAN_TIMER_HPP

View File

@@ -0,0 +1,132 @@
// boost run_timer.cpp -----------------------------------------------------//
// Copyright Beman Dawes 1994-2006
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org/libs/system for documentation.
//----------------------------------------------------------------------------//
// define BOOST_ENDIAN_SOURCE so that <boost/endian/detail/config.hpp> knows
// the library is being built (possibly exporting rather than importing code)
#define BOOST_ENDIAN_SOURCE
#include <boost/endian/support/timer.hpp>
#include <boost/system/system_error.hpp>
#include <boost/io/ios_state.hpp>
#include <boost/throw_exception.hpp>
#include <boost/cerrno.hpp>
#include <cstring>
#include <cassert>
using boost::endian::microsecond_t;
using boost::endian::times_t;
using boost::system::error_code;
# if defined(BOOST_WINDOWS_API)
# include <windows.h>
# elif defined(BOOST_POSIX_API)
# include <sys/times.h>
# else
# error unknown API
# endif
namespace
{
const char * default_format =
" %ws wall, %us user + %ss system = %ts cpu (%p%)\n";
void show_time(const char * format, int places, std::ostream& os,
const times_t& times)
// NOTE WELL: Will truncate least-significant digits to LDBL_DIG, which may
// be as low as 10, although will be 15 for many common platforms.
{
if (times.wall < microsecond_t(0))
return;
if (places > 6)
places = 6;
else if (places < 0)
places = 0;
boost::io::ios_flags_saver ifs(os);
boost::io::ios_precision_saver ips(os);
os.setf(std::ios_base::fixed, std::ios_base::floatfield);
os.precision(places);
const long double sec = 1000000.0L;
microsecond_t total = times.system + times.user;
long double wall_sec = times.wall / sec;
long double total_sec = total / sec;
for (; *format; ++format)
{
if (*format != '%' || !*(format+1) || !std::strchr("wustp", *(format+1)))
os << *format;
else
{
++format;
switch (*format)
{
case 'w':
os << times.wall / sec;
break;
case 'u':
os << times.user / sec;
break;
case 's':
os << times.system / sec;
break;
case 't':
os << total / sec;
break;
case 'p':
os.precision(1);
if (wall_sec > 0.001L && total_sec > 0.001L)
os << (total_sec/wall_sec) * 100.0;
else
os << "n/a";
os.precision(places);
break;
default:
assert(0);
}
}
}
}
} // unnamed namespace
namespace boost
{
namespace endian
{
// run_timer:: report --------------------------------------//
void run_timer::report()
{
show_time(!m_format
? default_format
: m_format,
m_places, m_os, this->stop());
}
error_code run_timer::report(error_code& ec)
{
try
{
report();
ec = error_code();
}
catch (...) // eat any exceptions
{
ec = error_code(EIO, system::generic_category());
}
return ec;
}
} // namespace endian
} // namespace boost

View File

@@ -0,0 +1,38 @@
// boost run_timer_ctors.cpp -----------------------------------------------//
// Copyright Beman Dawes 2007
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org/libs/system for documentation.
//----------------------------------------------------------------------------//
// These constructors are in a separate file so that this translation unit will
// not be linked in except when one of the constructors is actually used. This
// is important since header <iostream> is required, and it incurs the cost of
// the standard stream objects even if they are not used.
//----------------------------------------------------------------------------//
// define BOOST_ENDIAN_SOURCE so that <boost/endian/detail/config.hpp> knows
// the library is being built (possibly exporting rather than importing code)
#define BOOST_ENDIAN_SOURCE
#include <boost/endian/support/timer.hpp>
#include <iostream>
namespace boost
{
namespace endian
{
run_timer::run_timer(int places)
: m_places(places), m_os(std::cout), m_format(0) {}
run_timer::run_timer(const std::string& format, int places)
: m_places(places), m_os(std::cout), m_format(new char[format.size()+1])
{ std::strcpy(m_format, format.c_str()); }
} // namespace endian
} // namespace boost

View File

@@ -0,0 +1,167 @@
// boost timer.cpp ---------------------------------------------------------//
// Copyright Beman Dawes 1994-2006
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org/libs/system for documentation.
//----------------------------------------------------------------------------//
// define BOOST_ENDIAN_SOURCE so that <boost/system/config.hpp> knows
// the library is being built (possibly exporting rather than importing code)
#define BOOST_ENDIAN_SOURCE
#include <boost/endian/support/timer.hpp>
#include <boost/system/system_error.hpp>
#include <boost/io/ios_state.hpp>
#include <boost/throw_exception.hpp>
#include <boost/cerrno.hpp>
#include <cstring>
#include <cassert>
# if defined(BOOST_WINDOWS_API)
# include <windows.h>
# elif defined(BOOST_POSIX_API)
# include <unistd.h>
# include <sys/times.h>
# else
# error unknown API
# endif
using boost::system::error_code;
# if defined(BOOST_POSIX_API)
namespace
{
long tick_factor() // multiplier to convert ticks
// to microseconds; -1 if unknown
{
static long tick_factor = 0;
if (!tick_factor)
{
if ((tick_factor = ::sysconf(_SC_CLK_TCK)) <= 0)
tick_factor = -1;
else
{
assert(tick_factor <= 1000000L); // doesn't handle large ticks
tick_factor = 1000000L / tick_factor; // compute factor
if (!tick_factor) tick_factor = -1;
}
}
return tick_factor;
}
} // unnamed namespace
# endif
namespace boost
{
namespace endian
{
BOOST_ENDIAN_DECL
void times(times_t& current)
{
error_code ec;
if (times(current, ec))
boost::throw_exception(system::system_error(ec, "boost::endian::times"));
}
BOOST_ENDIAN_DECL
error_code& times(times_t& current, error_code& ec)
{
ec = error_code();
# if defined(BOOST_WINDOWS_API)
::GetSystemTimeAsFileTime((LPFILETIME)&current.wall);
FILETIME creation, exit;
if (::GetProcessTimes(::GetCurrentProcess(), &creation, &exit,
(LPFILETIME)&current.system, (LPFILETIME)&current.user))
{
current.wall /= 10; // Windows uses 100 nanosecond ticks
current.user /= 10;
current.system /= 10;
}
else
{
ec = error_code(::GetLastError(), system::system_category());
current.wall = current.system = current.user = microsecond_t(-1);
}
# else
tms tm;
clock_t c = ::times(&tm);
if (c == -1) // error
{
ec = error_code(errno, system::system_category());
current.wall = current.system = current.user = microsecond_t(-1);
}
else
{
current.wall = microsecond_t(c);
current.system = microsecond_t(tm.tms_stime + tm.tms_cstime);
current.user = microsecond_t(tm.tms_utime + tm.tms_cutime);
if (tick_factor() != -1)
{
current.wall *= tick_factor();
current.user *= tick_factor();
current.system *= tick_factor();
}
else
{
ec = error_code(errno, system::system_category());
current.wall = current.user = current.system = microsecond_t(-1);
}
}
# endif
return ec;
}
#define BOOST_TIMES(C) \
if (m_flags& m_nothrow) \
{ \
error_code ec; \
times(C, ec); \
} \
else \
times(C);
// timer ---------------------------------------------------------------//
void timer::start()
{
m_flags = static_cast<m_flags_t>(m_flags& ~m_stopped);
BOOST_TIMES(m_times);
}
const times_t& timer::stop()
{
if (stopped()) return m_times;
m_flags = static_cast<m_flags_t>(m_flags | m_stopped);
times_t current;
BOOST_TIMES(current);
m_times.wall = (current.wall - m_times.wall);
m_times.user = (current.user - m_times.user);
m_times.system = (current.system - m_times.system);
return m_times;
}
void timer::elapsed(times_t& current)
{
if (stopped())
{
current.wall = m_times.wall;
current.user = m_times.user;
current.system = m_times.system;
}
else
{
BOOST_TIMES(current);
current.wall -= m_times.wall;
current.user -= m_times.user;
current.system -= m_times.system;
}
}
} // namespace endian
} // namespace boost

View File

@@ -0,0 +1,107 @@
// benchmark.cpp ---------------------------------------------------------------------//
// Copyright Beman Dawes 2011
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
#define _CRT_SECURE_NO_WARNINGS
#include <boost/endian/conversion.hpp>
#include <boost/random.hpp>
#include <boost/cstdint.hpp>
#include <boost/endian/support/timer.hpp>
#include <iostream>
using namespace boost;
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
#define BENCHMARK(Function) \
{ \
cout << "\nRunning benchmark..." << endl << ' '; \
int64_t sum = 0; \
int32_t value; \
\
endian::run_timer t; \
\
for (int32_t i = n; i; --i) \
{ \
value = 0x01020304; \
Function(value); \
sum += value ; \
} \
\
t.report(); \
\
cout << " Benchmark complete\n" \
" sum is " << sum << endl; \
}
namespace
{
std::string command_args;
long n;
long seed = 1;
int places = 2;
void process_command_line(int argc, char * argv[])
{
for (int a = 0; a < argc; ++a)
{
command_args += argv[a];
if (a != argc-1)
command_args += ' ';
}
cout << command_args << '\n';;
if (argc >=2)
n = std::atol(argv[1]);
for (; argc > 2; ++argv, --argc)
{
if ( *(argv[2]+1) == 'p' )
places = atoi( argv[2]+2 );
else
{
cout << "Error - unknown option: " << argv[2] << "\n\n";
argc = -1;
break;
}
}
if (argc < 2)
{
cout << "Usage: benchmark n [Options]\n"
" The argument n specifies the number of test cases to run\n"
" Options:\n"
" -p# Decimal places for times; default -p" << places << "\n";
return std::exit(1);
}
}
inline void noop(int32_t&) {}
inline void shift_and_mask(int32_t& x)
{
x = ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) | ((x >> 24) & 0x000000ff)
| ((x >> 8) & 0x0000ff00);
}
} // unnamed namespace
//-------------------------------------- main() ---------------------------------------//
int main(int argc, char * argv[])
{
process_command_line(argc, argv);
BENCHMARK(noop);
BENCHMARK(endian::reorder);
BENCHMARK(shift_and_mask);
return 0;
}

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C9FEAE75-4DD9-44F5-B302-9910559A91BE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>benchmark</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>BOOST_ALL_NO_LIB;BOOST_ALL_DYN_LINK;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>d:\endian\stage\lib</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>"$(TargetDir)\$(TargetName).exe" 100</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>BOOST_ALL_NO_LIB;BOOST_ALL_DYN_LINK;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>d:\endian\stage\lib</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>"$(TargetDir)\$(TargetName).exe" 100000</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\system\src\error_code.cpp" />
<ClCompile Include="..\..\..\support\run_timer.cpp" />
<ClCompile Include="..\..\..\support\run_timer_ctors.cpp" />
<ClCompile Include="..\..\..\support\timer.cpp" />
<ClCompile Include="..\..\benchmark.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -13,6 +13,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "endian_example", "endian_ex
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "conversion_test", "conversion_test\conversion_test.vcxproj", "{9FA33B0B-2B00-49E8-A892-E049D86076A9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "benchmark", "benchmark\benchmark.vcxproj", "{C9FEAE75-4DD9-44F5-B302-9910559A91BE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -43,6 +45,10 @@ Global
{9FA33B0B-2B00-49E8-A892-E049D86076A9}.Debug|Win32.Build.0 = Debug|Win32
{9FA33B0B-2B00-49E8-A892-E049D86076A9}.Release|Win32.ActiveCfg = Release|Win32
{9FA33B0B-2B00-49E8-A892-E049D86076A9}.Release|Win32.Build.0 = Release|Win32
{C9FEAE75-4DD9-44F5-B302-9910559A91BE}.Debug|Win32.ActiveCfg = Debug|Win32
{C9FEAE75-4DD9-44F5-B302-9910559A91BE}.Debug|Win32.Build.0 = Debug|Win32
{C9FEAE75-4DD9-44F5-B302-9910559A91BE}.Release|Win32.ActiveCfg = Release|Win32
{C9FEAE75-4DD9-44F5-B302-9910559A91BE}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE