diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8a233d3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required( VERSION 3.0 ) +project( Profiler ) + +if ( MSVC ) + add_compile_options( "/std:c++14" ) +else() + set( CMAKE_CXX_STANDARD 14) + set( CMAKE_CXX_STANDARD_REQUIRED ON ) + add_compile_options( -std=c++14 ) +endif() + +option( BUILD_EXAMPLES OFF ) + +add_subdirectory( lib ) + +if ( ${BUILD_EXAMPLES} ) + add_subdirectory( examples ) +endif() diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e6c64a --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Profiler + +This two files library is designed for simple profiling. + +To use it just copy files from folder **lib/** to your project. + +You can find usage examples in examples/simple.cpp. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..e575148 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable( simple simple.cpp ) +target_link_libraries( simple profiler ) diff --git a/examples/simple.cpp b/examples/simple.cpp new file mode 100644 index 0000000..7d23bb5 --- /dev/null +++ b/examples/simple.cpp @@ -0,0 +1,42 @@ +#include + +#include "Profiler.h" + + +using namespace alt; + + +int main( int argc, char** argv ) +{ + Profiler profMain( "total time", true ); + + { // block-1 + Profiler profBlock1( "block-1", true ); + + for ( int i = 0; i < 1000000; ++i ) // 1M + int n = i * i - i / 3; + } + + { // block-2 + Profiler profBlock1( "block-2", true ); + + for ( int i = 0; i < 1000000; ++i ) // 1M + int n = i / 3 + i * 10 - i / 5 + 19; + } + + for ( int k = 0; k < 19; ++k ) + { + Profiler profOp( "operation" ); + + for ( int i = 0; i < 1000000; ++i ) // 1M + int n = i + i * i; + } + + Profiler::printStatistics(); + + std::ostringstream oss; + Profiler::printStatistics( oss ); + std::cout << "Statistics from stream\n" << oss.str() << std::endl; + + return 0; +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..2fa7103 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,19 @@ +set( lib profiler ) + +set( CMAKE_INCLUDE_CURRENT_DIR ON ) + +set( HEADERS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}" ) + +set( HDRS + ${HEADERS_ROOT}/Profiler.h +) + +set( SRCS + ${HEADERS_ROOT}/Profiler.cpp +) + +add_library( ${lib} ${SRCS} ${HDRS} ) + +target_include_directories( ${lib} INTERFACE + ${HEADERS_ROOT} +) diff --git a/lib/Profiler.cpp b/lib/Profiler.cpp new file mode 100644 index 0000000..90c3ce9 --- /dev/null +++ b/lib/Profiler.cpp @@ -0,0 +1,91 @@ +#include + + +std::map> alt::Profiler::map_; + + +namespace alt +{ + + + Profiler::Profiler( const std::string& name, bool print, std::ostream& out ) + : name_( name ) + , print_( print ) + , out_( out ) + , tick_( std::chrono::steady_clock::now() ) + { + if ( print_ ) + out_ << "\nBegin profile. " << name_ << std::endl; + } + + + Profiler::~Profiler() + { + const auto milli = currentMilli(); + if ( print_ ) + out_ << "End profile [" << milli << " ms]. " << name_ << "\n" << std::endl; + addStatistic( name_, milli ); + } + + + void Profiler::printStatistics( std::ostream& os ) + { + getStatistics( os ); + } + + + void Profiler::getStatistics( std::ostream& os ) + { + if ( map_.empty() ) + { + os + << "============================\n" + << "== Profiler map is EMPTY! ==\n" + << std::endl; + return; + } + + os + << "==================\n" + << "== Profiler map ==\n" + << "\n"; + + for ( const auto data : map_ ) + { + int ms = std::get<0>( data.second ); + int count = std::get<1>( data.second ); + os + << data.first << "\n" + << "total ms: " << ms << "\n" + << "count: " << count << "\n" + << "avg: " << static_cast< double >( ms ) / count << "\n" + << std::endl; + } + } + + + void Profiler::addStatistic( const std::string& name, int milli ) + { + auto it = map_.find( name ); + if ( it == map_.end() ) + { + bool ok; + std::tie( it, ok ) = map_.emplace( name, std::make_pair( 0, 0 ) ); + if ( !ok ) + return; + } + + auto& par = it->second; + std::get<0>( par ) += milli; + ++std::get<1>( par ); + } + + + std::size_t Profiler::currentMilli() const + { + const auto tick = std::chrono::steady_clock::now(); + return static_cast( std::chrono::duration_cast( tick - tick_ ).count() ); + } + + +} \ No newline at end of file diff --git a/lib/Profiler.h b/lib/Profiler.h new file mode 100644 index 0000000..242bf9b --- /dev/null +++ b/lib/Profiler.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include + + +namespace alt +{ + + + class Profiler + { + public: + Profiler( const std::string& name, bool print = false, std::ostream& = std::cout ); + ~Profiler(); + + static void printStatistics( std::ostream& = std::cout ); + static void getStatistics( std::ostream& ); + + private: + static void addStatistic( const std::string&, int ); + std::size_t currentMilli() const; + + const std::string name_; + bool print_; + std::ostream& out_; + std::chrono::time_point tick_; + + // name -> (total time, count) + static std::map> map_; + }; + + +}