Last active
August 29, 2015 14:14
-
-
Save sehe/54caed4b4cd7c9352174 to your computer and use it in GitHub Desktop.
benchmarking http://stackoverflow.com/questions/28254996/variadic-boost-bind-type-resolution/28257074#28257074
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Language: Cpp | |
# BasedOnStyle: LLVM | |
AccessModifierOffset: -2 | |
ConstructorInitializerIndentWidth: 8 | |
AlignEscapedNewlinesLeft: false | |
AlignTrailingComments: true | |
AllowAllParametersOfDeclarationOnNextLine: true | |
AllowShortIfStatementsOnASingleLine: false | |
AllowShortLoopsOnASingleLine: false | |
AllowShortFunctionsOnASingleLine: true | |
AlwaysBreakTemplateDeclarations: false | |
AlwaysBreakBeforeMultilineStrings: false | |
BreakBeforeBinaryOperators: false | |
BreakBeforeTernaryOperators: true | |
BreakConstructorInitializersBeforeComma: false | |
BinPackParameters: true | |
ColumnLimit: 120 | |
ConstructorInitializerAllOnOneLineOrOnePerLine: false | |
DerivePointerBinding: false | |
ExperimentalAutoDetectBinPacking: false | |
IndentCaseLabels: false | |
MaxEmptyLinesToKeep: 1 | |
NamespaceIndentation: None | |
ObjCSpaceAfterProperty: false | |
ObjCSpaceBeforeProtocolList: true | |
PenaltyBreakBeforeFirstCallParameter: 19 | |
PenaltyBreakComment: 300 | |
PenaltyBreakString: 1000 | |
PenaltyBreakFirstLessLess: 120 | |
PenaltyExcessCharacter: 1000000 | |
PenaltyReturnTypeOnItsOwnLine: 60 | |
PointerBindsToType: false | |
SpacesBeforeTrailingComments: 1 | |
Cpp11BracedListStyle: false | |
Standard: Cpp03 | |
IndentWidth: 4 | |
TabWidth: 4 | |
UseTab: Never | |
BreakBeforeBraces: Attach | |
IndentFunctionDeclarationAfterType: false | |
SpacesInParentheses: false | |
SpacesInAngles: false | |
SpaceInEmptyParentheses: false | |
SpacesInCStyleCastParentheses: false | |
SpacesInContainerLiterals: true | |
SpaceBeforeAssignmentOperators: true | |
ContinuationIndentWidth: 4 | |
CommentPragmas: '^ IWYU pragma:' | |
SpaceBeforeParens: ControlStatements | |
... | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file is NOT licensed under the GPLv3, which is the license for the rest | |
# of YouCompleteMe. | |
# | |
# Here's the license text for this file: | |
# | |
# This is free and unencumbered software released into the public domain. | |
# | |
# Anyone is free to copy, modify, publish, use, compile, sell, or | |
# distribute this software, either in source code form or as a compiled | |
# binary, for any purpose, commercial or non-commercial, and by any | |
# means. | |
# | |
# In jurisdictions that recognize copyright laws, the author or authors | |
# of this software dedicate any and all copyright interest in the | |
# software to the public domain. We make this dedication for the benefit | |
# of the public at large and to the detriment of our heirs and | |
# successors. We intend this dedication to be an overt act of | |
# relinquishment in perpetuity of all present and future rights to this | |
# software under copyright law. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
# OTHER DEALINGS IN THE SOFTWARE. | |
# | |
# For more information, please refer to <http://unlicense.org/> | |
import os | |
import ycm_core | |
# These are the compilation flags that will be used in case there's no | |
# compilation database set (by default, one is not set). | |
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. | |
flags = [ | |
'-Wall', | |
'-Wextra', | |
'-Wno-variadic-macros', | |
'-fexceptions', | |
'-DNDEBUG', | |
'-DUNIT_TESTS', | |
'-std=c++11', | |
'-x', 'c++', | |
'-isystem', '/home/sehe/custom/boost', | |
'-isystem', '/usr/lib/gcc/x86_64-linux-gnu/4.8/include', | |
'-I', 'src', | |
'-I', 'include', | |
'-I', '/home/sehe/custom/nonius/include', | |
'-isystem', '/usr/include', | |
'-isystem', '/usr/local/include', | |
] | |
# Set this to the absolute path to the folder (NOT the file!) containing the | |
# compile_commands.json file to use that instead of 'flags'. See here for | |
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html | |
# | |
# Most projects will NOT need to set this to anything; you can just change the | |
# 'flags' list of compilation flags. Notice that YCM itself uses that approach. | |
compilation_database_folder = '' | |
if os.path.exists( compilation_database_folder ): | |
database = ycm_core.CompilationDatabase( compilation_database_folder ) | |
else: | |
database = None | |
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm', '*.cs' ] | |
def DirectoryOfThisScript(): | |
return os.path.dirname( os.path.abspath( __file__ ) ) | |
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): | |
if not working_directory: | |
return list( flags ) | |
new_flags = [] | |
make_next_absolute = False | |
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] | |
for flag in flags: | |
new_flag = flag | |
if make_next_absolute: | |
make_next_absolute = False | |
if not flag.startswith( '/' ): | |
new_flag = os.path.join( working_directory, flag ) | |
for path_flag in path_flags: | |
if flag == path_flag: | |
make_next_absolute = True | |
break | |
if flag.startswith( path_flag ): | |
path = flag[ len( path_flag ): ] | |
new_flag = path_flag + os.path.join( working_directory, path ) | |
break | |
if new_flag: | |
new_flags.append( new_flag ) | |
return new_flags | |
def IsHeaderFile( filename ): | |
extension = os.path.splitext( filename )[ 1 ] | |
return extension in [ '.h', '.hxx', '.hpp', '.hh' ] | |
def GetCompilationInfoForFile( filename ): | |
# The compilation_commands.json file generated by CMake does not have entries | |
# for header files. So we do our best by asking the db for flags for a | |
# corresponding source file, if any. If one exists, the flags for that file | |
# should be good enough. | |
if IsHeaderFile( filename ): | |
basename = os.path.splitext( filename )[ 0 ] | |
for extension in SOURCE_EXTENSIONS: | |
replacement_file = basename + extension | |
if os.path.exists( replacement_file ): | |
compilation_info = database.GetCompilationInfoForFile( | |
replacement_file ) | |
if compilation_info.compiler_flags_: | |
return compilation_info | |
return None | |
return database.GetCompilationInfoForFile( filename ) | |
def FlagsForFile( filename, **kwargs ): | |
if database: | |
# Bear in mind that compilation_info.compiler_flags_ does NOT return a | |
# python list, but a "list-like" StringVec object | |
compilation_info = GetCompilationInfoForFile( filename ) | |
if not compilation_info: | |
return None | |
final_flags = MakeRelativePathsInFlagsAbsolute( | |
compilation_info.compiler_flags_, | |
compilation_info.compiler_working_dir_ ) | |
# NOTE: This is just for YouCompleteMe; it's highly likely that your project | |
# does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR | |
# ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. | |
try: | |
final_flags.remove( '-stdlib=libc++' ) | |
except ValueError: | |
pass | |
else: | |
relative_to = DirectoryOfThisScript() | |
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) | |
return { | |
'flags': final_flags, | |
'do_cache': True | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/thread/thread.hpp> | |
#include <boost/atomic.hpp> | |
#include <atomic> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <string> | |
#include <cstdio> | |
#include <sched.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/syscall.h> | |
#include <boost/scoped_ptr.hpp> | |
#include <sys/time.h> | |
#include <boost/lexical_cast.hpp> | |
#include "optional_nonius.hpp" | |
void setThreadAffinity(boost::thread * const bt, int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
pthread_setaffinity_np(bt->native_handle(),sizeof(cst),&cst); | |
} | |
void setThreadAffinity(int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
sched_setaffinity(0,sizeof(cst),&cst); | |
} | |
struct Log{ | |
public: | |
Log(std::string const & logFileName, int32_t coreNumber, int32_t queueSize) | |
: logFileName(logFileName), lock(ATOMIC_FLAG_INIT) | |
{ | |
#ifdef NONIUS | |
fp = std::fopen(logFileName.c_str(), "w"); | |
#else | |
fp = stderr; //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
std::atomic_store_explicit(&this->flag,true,std::memory_order_release); | |
this->q.reset(new boost::lockfree::spsc_queue<std::string>(queueSize)); | |
this->thrd.reset(new boost::thread(&Log::pop,this)); | |
setThreadAffinity(this->thrd.get(),coreNumber); | |
} | |
void pop(){ | |
// setThreadAffinity(this->coreNumber); | |
std::string s; | |
s.reserve(1000); | |
struct timeval ts; | |
while (std::atomic_load_explicit(&this->flag,std::memory_order_acquire)){ | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
std::fflush(this->fp); | |
} | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
} | |
void push(std::string const & s){ | |
while (std::atomic_flag_test_and_set_explicit(&this->lock,std::memory_order_acquire)); | |
while (!this->q->push(s)); | |
std::atomic_flag_clear_explicit(&this->lock,std::memory_order_release); | |
} | |
~Log(){ | |
std::atomic_store_explicit(&this->flag,false,std::memory_order_release); | |
this->thrd->join(); | |
std::fflush(this->fp); | |
std::fclose(this->fp); | |
this->fp = NULL; | |
} | |
private: | |
Log(){} | |
std::string logFileName; | |
boost::scoped_ptr<boost::lockfree::spsc_queue<std::string> > q; | |
boost::scoped_ptr<boost::thread> thrd; | |
std::atomic<bool> flag; | |
std::atomic_flag lock; | |
FILE * fp; | |
}; | |
// this is the piece of code that achieves the best time -> about 2-3 microseconds for this single print on the server i use | |
NONIUS_BENCHMARK("direct-simple", [](nonius::chronometer meter) { | |
Log l("/dev/null",15,1024); | |
for (size_t i=0; i<10; ++i) l.push("warm up maybe"); | |
meter.measure([&](int) { | |
std::string s("let's log this long line"); | |
l.push(s); | |
}); | |
}) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/thread/thread.hpp> | |
#include <boost/atomic.hpp> | |
#include <atomic> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <string> | |
#include <cstdio> | |
#include <sched.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/syscall.h> | |
#include <boost/scoped_ptr.hpp> | |
#include <sys/time.h> | |
#include <boost/lexical_cast.hpp> | |
#include "optional_nonius.hpp" | |
void setThreadAffinity(boost::thread * const bt, int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
pthread_setaffinity_np(bt->native_handle(),sizeof(cst),&cst); | |
} | |
void setThreadAffinity(int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
sched_setaffinity(0,sizeof(cst),&cst); | |
} | |
struct Log{ | |
public: | |
Log(std::string const & logFileName, int32_t coreNumber, int32_t queueSize) | |
: logFileName(logFileName), lock(ATOMIC_FLAG_INIT) | |
{ | |
#ifdef NONIUS | |
fp = std::fopen(logFileName.c_str(), "w"); | |
#else | |
fp = stderr; //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
std::atomic_store_explicit(&this->flag,true,std::memory_order_release); | |
this->q.reset(new boost::lockfree::spsc_queue<std::string>(queueSize)); | |
this->thrd.reset(new boost::thread(&Log::pop,this)); | |
setThreadAffinity(this->thrd.get(),coreNumber); | |
} | |
void pop(){ | |
// setThreadAffinity(this->coreNumber); | |
std::string s; | |
s.reserve(1000); | |
struct timeval ts; | |
while (std::atomic_load_explicit(&this->flag,std::memory_order_acquire)){ | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
std::fflush(this->fp); | |
} | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
} | |
template <typename T> | |
inline __attribute__((always_inline)) std::string stringer(T const & t){ | |
return boost::lexical_cast<std::string>(t); | |
} | |
template<typename T, typename ... Args> | |
inline __attribute__((always_inline)) | |
std::string stringer(T const & t, Args const & ... args){ | |
return stringer(t) + stringer(args...); | |
} | |
template<typename T, typename ... Args> | |
inline __attribute__((always_inline)) void enqueue(T const& t, Args const & ... args){ | |
this->push(stringer(t, args...)); | |
} | |
void push(std::string const & s){ | |
while (std::atomic_flag_test_and_set_explicit(&this->lock,std::memory_order_acquire)); | |
while (!this->q->push(s)); | |
std::atomic_flag_clear_explicit(&this->lock,std::memory_order_release); | |
} | |
~Log(){ | |
std::atomic_store_explicit(&this->flag,false,std::memory_order_release); | |
this->thrd->join(); | |
std::fflush(this->fp); | |
std::fclose(this->fp); | |
this->fp = NULL; | |
} | |
private: | |
Log(){} | |
std::string logFileName; | |
boost::scoped_ptr<boost::lockfree::spsc_queue<std::string> > q; | |
boost::scoped_ptr<boost::thread> thrd; | |
std::atomic<bool> flag; | |
std::atomic_flag lock; | |
FILE * fp; | |
}; | |
// this is the piece of code that achieves the best time -> about 2-3 microseconds for this single print on the server i use | |
NONIUS_BENCHMARK("direct-variadic", [](nonius::chronometer meter) { | |
std::string const a_s("let's log this long line"); | |
double a_d(atan(1)*4); | |
const char* const a_l = "literal"; | |
Log l("/dev/null",15,1024); | |
// warmup | |
for (size_t i=0; i<10; ++i) l.enqueue(a_s, a_d, i, a_l); | |
meter.measure([&](int i) { | |
switch (i%3) { | |
case 0: l.enqueue(a_s, a_d, i, a_l); break; | |
case 1: l.enqueue(a_s, a_l, a_d, i); break; | |
case 2: l.enqueue(a_d, i, a_l); break; | |
} | |
}); | |
}) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SHELL=/bin/bash | |
TARGETS+=mine-simple direct-simple service-simple | |
TARGETS+=mine-variadic service-variadic direct-variadic | |
# wip | |
TARGETS+=smart-lambda subnano | |
all: nonius test | |
nonius:$(patsubst %,build/nonius/%,$(TARGETS)) | |
html:$(patsubst %,build/nonius/%.html,$(TARGETS)) | |
test:$(patsubst %,build/test/%,$(TARGETS)) | |
text:$(patsubst %,build/nonius/%.txt,$(TARGETS)) | |
bench: html text | |
upload:bench | |
rsync build/nonius/*.{html,txt} *.cpp www-data@koolu:downloads/stackoverflow/q28254996/ | |
rsync build/nonius/*.{html,txt} *.cpp www-data@linode:downloads/stackoverflow/q28254996/ | |
CPPFLAGS+=-std=c++11 -Wall -pedantic | |
CPPFLAGS+=-g -O3 | |
CPPFLAGS+=-isystem ~/custom/boost/ | |
CPPFLAGS+=-I ~/custom/nonius/include | |
CPPFLAGS+=-pthread | |
CPPFLAGS+=-DNDEBUG | |
# CPPFLAGS+=-fopenmp | |
CPPFLAGS+=-march=native | |
LDFLAGS+=-L ~/custom/boost/stage/lib/ -Wl,-rpath,/home/sehe/custom/boost/stage/lib | |
LDFLAGS+=-lboost_system -lboost_thread -ltcmalloc | |
#LDFLAGS+=-lboost_system -lboost_regex -lboost_thread -lpthread -lboost_iostreams -lboost_serialization | |
#LDFLAGS+=-lboost_date_time | |
CXX=/usr/lib/gcc-snapshot/bin/g++ | |
# CC=/usr/lib/gcc-snapshot/bin/gcc | |
# CXX=clang++ | |
# CC=clang | |
%.S:%.cpp | |
$(CXX) $(CPPFLAGS) $^ -S -masm=intel -o - | egrep -v '\s*\.' | c++filt > $@ | |
build/nonius/%:%.cpp | |
mkdir -pv $(@D) | |
$(CXX) -DNONIUS $(CPPFLAGS) $< -o $@ $(LDFLAGS) | |
build/test/%:%.cpp | |
mkdir -pv $(@D) | |
$(CXX) $(CPPFLAGS) $< -o $@ $(LDFLAGS) | |
%.txt:% | |
./$< -o $@ | |
%.html:% | |
./$< -r html -o $@ | |
*/*/*: optional_nonius.hpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/iostreams/device/array.hpp> | |
#include <boost/iostreams/stream.hpp> | |
#include <boost/atomic.hpp> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <boost/thread/thread.hpp> | |
#include "optional_nonius.hpp" | |
/* | |
* safe for use from a single thread only | |
*/ | |
template <unsigned line_maxchars = 1000> | |
class Log { | |
public: | |
Log(std::string const &logFileName, int32_t queueSize) | |
: | |
#ifdef NONIUS | |
fp(std::fopen(logFileName.c_str(), "w")), | |
#else | |
fp(stderr), //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
_shutdown(false), | |
_thread(&Log::pop, this), | |
_queue(queueSize) | |
{ } | |
void pop() { | |
std::string s; | |
s.reserve(line_maxchars); | |
struct timeval ts; | |
while (!_shutdown) { | |
while (_queue.pop(s)) { | |
gettimeofday(&ts, NULL); | |
std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str()); | |
} | |
std::fflush(fp); // RECONSIDER HERE? | |
} | |
while (_queue.pop(s)) { | |
gettimeofday(&ts, NULL); | |
std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str()); | |
} | |
} | |
void enqueue(std::string const& s) { | |
push(s); | |
} | |
void push(std::string const &s) { | |
while (!_queue.push(s)); | |
} | |
~Log() { | |
_shutdown = true; | |
_thread.join(); | |
assert(_queue.empty()); | |
std::fflush(fp); | |
std::fclose(fp); | |
fp = NULL; | |
} | |
private: | |
FILE *fp; | |
boost::atomic_bool _shutdown; | |
boost::thread _thread; | |
boost::lockfree::spsc_queue<std::string> _queue; | |
}; | |
#include <chrono> | |
#include <iostream> | |
NONIUS_BENCHMARK("mine-simple", [](nonius::chronometer meter) { | |
Log<> l("/dev/null", 1024); | |
for (size_t i=0; i<10; ++i) l.enqueue("warm up maybe"); | |
meter.measure([&l](long i) { | |
std::string s("let's log this long line"); | |
l.enqueue(s); | |
}); | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/iostreams/device/array.hpp> | |
#include <boost/iostreams/stream.hpp> | |
#include <boost/atomic.hpp> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <boost/thread/thread.hpp> | |
#include "optional_nonius.hpp" | |
/* | |
* safe for use from a single thread only | |
*/ | |
template <unsigned line_maxchars = 1000> | |
class Log { | |
public: | |
Log(std::string const &logFileName, int32_t queueSize) | |
: | |
#ifdef NONIUS | |
fp(std::fopen(logFileName.c_str(), "w")), | |
#else | |
fp(stderr), //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
_shutdown(false), | |
_thread(&Log::pop, this), | |
_queue(queueSize) | |
{ } | |
void pop() { | |
std::string s; | |
s.reserve(line_maxchars); | |
struct timeval ts; | |
while (!_shutdown) { | |
while (_queue.pop(s)) { | |
gettimeofday(&ts, NULL); | |
std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str()); | |
} | |
std::fflush(fp); // RECONSIDER HERE? | |
} | |
while (_queue.pop(s)) { | |
gettimeofday(&ts, NULL); | |
std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str()); | |
} | |
} | |
template <typename S, typename T> void stringer(S& stream, T const &t) { | |
stream << t; | |
} | |
template <typename S, typename T, typename... Args> | |
void stringer(S& stream, T const &t, Args const &... args) { | |
stringer(stream, t); | |
stringer(stream, args...); | |
} | |
template <typename T, typename... Args> void enqueue(T &t, Args const&... args) { | |
thread_local char buffer[line_maxchars] = {}; | |
thread_local boost::iostreams::array_sink as(buffer); | |
boost::iostreams::stream<boost::iostreams::array_sink> stream(as); | |
//stream.open(as); | |
stringer(stream, t, args...); | |
auto output = as.output_sequence(); | |
push(std::string(output.first, output.second)); | |
} | |
void push(std::string const &s) { | |
while (!_queue.push(s)); | |
} | |
~Log() { | |
_shutdown = true; | |
_thread.join(); | |
assert(_queue.empty()); | |
std::fflush(fp); | |
std::fclose(fp); | |
fp = NULL; | |
} | |
private: | |
FILE *fp; | |
boost::atomic_bool _shutdown; | |
boost::thread _thread; | |
boost::lockfree::spsc_queue<std::string> _queue; | |
}; | |
#include <chrono> | |
#include <iostream> | |
NONIUS_BENCHMARK("mine-variadic", [](nonius::chronometer meter) { | |
std::string const a_s("let's log this long line"); | |
double a_d(atan(1)*4); | |
const char* const a_l = "literal"; | |
Log<> l("/dev/null", 1024); | |
// warmup | |
for (size_t i=0; i<10; ++i) l.enqueue(a_s, a_d, i, a_l); | |
meter.measure([&](int i) { | |
switch (i%3) { | |
case 0: l.enqueue(a_s, a_d, i, a_l); break; | |
case 1: l.enqueue(a_s, a_l, a_d, i); break; | |
case 2: l.enqueue(a_d, i, a_l); break; | |
} | |
}); | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#ifdef NONIUS | |
#include <nonius/benchmark.h++> | |
#include <nonius/main.h++> | |
#else | |
#include <utility> | |
namespace nonius { | |
struct chronometer { | |
template <typename F> void measure(F&& f, decltype(f(0))* = nullptr) const { for (int i=0;i<10;++i) std::move(f)(i); } | |
template <typename F> void measure(F&& f, decltype(f())* = nullptr) const { for (int i=0;i<10;++i) std::move(f)(); } | |
}; | |
} | |
#define NONIUS_BENCHMARK(name,lambda) \ | |
int main() { \ | |
auto fake_nonius_ll = lambda; \ | |
fake_nonius_ll(nonius::chronometer {}); \ | |
} | |
#endif | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/thread/thread.hpp> | |
#include <boost/atomic.hpp> | |
#include <atomic> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <string> | |
#include <sstream> | |
#include <cstdio> | |
#include <sched.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/syscall.h> | |
#include <boost/scoped_ptr.hpp> | |
#include <sys/time.h> | |
#include <boost/lexical_cast.hpp> | |
#include <boost/asio.hpp> | |
#include <boost/function.hpp> | |
#include <boost/bind.hpp> | |
#include <boost/move/utility.hpp> | |
#include "optional_nonius.hpp" | |
void setThreadAffinity(boost::thread * const bt, int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
pthread_setaffinity_np(bt->native_handle(),sizeof(cst),&cst); | |
} | |
void setThreadAffinity(int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
sched_setaffinity(0,sizeof(cst),&cst); | |
} | |
// make sure size of pushCores vector is only 1 | |
struct Log{ | |
public: | |
Log(std::string const & logFileName, int32_t coreNumber, int32_t queueSize, std::vector<int32_t> const & pushCores) | |
: logFileName(logFileName), lock(ATOMIC_FLAG_INIT) | |
{ | |
#ifdef NONIUS | |
fp = std::fopen(logFileName.c_str(), "w"); | |
#else | |
fp = stderr; //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
std::atomic_store_explicit(&this->flag,true,std::memory_order_release); | |
this->q.reset(new boost::lockfree::spsc_queue<std::string>(queueSize)); | |
this->thrd.reset(new boost::thread(&Log::pop,this)); | |
setThreadAffinity(this->thrd.get(),coreNumber); | |
// | |
this->io_service.reset(new boost::asio::io_service); | |
this->work.reset(new boost::asio::io_service::work(*this->io_service)); | |
for (unsigned i = 0; i < pushCores.size(); ++i){ | |
boost::thread * t_thread = this->thread_pool.create_thread(boost::bind(&boost::asio::io_service::run,this->io_service.get())); | |
setThreadAffinity(t_thread,pushCores[i]); | |
} | |
} | |
inline __attribute__((always_inline)) void pop(){ | |
// setThreadAffinity(this->coreNumber); | |
std::string s; | |
s.reserve(1000); | |
struct timeval ts; | |
while (std::atomic_load_explicit(&this->flag,std::memory_order_acquire)){ | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
std::fflush(this->fp); | |
} | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
} | |
template <typename T> | |
inline __attribute__((always_inline)) std::string stringer(T const & t){ | |
return boost::lexical_cast<std::string>(t); | |
} | |
template<typename T, typename ... Args> | |
inline __attribute__((always_inline)) | |
std::string stringer(T const & t, Args const & ... args){ | |
return stringer(t) + stringer(args...); | |
} | |
template<typename T> | |
inline __attribute__((always_inline)) void enqueue(T t){ | |
this->io_service->post(t); | |
} | |
inline __attribute__((always_inline)) void push(std::string const & s){ | |
while (std::atomic_flag_test_and_set_explicit(&this->lock,std::memory_order_acquire)); | |
while (!this->q->push(s)); | |
std::atomic_flag_clear_explicit(&this->lock,std::memory_order_release); | |
} | |
~Log(){ | |
work.reset(); | |
this->thread_pool.join_all(); | |
std::atomic_store_explicit(&this->flag,false,std::memory_order_release); | |
this->thrd->join(); | |
std::fflush(this->fp); | |
std::fclose(this->fp); | |
this->fp = NULL; | |
} | |
private: | |
Log(){} | |
std::string logFileName; | |
boost::scoped_ptr<boost::lockfree::spsc_queue<std::string> > q; | |
boost::scoped_ptr<boost::thread> thrd; | |
std::atomic<bool> flag; | |
std::atomic_flag lock; | |
FILE * fp; | |
boost::scoped_ptr<boost::asio::io_service> io_service; | |
boost::scoped_ptr<boost::asio::io_service::work> work; | |
boost::thread_group thread_pool; | |
}; | |
NONIUS_BENCHMARK("service-simple", [](nonius::chronometer meter) { | |
std::vector<int32_t> pushCores; | |
for (int i = 0; i < 1; ++i) { | |
pushCores.push_back(i); | |
} | |
// pushCores.push_back(16); pushCores.push_back(17), pushCores.push_back(18), pushCores.push_back(19); | |
Log l("/dev/null",1,1024,pushCores); | |
for (size_t i=0; i<10; ++i) l.enqueue(boost::bind(&Log::push,&l,"warm up maybe")); | |
meter.measure([&l](int i) { | |
l.enqueue(boost::bind(&Log::push,&l,"let's print out this line")); | |
}); | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/thread/thread.hpp> | |
#include <boost/atomic.hpp> | |
#include <atomic> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <string> | |
#include <sstream> | |
#include <cstdio> | |
#include <sched.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/syscall.h> | |
#include <boost/scoped_ptr.hpp> | |
#include <sys/time.h> | |
#include <boost/lexical_cast.hpp> | |
#include <boost/asio.hpp> | |
#include <boost/function.hpp> | |
#include <boost/bind.hpp> | |
#include <boost/move/utility.hpp> | |
#include "optional_nonius.hpp" | |
void setThreadAffinity(boost::thread * const bt, int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
pthread_setaffinity_np(bt->native_handle(),sizeof(cst),&cst); | |
} | |
void setThreadAffinity(int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
sched_setaffinity(0,sizeof(cst),&cst); | |
} | |
// make sure size of pushCores vector is only 1 | |
struct Log{ | |
public: | |
Log(std::string const & logFileName, int32_t coreNumber, int32_t queueSize, std::vector<int32_t> const & pushCores) | |
: logFileName(logFileName), lock(ATOMIC_FLAG_INIT) | |
{ | |
#ifdef NONIUS | |
fp = std::fopen(logFileName.c_str(), "w"); | |
#else | |
fp = stderr; //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
std::atomic_store_explicit(&this->flag,true,std::memory_order_release); | |
this->q.reset(new boost::lockfree::spsc_queue<std::string>(queueSize)); | |
this->thrd.reset(new boost::thread(&Log::pop,this)); | |
setThreadAffinity(this->thrd.get(),coreNumber); | |
// | |
this->io_service.reset(new boost::asio::io_service); | |
this->work.reset(new boost::asio::io_service::work(*this->io_service)); | |
for (unsigned i = 0; i < pushCores.size(); ++i){ | |
boost::thread * t_thread = this->thread_pool.create_thread(boost::bind(&boost::asio::io_service::run,this->io_service.get())); | |
setThreadAffinity(t_thread,pushCores[i]); | |
} | |
} | |
inline __attribute__((always_inline)) void pop(){ | |
// setThreadAffinity(this->coreNumber); | |
std::string s; | |
s.reserve(1000); | |
struct timeval ts; | |
while (std::atomic_load_explicit(&this->flag,std::memory_order_acquire)){ | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
std::fflush(this->fp); | |
} | |
while (this->q->pop(s)){ | |
gettimeofday(&ts,NULL); | |
std::fprintf(this->fp,"%li.%06li %s\n",ts.tv_sec,ts.tv_usec,s.c_str()); | |
} | |
} | |
template <typename T> | |
inline __attribute__((always_inline)) std::string stringer(T const & t){ | |
return boost::lexical_cast<std::string>(t); | |
} | |
template<typename T, typename ... Args> | |
inline __attribute__((always_inline)) | |
std::string stringer(T const & t, Args const & ... args){ | |
return stringer(t) + stringer(args...); | |
} | |
template<typename T, typename ... Args> | |
inline __attribute__((always_inline)) void enqueue(T const& t, Args const & ... args){ | |
io_service->post([&]{ this->push(stringer(t, args...)); }); | |
} | |
inline __attribute__((always_inline)) void push(std::string const & s){ | |
while (std::atomic_flag_test_and_set_explicit(&this->lock,std::memory_order_acquire)); | |
while (!this->q->push(s)); | |
std::atomic_flag_clear_explicit(&this->lock,std::memory_order_release); | |
} | |
~Log(){ | |
work.reset(); | |
this->thread_pool.join_all(); | |
std::atomic_store_explicit(&this->flag,false,std::memory_order_release); | |
this->thrd->join(); | |
std::fflush(this->fp); | |
std::fclose(this->fp); | |
this->fp = NULL; | |
} | |
private: | |
Log(){} | |
std::string logFileName; | |
boost::scoped_ptr<boost::lockfree::spsc_queue<std::string> > q; | |
boost::scoped_ptr<boost::thread> thrd; | |
std::atomic<bool> flag; | |
std::atomic_flag lock; | |
FILE * fp; | |
boost::scoped_ptr<boost::asio::io_service> io_service; | |
boost::scoped_ptr<boost::asio::io_service::work> work; | |
boost::thread_group thread_pool; | |
}; | |
NONIUS_BENCHMARK("service-variadic", [](nonius::chronometer meter) { | |
std::string const a_s("let's log this long line"); | |
double a_d(atan(1)*4); | |
const char* const a_l = "literal"; | |
Log l("/dev/null",15,1024, {0}); | |
// warmup | |
for (size_t i=0; i<10; ++i) l.enqueue(a_s, a_d, i, a_l); | |
meter.measure([&](int i) { | |
switch (i%3) { | |
case 0: l.enqueue(a_s, a_d, i, a_l); break; | |
case 1: l.enqueue(a_s, a_l, a_d, i); break; | |
case 2: l.enqueue(a_d, i, a_l); break; | |
} | |
}); | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/iostreams/device/array.hpp> | |
#include <boost/iostreams/stream.hpp> | |
#include <boost/function.hpp> | |
#include <boost/atomic.hpp> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <boost/thread/thread.hpp> | |
#include "optional_nonius.hpp" | |
/* | |
* safe for use from a single thread only | |
*/ | |
template <unsigned line_maxchars = 1000> | |
class Log { | |
public: | |
typedef boost::function<void(std::ostream&)> render_f; | |
Log(std::string const &logFileName, int32_t queueSize) | |
: | |
#ifdef NONIUS | |
fp(std::fopen(logFileName.c_str(), "w")), | |
#else | |
fp(stderr), //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
_shutdown(false), | |
_thread(&Log::pop, this), | |
_queue(queueSize) | |
{ } | |
void pop() { | |
render_f f; | |
char buffer[line_maxchars+1] = {}; | |
auto loop = [&] { | |
bool needflush = false; | |
while (_queue.pop(f)) { | |
needflush = true; | |
struct timeval ts; | |
gettimeofday(&ts, NULL); | |
boost::iostreams::array_sink as(buffer, line_maxchars); | |
boost::iostreams::stream<boost::iostreams::array_sink> stream(as); | |
f(stream); | |
stream.rdbuf()->sputc('\0'); | |
std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, buffer); | |
} | |
return needflush; | |
}; | |
while (!_shutdown) { | |
if (loop()) | |
std::fflush(fp); | |
} | |
if (loop()) | |
std::fflush(fp); | |
} | |
void push(render_f f) { | |
while (!_queue.push(f)); | |
} | |
~Log() { | |
_shutdown = true; | |
_thread.join(); | |
assert(_queue.empty()); | |
std::fflush(fp); | |
std::fclose(fp); | |
fp = NULL; | |
} | |
private: | |
FILE *fp; | |
boost::atomic_bool _shutdown; | |
boost::thread _thread; | |
boost::lockfree::spsc_queue<render_f> _queue; | |
}; | |
#include <chrono> | |
#include <iostream> | |
#define LOG(body) do { l.push([=](std::ostream& os) { body; }); } while(false); | |
NONIUS_BENCHMARK("mine-smart-variadic", [](nonius::chronometer meter) { | |
std::string const a_s("let's log this long line"); | |
double a_d(atan(1)*4); | |
const char* const a_l = "literal"; | |
Log<> l("/dev/null", 1024); | |
// warmup | |
for (size_t i=0; i<10; ++i) l.push([&](std::ostream& os) { os << a_s << a_d << i << a_l; }); | |
meter.measure([&](int i) { | |
switch (i%3) { | |
case 0: LOG(os << a_s << a_d << i << a_l); break; | |
case 1: LOG(os << a_s << a_l << a_d << i); break; | |
case 2: LOG(os << a_d << i << a_l); break; | |
} | |
}); | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _BLITZ_LOGGER_H_ | |
#include <boost/thread/thread.hpp> | |
#include <boost/atomic.hpp> | |
#include <atomic> | |
#include <boost/lockfree/spsc_queue.hpp> | |
#include <string> | |
#include <sstream> | |
#include <cstdio> | |
#include <sched.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <sys/syscall.h> | |
#include <boost/scoped_ptr.hpp> | |
#include <sys/time.h> | |
#include <boost/lexical_cast.hpp> | |
#include <boost/asio.hpp> | |
#include <boost/function.hpp> | |
#include <boost/bind.hpp> | |
#include <boost/move/utility.hpp> | |
#include <functional> | |
#include <tr1/functional> | |
#include "optional_nonius.hpp" | |
void setThreadAffinity(boost::thread * const bt, int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
pthread_setaffinity_np(bt->native_handle(),sizeof(cst),&cst); | |
} | |
void setThreadAffinity(int32_t const coreNumber){ | |
cpu_set_t cst; | |
CPU_ZERO(&cst); | |
CPU_SET(coreNumber,&cst); | |
sched_setaffinity(0,sizeof(cst),&cst); | |
} | |
namespace blitz { | |
template <unsigned popResSize = 1024> struct BlitzLogger { | |
public: | |
BlitzLogger(std::string const &logFileName, int32_t const popCore, int32_t const pushCore, int32_t queueSize) | |
: | |
#ifdef NONIUS | |
fp(std::fopen(logFileName.c_str(), "w")), | |
#else | |
fp(stderr), //std::fopen(logFileName.c_str(),"w")), | |
#endif | |
flag(true), | |
_queue(queueSize), | |
pop_thread(&BlitzLogger::pop, this), | |
io_service(), | |
work(boost::asio::io_service::work(io_service)), | |
push_thread(boost::bind(&boost::asio::io_service::run, &io_service)) | |
{ | |
setThreadAffinity(&pop_thread, popCore); | |
setThreadAffinity(&push_thread, pushCore); | |
} | |
template <typename... Args> void enqueue(Args const &... args) { concatenate(args...); } | |
~BlitzLogger() { | |
work.reset(); | |
push_thread.join(); | |
flag = false; | |
pop_thread.join(); | |
std::fflush(fp); | |
if (fp != stdout && fp != stderr) | |
std::fclose(fp); | |
fp = NULL; | |
} | |
private: | |
FILE *fp; | |
std::atomic<bool> flag; | |
boost::lockfree::spsc_queue<std::string> _queue; | |
boost::thread pop_thread; | |
boost::asio::io_service io_service; | |
boost::optional<boost::asio::io_service::work> work; | |
boost::thread push_thread; | |
void pop() { | |
std::string s; | |
s.reserve(popResSize); | |
struct timeval ts; | |
while (flag) { | |
while (_queue.pop(s)) { | |
gettimeofday(&ts, NULL); | |
std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str()); | |
} | |
std::fflush(fp); | |
} | |
while (_queue.pop(s)) { | |
gettimeofday(&ts, NULL); | |
std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str()); | |
} | |
} | |
template <typename T> std::string stringer(T const &t) { | |
return boost::lexical_cast<std::string>(t); | |
} | |
template <typename T, typename... Args> | |
std::string stringer(T const &t, Args const &... args) { | |
return stringer(t) + stringer(args...); | |
} | |
template <typename... Args> void concatenate(Args const&... args) { | |
io_service.post( | |
std::tr1::bind(&BlitzLogger::push, this, | |
std::tr1::bind(&BlitzLogger::stringer<Args const &...>, this, args...))); | |
} | |
void push(std::string const &s) { | |
while (!_queue.push(s)); | |
} | |
}; | |
} | |
#include <chrono> | |
#include <iostream> | |
#define LOG(body) do { l.push([=](std::ostream& os) { body; }); } while(false); | |
NONIUS_BENCHMARK("subnano", [](nonius::chronometer meter) { | |
std::string const a_s("let's log this long line"); | |
double a_d(atan(1)*4); | |
const char* const a_l = "literal"; | |
blitz::BlitzLogger<> l("/dev/null",15,15,1024); | |
// warmup | |
for (size_t i=0; i<10; ++i) l.enqueue(a_s, a_d, i, a_l); | |
meter.measure([&](int i) { | |
switch (i%3) { | |
case 0: l.enqueue(a_s, a_d, i, a_l); break; | |
case 1: l.enqueue(a_s, a_l, a_d, i); break; | |
case 2: l.enqueue(a_d, i, a_l); break; | |
} | |
}); | |
}) | |
#if 0 | |
int main(){ | |
BlitzLogger<> l("/tmp/junk.log",15,15,1024); | |
struct timeval ts_1, ts_2; | |
gettimeofday(&ts_1,NULL); | |
// burn in | |
for (int64_t i = 0; i < 10; ++i){ | |
l.enqueue("hello",1,2,3,5.36," world\n"); | |
} | |
gettimeofday(&ts_1,NULL); | |
{ | |
for (int i = 0; i < 333333; ++i){ | |
// l.enqueue("hello",42,32,45); | |
l.enqueue("check this out", 2, 4.3, "junk it\n"); | |
l.enqueue("trade @ ", 100," for ", 42000,"sadadahares for instrument ", 4.3, "junk it\n",42); | |
l.enqueue("check thasdadis out", 2, 4.3, "junasdk it","trade @ ", 100," for ", 42000, | |
"check adadathasdadis out", 2, 4.3, "juadadadnasdk it","tradeasd @ ", 100," for ", 420930, | |
"check thasdadis out", 2, 4.3, "junasdk it","trade @ ", 100," for ", 42000); | |
} | |
} | |
gettimeofday(&ts_2,NULL); | |
std::fprintf(stderr,"%li microsec\n",(ts_2.tv_sec-ts_1.tv_sec)*1000000+(ts_2.tv_usec-ts_1.tv_usec)); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
simple: /home/sehe/custom/boost/boost/smart_ptr/scoped_ptr.hpp:99: T* boost::scoped_ptr<T>::operator->() const [with T = boost::lockfree::spsc_queue<std::basic_string<char> >]: Assertion `px != 0' failed. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment