From b6daf43f33340d115bb453d0fe010d8d48bb4b13 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Fri, 19 May 2017 17:10:04 +1000 Subject: [PATCH] Add profiling support using easy_profiler --- src/DTRenderer.cpp | 3 + src/DTRendererDebug.h | 26 +- src/DTRendererRender.cpp | 157 ++-- src/Win32DTRenderer.cpp | 4 + src/build.bat | 6 +- src/external/easy/easy_compiler_support.h | 156 ++++ src/external/easy/easy_net.h | 149 ++++ src/external/easy/easy_profiler.lib | Bin 0 -> 34256 bytes src/external/easy/easy_socket.h | 128 +++ src/external/easy/profiler.h | 933 ++++++++++++++++++++++ src/external/easy/profiler_aux.h | 209 +++++ src/external/easy/profiler_colors.h | 412 ++++++++++ src/external/easy/reader.h | 416 ++++++++++ src/external/easy/serialized_block.h | 112 +++ 14 files changed, 2635 insertions(+), 76 deletions(-) create mode 100644 src/external/easy/easy_compiler_support.h create mode 100644 src/external/easy/easy_net.h create mode 100644 src/external/easy/easy_profiler.lib create mode 100644 src/external/easy/easy_socket.h create mode 100644 src/external/easy/profiler.h create mode 100644 src/external/easy/profiler_aux.h create mode 100644 src/external/easy/profiler_colors.h create mode 100644 src/external/easy/reader.h create mode 100644 src/external/easy/serialized_block.h diff --git a/src/DTRenderer.cpp b/src/DTRenderer.cpp index 47cc653..c0d8011 100644 --- a/src/DTRenderer.cpp +++ b/src/DTRenderer.cpp @@ -1038,6 +1038,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, DTRState *state = (DTRState *)memory->context; if (!memory->isInit) { + DTR_DEBUG_PROFILE_START(); // NOTE(doyle): Do premultiply ourselves stbi_set_unpremultiply_on_load(true); stbi_set_flip_vertically_on_load(true); @@ -1060,6 +1061,8 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, int x = 5; DqnMemBuffer_EndTempRegion(tmp); } + DTR_DEBUG_TIMED_FUNCTION(); + DTRRender_Clear(renderBuffer, DqnV3_3f(0, 0, 0)); #if 1 diff --git a/src/DTRendererDebug.h b/src/DTRendererDebug.h index f681ae2..0c3105d 100644 --- a/src/DTRendererDebug.h +++ b/src/DTRendererDebug.h @@ -2,10 +2,32 @@ #define DTRENDERER_DEBUG_H #include "dqn.h" - #define DTR_DEBUG 1 #ifdef DTR_DEBUG - #define DTR_DEBUG_RENDER 0 + #define DTR_DEBUG_RENDER 0 + + #define DTR_DEBUG_PROFILING 1 + #ifdef DTR_DEBUG_PROFILING + #define BUILD_WITH_EASY_PROFILER 1 + #include "external/easy/profiler.h" + + #define DTR_DEBUG_PROFILE_START() profiler::startListen() + #define DTR_DEBUG_PROFILE_END() profiler::stopListen() + + #define DTR_DEBUG_TIMED_BLOCK(name) EASY_BLOCK(name) + #define DTR_DEBUG_TIMED_NONSCOPED_BLOCK(name) EASY_NONSCOPED_BLOCK(name) + #define DTR_DEBUG_TIMED_END_BLOCK() EASY_END_BLOCK() + #define DTR_DEBUG_TIMED_FUNCTION() EASY_FUNCTION() + #else + #define DTR_DEBUG_PROFILE_START() + #define DTR_DEBUG_PROFILE_END() + + #define DTR_DEBUG_TIMED_BLOCK(name) + #define DTR_DEBUG_TIMED_NONSCOPED_BLOCK(name) + #define DTR_DEBUG_TIMED_END_BLOCK() + #define DTR_DEBUG_TIMED_FUNCTION() + #endif + #endif typedef struct PlatformRenderBuffer PlatformRenderBuffer; diff --git a/src/DTRendererRender.cpp b/src/DTRendererRender.cpp index c72e115..d8332e7 100644 --- a/src/DTRendererRender.cpp +++ b/src/DTRendererRender.cpp @@ -1,4 +1,5 @@ #include "DTRendererRender.h" +#include "DTRendererDebug.h" #include "DTRendererPlatform.h" #define STB_RECT_PACK_IMPLEMENTATION @@ -104,6 +105,7 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const if (!renderBuffer) return; if (x < 0 || x > (renderBuffer->width - 1)) return; if (y < 0 || y > (renderBuffer->height - 1)) return; + DTR_DEBUG_TIMED_FUNCTION(); u32 *const bitmapPtr = (u32 *)renderBuffer->memory; const u32 pitchInU32 = (renderBuffer->width * renderBuffer->bytesPerPixel) / 4; @@ -172,6 +174,7 @@ void DTRRender_Text(PlatformRenderBuffer *const renderBuffer, { if (!text) return; if (!font.bitmap || !font.atlas || !renderBuffer) return; + DTR_DEBUG_TIMED_FUNCTION(); if (len == -1) len = Dqn_strlen(text); @@ -249,6 +252,7 @@ FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList, const f32 rotation) { if (!pList || numP == 0) return; + DTR_DEBUG_TIMED_FUNCTION(); DqnV2 xAxis = (DqnV2_2f(cosf(rotation), sinf(rotation))); DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x); @@ -266,6 +270,8 @@ void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color) { if (!renderBuffer) return; + DTR_DEBUG_TIMED_FUNCTION(); + color = DTRRender_SRGB1ToLinearSpaceV4(color); color = PreMultiplyAlpha1(color); @@ -383,6 +389,7 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP) void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform) { + DTR_DEBUG_TIMED_FUNCTION(); //////////////////////////////////////////////////////////////////////////// // Transform vertexes //////////////////////////////////////////////////////////////////////////// @@ -479,6 +486,8 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV2 p2, DqnV2 p3, DqnV4 color, const DTRRenderTransform transform) { + DTR_DEBUG_TIMED_FUNCTION(); + //////////////////////////////////////////////////////////////////////////// // Transform vertexes //////////////////////////////////////////////////////////////////////////// @@ -705,10 +714,7 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, const DTRRenderTransform transform, DqnV4 color) { if (!bitmap || !bitmap->memory || !renderBuffer) return; - DQN_ASSERT(color.a >= 0 && color.a <= 1.0f); - DQN_ASSERT(color.r >= 0 && color.r <= 1.0f); - DQN_ASSERT(color.g >= 0 && color.g <= 1.0f); - DQN_ASSERT(color.b >= 0 && color.b <= 1.0f); + DTR_DEBUG_TIMED_FUNCTION(); //////////////////////////////////////////////////////////////////////////// // Transform vertexes @@ -722,11 +728,16 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, const i32 RECT_PLIST_SIZE = DQN_ARRAY_COUNT(rectPoints.pList); DqnRect bounds = GetBoundingBox(pList, RECT_PLIST_SIZE); - min = bounds.min; - max = bounds.max; + min = bounds.min; + max = bounds.max; color = DTRRender_SRGB1ToLinearSpaceV4(color); color = PreMultiplyAlpha1(color); + DQN_ASSERT(color.a >= 0 && color.a <= 1.0f); + DQN_ASSERT(color.r >= 0 && color.r <= 1.0f); + DQN_ASSERT(color.g >= 0 && color.g <= 1.0f); + DQN_ASSERT(color.b >= 0 && color.b <= 1.0f); + //////////////////////////////////////////////////////////////////////////// // Clip drawing space //////////////////////////////////////////////////////////////////////////// @@ -775,6 +786,7 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, if (bufXYIsInside) { + DTR_DEBUG_TIMED_BLOCK("DTRRender_Bitmap TexelCalculation"); DqnV2 bufPRelToBasis = DqnV2_2i(bufferX, bufferY) - rectBasis; f32 u = DqnV2_Dot(bufPRelToBasis, xAxisRelToBasis) * invXAxisLenSq; @@ -804,86 +816,89 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, i32 texel4X = DQN_MIN((texelX + 1), bitmap->dim.w - 1); i32 texel4Y = DQN_MIN((texelY + 1), bitmap->dim.h - 1); - u32 texel1 = *(u32 *)(bitmapPtr + ((texel1X * bitmap->bytesPerPixel) + (texel1Y * pitch))); - u32 texel2 = *(u32 *)(bitmapPtr + ((texel2X * bitmap->bytesPerPixel) + (texel2Y * pitch))); - u32 texel3 = *(u32 *)(bitmapPtr + ((texel3X * bitmap->bytesPerPixel) + (texel3Y * pitch))); - u32 texel4 = *(u32 *)(bitmapPtr + ((texel4X * bitmap->bytesPerPixel) + (texel4Y * pitch))); + { + DTR_DEBUG_TIMED_BLOCK("DTRRender_Bitmap TexelBilinearInterpolation"); + u32 texel1 = *(u32 *)(bitmapPtr + ((texel1X * bitmap->bytesPerPixel) + (texel1Y * pitch))); + u32 texel2 = *(u32 *)(bitmapPtr + ((texel2X * bitmap->bytesPerPixel) + (texel2Y * pitch))); + u32 texel3 = *(u32 *)(bitmapPtr + ((texel3X * bitmap->bytesPerPixel) + (texel3Y * pitch))); + u32 texel4 = *(u32 *)(bitmapPtr + ((texel4X * bitmap->bytesPerPixel) + (texel4Y * pitch))); - DqnV4 color1; - color1.a = (f32)(texel1 >> 24); - color1.b = (f32)((texel1 >> 16) & 0xFF); - color1.g = (f32)((texel1 >> 8) & 0xFF); - color1.r = (f32)((texel1 >> 0) & 0xFF); + DqnV4 color1; + color1.a = (f32)(texel1 >> 24); + color1.b = (f32)((texel1 >> 16) & 0xFF); + color1.g = (f32)((texel1 >> 8) & 0xFF); + color1.r = (f32)((texel1 >> 0) & 0xFF); - DqnV4 color2; - color2.a = (f32)(texel2 >> 24); - color2.b = (f32)((texel2 >> 16) & 0xFF); - color2.g = (f32)((texel2 >> 8) & 0xFF); - color2.r = (f32)((texel2 >> 0) & 0xFF); + DqnV4 color2; + color2.a = (f32)(texel2 >> 24); + color2.b = (f32)((texel2 >> 16) & 0xFF); + color2.g = (f32)((texel2 >> 8) & 0xFF); + color2.r = (f32)((texel2 >> 0) & 0xFF); - DqnV4 color3; - color3.a = (f32)(texel3 >> 24); - color3.b = (f32)((texel3 >> 16) & 0xFF); - color3.g = (f32)((texel3 >> 8) & 0xFF); - color3.r = (f32)((texel3 >> 0) & 0xFF); + DqnV4 color3; + color3.a = (f32)(texel3 >> 24); + color3.b = (f32)((texel3 >> 16) & 0xFF); + color3.g = (f32)((texel3 >> 8) & 0xFF); + color3.r = (f32)((texel3 >> 0) & 0xFF); - DqnV4 color4; - color4.a = (f32)(texel4 >> 24); - color4.b = (f32)((texel4 >> 16) & 0xFF); - color4.g = (f32)((texel4 >> 8) & 0xFF); - color4.r = (f32)((texel4 >> 0) & 0xFF); + DqnV4 color4; + color4.a = (f32)(texel4 >> 24); + color4.b = (f32)((texel4 >> 16) & 0xFF); + color4.g = (f32)((texel4 >> 8) & 0xFF); + color4.r = (f32)((texel4 >> 0) & 0xFF); - color1 *= DTRRENDER_INV_255; - color2 *= DTRRENDER_INV_255; - color3 *= DTRRENDER_INV_255; - color4 *= DTRRENDER_INV_255; + color1 *= DTRRENDER_INV_255; + color2 *= DTRRENDER_INV_255; + color3 *= DTRRENDER_INV_255; + color4 *= DTRRENDER_INV_255; - color1 = DTRRender_SRGB1ToLinearSpaceV4(color1); - color2 = DTRRender_SRGB1ToLinearSpaceV4(color2); - color3 = DTRRender_SRGB1ToLinearSpaceV4(color3); - color4 = DTRRender_SRGB1ToLinearSpaceV4(color4); + color1 = DTRRender_SRGB1ToLinearSpaceV4(color1); + color2 = DTRRender_SRGB1ToLinearSpaceV4(color2); + color3 = DTRRender_SRGB1ToLinearSpaceV4(color3); + color4 = DTRRender_SRGB1ToLinearSpaceV4(color4); - DqnV4 color12; - color12.a = DqnMath_Lerp(color1.a, texelFractionalX, color2.a); - color12.b = DqnMath_Lerp(color1.b, texelFractionalX, color2.b); - color12.g = DqnMath_Lerp(color1.g, texelFractionalX, color2.g); - color12.r = DqnMath_Lerp(color1.r, texelFractionalX, color2.r); + DqnV4 color12; + color12.a = DqnMath_Lerp(color1.a, texelFractionalX, color2.a); + color12.b = DqnMath_Lerp(color1.b, texelFractionalX, color2.b); + color12.g = DqnMath_Lerp(color1.g, texelFractionalX, color2.g); + color12.r = DqnMath_Lerp(color1.r, texelFractionalX, color2.r); - DqnV4 color34; - color34.a = DqnMath_Lerp(color3.a, texelFractionalX, color4.a); - color34.b = DqnMath_Lerp(color3.b, texelFractionalX, color4.b); - color34.g = DqnMath_Lerp(color3.g, texelFractionalX, color4.g); - color34.r = DqnMath_Lerp(color3.r, texelFractionalX, color4.r); + DqnV4 color34; + color34.a = DqnMath_Lerp(color3.a, texelFractionalX, color4.a); + color34.b = DqnMath_Lerp(color3.b, texelFractionalX, color4.b); + color34.g = DqnMath_Lerp(color3.g, texelFractionalX, color4.g); + color34.r = DqnMath_Lerp(color3.r, texelFractionalX, color4.r); - DqnV4 blend; - blend.a = DqnMath_Lerp(color12.a, texelFractionalY, color34.a); - blend.b = DqnMath_Lerp(color12.b, texelFractionalY, color34.b); - blend.g = DqnMath_Lerp(color12.g, texelFractionalY, color34.g); - blend.r = DqnMath_Lerp(color12.r, texelFractionalY, color34.r); + DqnV4 blend; + blend.a = DqnMath_Lerp(color12.a, texelFractionalY, color34.a); + blend.b = DqnMath_Lerp(color12.b, texelFractionalY, color34.b); + blend.g = DqnMath_Lerp(color12.g, texelFractionalY, color34.g); + blend.r = DqnMath_Lerp(color12.r, texelFractionalY, color34.r); - DQN_ASSERT(blend.a >= 0 && blend.a <= 1.0f); - DQN_ASSERT(blend.r >= 0 && blend.r <= 1.0f); - DQN_ASSERT(blend.g >= 0 && blend.g <= 1.0f); - DQN_ASSERT(blend.b >= 0 && blend.b <= 1.0f); + DQN_ASSERT(blend.a >= 0 && blend.a <= 1.0f); + DQN_ASSERT(blend.r >= 0 && blend.r <= 1.0f); + DQN_ASSERT(blend.g >= 0 && blend.g <= 1.0f); + DQN_ASSERT(blend.b >= 0 && blend.b <= 1.0f); - // TODO(doyle): Color modulation does not work!!! By supplying - // colors [0->1] it'll reduce some of the coverage of a channel - // and once alpha blending is applied that reduced coverage will - // blend with the background and cause the bitmap to go - // transparent when it shouldn't. - blend.a *= color.a; - blend.r *= color.r; - blend.g *= color.g; - blend.b *= color.b; + // TODO(doyle): Color modulation does not work!!! By supplying + // colors [0->1] it'll reduce some of the coverage of a channel + // and once alpha blending is applied that reduced coverage will + // blend with the background and cause the bitmap to go + // transparent when it shouldn't. + blend.a *= color.a; + blend.r *= color.r; + blend.g *= color.g; + blend.b *= color.b; #if 0 - blend.a = DqnMath_Clampf(blend.a, 0.0f, 1.0f); - blend.r = DqnMath_Clampf(blend.r, 0.0f, 1.0f); - blend.g = DqnMath_Clampf(blend.g, 0.0f, 1.0f); - blend.b = DqnMath_Clampf(blend.b, 0.0f, 1.0f); + blend.a = DqnMath_Clampf(blend.a, 0.0f, 1.0f); + blend.r = DqnMath_Clampf(blend.r, 0.0f, 1.0f); + blend.g = DqnMath_Clampf(blend.g, 0.0f, 1.0f); + blend.b = DqnMath_Clampf(blend.b, 0.0f, 1.0f); #endif - SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear); + SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear); + } } } } diff --git a/src/Win32DTRenderer.cpp b/src/Win32DTRenderer.cpp index 19dcf9f..203860f 100644 --- a/src/Win32DTRenderer.cpp +++ b/src/Win32DTRenderer.cpp @@ -158,6 +158,10 @@ FILE_SCOPE Win32ExternalCode Win32LoadExternalDLL(const char *const srcPath, (DTR_UpdateFunction *)GetProcAddress(result.dll, "DTR_Update"); if (updateFunction) result.DTR_Update = updateFunction; } + else + { + DqnWin32_DisplayLastError("LoadLibraryA failed"); + } return result; } diff --git a/src/build.bat b/src/build.bat index e373cf8..ccaf0d2 100644 --- a/src/build.bat +++ b/src/build.bat @@ -25,7 +25,7 @@ pushd ..\bin REM //////////////////////////////////////////////////////////////////////////// REM Compile Switches REM //////////////////////////////////////////////////////////////////////////// -REM EHa- disable exception handling (we don't use) +REM EHa- disable exception handling (currently it's on /EHsc since libraries need) REM GR- disable c runtime type information (we don't use) REM MD use dynamic runtime library REM MT use static runtime library, so build and link it into exe @@ -39,7 +39,7 @@ REM wd4100 unused argument parameters REM wd4201 nonstandard extension used: nameless struct/union REM wd4189 local variable is initialised but not referenced REM wd4505 unreferenced local function not used will be removed -set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -FAsc +set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -FAsc /I..\src\external\ set DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName% set Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer @@ -61,7 +61,7 @@ REM Compile REM //////////////////////////////////////////////////////////////////////////// del *.pdb >NUL 2>NUL cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags% -cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags% +cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link ..\src\external\easy\easy_profiler.lib /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags% popd set LastError=%ERRORLEVEL% diff --git a/src/external/easy/easy_compiler_support.h b/src/external/easy/easy_compiler_support.h new file mode 100644 index 0000000..e45d1a8 --- /dev/null +++ b/src/external/easy/easy_compiler_support.h @@ -0,0 +1,156 @@ +/************************************************************************ +* file name : easy_compiler_support.h +* ----------------- : +* creation time : 2016/09/22 +* authors : Victor Zarubkin, Sergey Yagovtsev +* emails : v.s.zarubkin@gmail.com, yse.sey@gmail.com +* ----------------- : +* description : This file contains auxiliary profiler macros for different compiler support. +* ----------------- : +* license : Lightweight profiler library for c++ +* : Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin +* : +* : Licensed under either of +* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) +* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +* : at your option. +* : +* : The MIT License +* : +* : Permission is hereby granted, free of charge, to any person obtaining a copy +* : of this software and associated documentation files (the "Software"), to deal +* : in the Software without restriction, including without limitation the rights +* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +* : of the Software, and to permit persons to whom the Software is furnished +* : to do so, subject to the following conditions: +* : +* : The above copyright notice and this permission notice shall be included in all +* : copies or substantial portions of the Software. +* : +* : 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 OR COPYRIGHT HOLDERS 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. +* : +* : The Apache License, Version 2.0 (the "License") +* : +* : You may not use this file except in compliance with the License. +* : You may obtain a copy of the License at +* : +* : http://www.apache.org/licenses/LICENSE-2.0 +* : +* : Unless required by applicable law or agreed to in writing, software +* : distributed under the License is distributed on an "AS IS" BASIS, +* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* : See the License for the specific language governing permissions and +* : limitations under the License. +************************************************************************/ + +#ifndef EASY_PROFILER_COMPILER_SUPPORT_H +#define EASY_PROFILER_COMPILER_SUPPORT_H + +#include + +//#define EASY_CODE_WRAP(Code) Code + +#ifdef _WIN32 +// Visual Studio and MinGW +# ifdef _BUILD_PROFILER +# define PROFILER_API __declspec(dllexport) +# else +# define PROFILER_API __declspec(dllimport) +# endif +#endif + + + +#if defined (_MSC_VER) +////////////////////////////////////////////////////////////////////////// +// Visual Studio + +# define __func__ __FUNCTION__ + +# if _MSC_VER <= 1800 +// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead. +// There is also no support for C++11 magic statics feature :( So it becomes slightly harder to initialize static vars - additional "if" for each profiler block. +# define EASY_THREAD_LOCAL __declspec(thread) +# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\ + __declspec(thread) static VarType VarName = 0;\ + if (!VarName)\ + VarName = VarInitializer +# endif + +#elif defined (__clang__) +////////////////////////////////////////////////////////////////////////// +// Clang Compiler + +# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3) +// There is no support for C++11 thread_local keyword prior to clang 3.3. Use __thread instead. +# define EASY_THREAD_LOCAL __thread +# endif + +# if (__clang_major__ == 2 && __clang_minor__ < 9) || (__clang_major__ < 2) +// There is no support for C++11 magic statics feature prior to clang 2.9. It becomes slightly harder to initialize static vars - additional "if" for each profiler block. +# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\ + EASY_THREAD_LOCAL static VarType VarName = 0;\ + if (!VarName)\ + VarName = VarInitializer + +// There is no support for C++11 final keyword prior to clang 2.9 +# define EASY_FINAL +# endif + +#elif defined(__GNUC__) +////////////////////////////////////////////////////////////////////////// +// GNU Compiler + +# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4) +// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead. +# define EASY_THREAD_LOCAL __thread +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || (__GNUC__ < 4) +// There is no support for C++11 magic statics feature prior to gcc 4.3. It becomes slightly harder to initialize static vars - additional "if" for each profiler block. +# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\ + EASY_THREAD_LOCAL static VarType VarName = 0;\ + if (!VarName)\ + VarName = VarInitializer +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ < 7) || (__GNUC__ < 4) +// There is no support for C++11 final keyword prior to gcc 4.7 +# define EASY_FINAL +# endif + +#endif +// END // TODO: Add other compilers support +////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////////////////// +// Default values + +#ifndef EASY_THREAD_LOCAL +# define EASY_THREAD_LOCAL thread_local +# define EASY_THREAD_LOCAL_CPP11 +#endif + +#ifndef EASY_LOCAL_STATIC_PTR +# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer) static VarType VarName = VarInitializer +# define EASY_MAGIC_STATIC_CPP11 +#endif + +#ifndef EASY_FINAL +# define EASY_FINAL final +#endif + +#ifndef PROFILER_API +# define PROFILER_API +#endif + +////////////////////////////////////////////////////////////////////////// + +#endif // EASY_PROFILER_COMPILER_SUPPORT_H diff --git a/src/external/easy/easy_net.h b/src/external/easy/easy_net.h new file mode 100644 index 0000000..ad8c382 --- /dev/null +++ b/src/external/easy/easy_net.h @@ -0,0 +1,149 @@ +/** +Lightweight profiler library for c++ +Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin + +Licensed under either of + * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +at your option. + +The MIT License + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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 OR COPYRIGHT HOLDERS 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. + + +The Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**/ + +#ifndef EASY_NET_H +#define EASY_NET_H + +#include + +namespace profiler { +namespace net { + +const uint32_t EASY_MESSAGE_SIGN = 20160909; + +#pragma pack(push,1) + +enum MessageType : uint8_t +{ + MESSAGE_TYPE_ZERO = 0, + + MESSAGE_TYPE_REQUEST_START_CAPTURE, + MESSAGE_TYPE_REPLY_START_CAPTURING, + MESSAGE_TYPE_REQUEST_STOP_CAPTURE, + + MESSAGE_TYPE_REPLY_BLOCKS, + MESSAGE_TYPE_REPLY_BLOCKS_END, + + MESSAGE_TYPE_ACCEPTED_CONNECTION, + + MESSAGE_TYPE_REQUEST_BLOCKS_DESCRIPTION, + MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION, + MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION_END, + + MESSAGE_TYPE_EDIT_BLOCK_STATUS, + + MESSAGE_TYPE_EVENT_TRACING_STATUS, + MESSAGE_TYPE_EVENT_TRACING_PRIORITY, + MESSAGE_TYPE_CHECK_CONNECTION, + + MESSAGE_TYPE_REQUEST_MAIN_FRAME_TIME_MAX_AVG_US, + MESSAGE_TYPE_REPLY_MAIN_FRAME_TIME_MAX_AVG_US, +}; + +struct Message +{ + uint32_t magic_number = EASY_MESSAGE_SIGN; + MessageType type = MESSAGE_TYPE_ZERO; + + bool isEasyNetMessage() const + { + return EASY_MESSAGE_SIGN == magic_number; + } + + Message() = default; + Message(MessageType _t):type(_t){} +}; + +struct DataMessage : public Message { + uint32_t size = 0; // bytes + DataMessage(MessageType _t = MESSAGE_TYPE_REPLY_BLOCKS) : Message(_t) {} + DataMessage(uint32_t _s, MessageType _t = MESSAGE_TYPE_REPLY_BLOCKS) : Message(_t), size(_s) {} + const char* data() const { return reinterpret_cast(this) + sizeof(DataMessage); } +}; + +struct BlockStatusMessage : public Message { + uint32_t id; + uint8_t status; + BlockStatusMessage(uint32_t _id, uint8_t _status) : Message(MESSAGE_TYPE_EDIT_BLOCK_STATUS), id(_id), status(_status) { } +private: + BlockStatusMessage() = delete; +}; + +struct EasyProfilerStatus : public Message +{ + bool isProfilerEnabled; + bool isEventTracingEnabled; + bool isLowPriorityEventTracing; + + EasyProfilerStatus(bool _enabled, bool _ETenabled, bool _ETlowp) + : Message(MESSAGE_TYPE_ACCEPTED_CONNECTION) + , isProfilerEnabled(_enabled) + , isEventTracingEnabled(_ETenabled) + , isLowPriorityEventTracing(_ETlowp) + { + } + +private: + + EasyProfilerStatus() = delete; +}; + +struct BoolMessage : public Message { + bool flag = false; + BoolMessage(MessageType _t, bool _flag = false) : Message(_t), flag(_flag) { } + BoolMessage() = default; +}; + +struct TimestampMessage : public Message { + uint32_t maxValue = 0; + uint32_t avgValue = 0; + TimestampMessage(MessageType _t, uint32_t _maxValue, uint32_t _avgValue) : Message(_t), maxValue(_maxValue), avgValue(_avgValue) { } + TimestampMessage() = default; +}; + +#pragma pack(pop) + +}//net + +}//profiler + +#endif // EASY_NET_H diff --git a/src/external/easy/easy_profiler.lib b/src/external/easy/easy_profiler.lib new file mode 100644 index 0000000000000000000000000000000000000000..c3ea6419261b690ea4588da4bac4571cf9495d97 GIT binary patch literal 34256 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 +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include //for android-build +#else + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#endif + +class PROFILER_API EasySocket +{ +public: + +#ifdef _WIN32 + typedef SOCKET socket_t; +#else + typedef int socket_t; +#endif + + enum ConnectionState + { + CONNECTION_STATE_UNKNOWN, + CONNECTION_STATE_SUCCESS, + + CONNECTION_STATE_DISCONNECTED, + CONNECTION_STATE_IN_PROGRESS + }; + +private: + + void checkResult(int result); + bool checkSocket(socket_t s) const; + static int _close(socket_t s); + void setBlocking(socket_t s, bool blocking); + + socket_t m_socket = 0; + socket_t m_replySocket = 0; + + int wsaret = -1; + + struct hostent * server; + struct sockaddr_in serv_addr; + + ConnectionState m_state = CONNECTION_STATE_UNKNOWN; + +public: + + EasySocket(); + ~EasySocket(); + + int send(const void *buf, size_t nbyte); + int receive(void *buf, size_t nbyte); + int listen(int count=5); + int accept(); + int bind(uint16_t portno); + + bool setAddress(const char* serv, uint16_t port); + int connect(); + + void flush(); + void init(); + + void setState(ConnectionState state){m_state=state;} + ConnectionState state() const{return m_state;} + + bool isDisconnected() const + { + return m_state == CONNECTION_STATE_UNKNOWN || + m_state == CONNECTION_STATE_DISCONNECTED; + } +}; + +#endif // EASY________SOCKET_________H diff --git a/src/external/easy/profiler.h b/src/external/easy/profiler.h new file mode 100644 index 0000000..617871d --- /dev/null +++ b/src/external/easy/profiler.h @@ -0,0 +1,933 @@ +/** +Lightweight profiler library for c++ +Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin + +Licensed under either of + * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +at your option. + +The MIT License + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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 OR COPYRIGHT HOLDERS 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. + + +The Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**/ + +#ifndef EASY_PROFILER_H +#define EASY_PROFILER_H + +#include + +#if defined ( __clang__ ) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#endif + +// +// BUILD_WITH_EASY_PROFILER is defined in CMakeLists.txt if your project is linked to easy_profiler. +// + +// +// DISABLE_EASY_PROFILER may be defined manually in source-file before #include +// to disable profiler for certain source-file or project. +// + +#if defined(BUILD_WITH_EASY_PROFILER) && !defined(DISABLE_EASY_PROFILER) + +/** +\defgroup profiler EasyProfiler +*/ + + +/** Indicates that EasyProfiler is used. + +\ingroup profiler +*/ +#define USING_EASY_PROFILER + + +// EasyProfiler core API: + +/** Macro for beginning of a scoped block with custom name and color. + +\code + #include + void foo() + { + // some code ... + + EASY_BLOCK("Check something", profiler::OFF); // Disabled block (There is possibility to enable this block later via GUI) + if(something){ + EASY_BLOCK("Calling bar()"); // Block with default color + bar(); + } + else{ + EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block + baz(); + } + EASY_END_BLOCK; // End of "Check something" block (Even if "Check something" is disabled, this EASY_END_BLOCK will not end any other block). + + EASY_BLOCK("Some another block", profiler::colors::Blue, profiler::ON_WITHOUT_CHILDREN); // Block with Blue color without + // some another code... + EASY_BLOCK("Calculate sum"); // This block will not be profiled because it's parent is ON_WITHOUT_CHILDREN + int sum = 0; + for (int i = 0; i < 10; ++i) + sum += i; + EASY_END_BLOCK; // End of "Calculate sum" block + } +\endcode + +Block will be automatically completed by destructor. + +\ingroup profiler +*/ +# define EASY_BLOCK(name, ...)\ + EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\ + EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__),\ + ::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\ + ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); + +/** Macro for beginning of a non-scoped block with custom name and color. + +You must end such block manually with EASY_END_BLOCK. + +\code + #include + void foo() { + EASY_NONSCOPED_BLOCK("Callback"); // Begin block which would not be finished when function returns. + + // some code ... + } + + void bar() { + // some another code... + + EASY_END_BLOCK; // This, as always, ends last opened block. You have to take care about blocks order by yourself. + } + + void baz() { + foo(); // non-scoped block begins here + + // some code... + + bar(); // non-scoped block ends here + } +\endcode + +Block will be automatically completed by destructor. + +\ingroup profiler +*/ +#define EASY_NONSCOPED_BLOCK(name, ...)\ + EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\ + EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__),\ + ::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\ + ::profiler::beginNonScopedBlock(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name)); + +/** Macro for beginning of a block with function name and custom color. + +\code + #include + void foo(){ + EASY_FUNCTION(); // Block with name="foo" and default color + //some code... + } + + void bar(){ + EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar" + //some code... + } + + void baz(){ + EASY_FUNCTION(profiler::FORCE_ON); // Force enabled block with name="baz" and default color (This block will be profiled even if it's parent is OFF_RECURSIVE) + // som code... + } +\endcode + +Name of the block automatically created with function name. + +\ingroup profiler +*/ +# define EASY_FUNCTION(...)\ + EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\ + EASY_UNIQUE_LINE_ID, __func__, __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__), false));\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(EASY_UNIQUE_DESC(__LINE__), "");\ + ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable + +/** Macro for completion of last opened block explicitly. + +\code +#include +int foo() +{ + // some code ... + + int sum = 0; + EASY_BLOCK("Calculating sum"); + for (int i = 0; i < 10; ++i){ + sum += i; + } + EASY_END_BLOCK; + + // some antoher code here ... + + return sum; +} +\endcode + +\ingroup profiler +*/ +# define EASY_END_BLOCK ::profiler::endBlock(); + +/** Macro for creating event marker with custom name and color. + +Event marker is a block with zero duration and special type. + +\warning Event marker ends immidiately and calling EASY_END_BLOCK after EASY_EVENT +will end previously opened EASY_BLOCK or EASY_FUNCTION. + +\ingroup profiler +*/ +# define EASY_EVENT(name, ...)\ + EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\ + ::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\ + __FILE__, __LINE__, ::profiler::BLOCK_TYPE_EVENT, ::profiler::extract_color(__VA_ARGS__),\ + ::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\ + ::profiler::storeEvent(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name)); + +/** Macro for enabling profiler. + +\ingroup profiler +*/ +# define EASY_PROFILER_ENABLE ::profiler::setEnabled(true); + +/** Macro for disabling profiler. + +\ingroup profiler +*/ +# define EASY_PROFILER_DISABLE ::profiler::setEnabled(false); + +/** Macro for current thread registration. + +\note If this thread has been already registered then nothing happens. + +\ingroup profiler +*/ +# define EASY_THREAD(name)\ + EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = 0;\ + if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\ + EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThread(name); + +/** Macro for current thread registration and creating a thread guard object. + +\note If this thread has been already registered then nothing happens. + +\note Also creates thread guard which marks thread as "expired" on it's destructor +and creates "ThreadFinished" profiler event. + +\ingroup profiler +*/ +# define EASY_THREAD_SCOPE(name)\ + EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = 0;\ + ::profiler::ThreadGuard EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__);\ + if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\ + EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThreadScoped(name,\ + EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__)); + +/** Macro for main thread registration. + +This is just for user's comfort. There is no difference for EasyProfiler GUI between different threads. + +\ingroup profiler +*/ +# define EASY_MAIN_THREAD EASY_THREAD("Main") + +/** Enable or disable event tracing (context switch events). + +\note Default value is controlled by EASY_OPTION_EVENT_TRACING_ENABLED macro. + +\note Change will take effect on the next call to EASY_PROFILER_ENABLE. + +\sa EASY_PROFILER_ENABLE, EASY_OPTION_EVENT_TRACING_ENABLED + +\ingroup profiler +*/ +# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled) ::profiler::setEventTracingEnabled(isEnabled); + +/** Set event tracing thread priority (low or normal). + +Event tracing with low priority will affect your application performance much more less, but +it can be late to gather information about thread/process (thread could be finished to the moment +when event tracing thread will be awaken) and you will not see process name and process id +information in GUI for such threads. You will still be able to see all context switch events. + +Event tracing with normal priority could gather more information about processes but potentially +it could affect performance as it has more work to do. Usually you will not notice any performance +breakdown, but if you care about that then you change set event tracing priority level to low. + +\sa EASY_OPTION_LOW_PRIORITY_EVENT_TRACING + +\ingroup profiler +*/ +# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority) ::profiler::setLowPriorityEventTracing(isLowPriority); + +/** Macro for setting temporary log-file path for Unix event tracing system. + +\note Default value is "/tmp/cs_profiling_info.log". + +\ingroup profiler +*/ +# define EASY_EVENT_TRACING_SET_LOG(filename) ::profiler::setContextSwitchLogFilename(filename); + +/** Macro returning current path to the temporary log-file for Unix event tracing system. + +\ingroup profiler +*/ +# define EASY_EVENT_TRACING_LOG ::profiler::getContextSwitchLogFilename(); + +// EasyProfiler settings: + +/** If != 0 then EasyProfiler will measure time for blocks storage expansion. +If 0 then EasyProfiler will be compiled without blocks of code responsible +for measuring these events. + +These are "EasyProfiler.ExpandStorage" blocks on a diagram. + +\ingroup profiler +*/ +# ifndef EASY_OPTION_MEASURE_STORAGE_EXPAND +# define EASY_OPTION_MEASURE_STORAGE_EXPAND 0 +# endif + +# if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0 +/** If true then "EasyProfiler.ExpandStorage" blocks are enabled by default and will be +writed to output file or translated over the net. +If false then you need to enable these blocks via GUI if you want to see them. + +\ingroup profiler +*/ +# ifndef EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON +# define EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON true +# endif + +# endif // EASY_OPTION_MEASURE_STORAGE_EXPAND != 0 + +/** If true then EasyProfiler event tracing is enabled by default +and will be turned on and off when you call profiler::setEnabled(). +Otherwise, it have to be turned on via GUI and then it will be +turned on/off with next calls of profiler::setEnabled(). + +\ingroup profiler +*/ +# ifndef EASY_OPTION_EVENT_TRACING_ENABLED +# define EASY_OPTION_EVENT_TRACING_ENABLED true +# endif + +/** If true then EasyProfiler.ETW thread (Event tracing for Windows) will have low priority by default. + +\sa EASY_SET_LOW_PRIORITY_EVENT_TRACING + +\note You can always change priority level via GUI or API while profiling session is not launched. +You don't need to rebuild or restart your application for that. + +\ingroup profiler +*/ +# ifndef EASY_OPTION_LOW_PRIORITY_EVENT_TRACING +# define EASY_OPTION_LOW_PRIORITY_EVENT_TRACING true +# endif + + +/** If != 0 then EasyProfiler will print error messages into stderr. +Otherwise, no log messages will be printed. + +\ingroup profiler +*/ +# ifndef EASY_OPTION_LOG_ENABLED +# define EASY_OPTION_LOG_ENABLED 0 +# endif + +/** If != 0 then EasyProfiler will start listening thread immidiately on ProfileManager initialization. + +\sa startListen + +\ingroup profiler +*/ +# ifndef EASY_OPTION_START_LISTEN_ON_STARTUP +# define EASY_OPTION_START_LISTEN_ON_STARTUP 0 +# endif + +#else // #ifdef BUILD_WITH_EASY_PROFILER + +# define EASY_BLOCK(...) +# define EASY_NONSCOPED_BLOCK(...) +# define EASY_FUNCTION(...) +# define EASY_END_BLOCK +# define EASY_PROFILER_ENABLE +# define EASY_PROFILER_DISABLE +# define EASY_EVENT(...) +# define EASY_THREAD(...) +# define EASY_THREAD_SCOPE(...) +# define EASY_MAIN_THREAD +# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled) +# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority) + +# ifndef _WIN32 +# define EASY_EVENT_TRACING_SET_LOG(filename) +# define EASY_EVENT_TRACING_LOG "" +# endif + +# ifndef EASY_OPTION_MEASURE_STORAGE_EXPAND +# define EASY_OPTION_MEASURE_STORAGE_EXPAND 0 +# endif + +# ifndef EASY_OPTION_EVENT_TRACING_ENABLED +# define EASY_OPTION_EVENT_TRACING_ENABLED false +# endif + +# ifndef EASY_OPTION_LOW_PRIORITY_EVENT_TRACING +# define EASY_OPTION_LOW_PRIORITY_EVENT_TRACING true +# endif + +# ifndef EASY_OPTION_LOG_ENABLED +# define EASY_OPTION_LOG_ENABLED 0 +# endif + +# ifndef EASY_OPTION_START_LISTEN_ON_STARTUP +# define EASY_OPTION_START_LISTEN_ON_STARTUP 0 +# endif + +#endif // #ifndef BUILD_WITH_EASY_PROFILER + +# ifndef EASY_DEFAULT_PORT +# define EASY_DEFAULT_PORT 28077 +# endif + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +class NonscopedBlock; +class ProfileManager; +struct ThreadStorage; + +namespace profiler { + + ////////////////////////////////////////////////////////////////////// + // Core types + + const uint16_t DEFAULT_PORT = EASY_DEFAULT_PORT; + + typedef uint64_t timestamp_t; + typedef uint32_t thread_id_t; + typedef uint32_t block_id_t; + + enum BlockType : uint8_t + { + BLOCK_TYPE_EVENT = 0, + BLOCK_TYPE_BLOCK, + + BLOCK_TYPES_NUMBER + }; + typedef BlockType block_type_t; + + enum Duration : uint8_t + { + TICKS = 0, ///< CPU ticks + MICROSECONDS ///< Microseconds + }; + + //*********************************************** + +#pragma pack(push,1) + class PROFILER_API BaseBlockDescriptor + { + friend ::ProfileManager; + friend ::ThreadStorage; + + protected: + + block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors) + int m_line; ///< Line number in the source file + color_t m_color; ///< Color of the block packed into 1-byte structure + block_type_t m_type; ///< Type of the block (See BlockType) + EasyBlockStatus m_status; ///< If false then blocks with such id() will not be stored by profiler during profile session + + BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color); + + public: + + inline block_id_t id() const { return m_id; } + inline int line() const { return m_line; } + inline color_t color() const { return m_color; } + inline block_type_t type() const { return m_type; } + inline EasyBlockStatus status() const { return m_status; } + + }; // END of class BaseBlockDescriptor. + + //*********************************************** + + class PROFILER_API BaseBlockData + { + friend ::ProfileManager; + + protected: + + timestamp_t m_begin; + timestamp_t m_end; + block_id_t m_id; + + public: + + BaseBlockData(const BaseBlockData&) = default; + BaseBlockData(timestamp_t _begin_time, block_id_t _id); + BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id); + + inline timestamp_t begin() const { return m_begin; } + inline timestamp_t end() const { return m_end; } + inline block_id_t id() const { return m_id; } + inline timestamp_t duration() const { return m_end - m_begin; } + + inline void setId(block_id_t _id) { m_id = _id; } + + private: + + BaseBlockData() = delete; + + }; // END of class BaseBlockData. +#pragma pack(pop) + + //*********************************************** + + class PROFILER_API Block : public BaseBlockData + { + friend ::ProfileManager; + friend ::ThreadStorage; + friend ::NonscopedBlock; + + const char* m_name; + EasyBlockStatus m_status; + bool m_isScoped; + + private: + + void start(); + void start(timestamp_t _time); + void finish(); + void finish(timestamp_t _time); + inline bool finished() const { return m_end >= m_begin; } + inline EasyBlockStatus status() const { return m_status; } + inline void setStatus(EasyBlockStatus _status) { m_status = _status; } + + public: + + Block(Block&& that); + Block(const BaseBlockDescriptor* _desc, const char* _runtimeName, bool _scoped = true); + Block(timestamp_t _begin_time, block_id_t _id, const char* _runtimeName); + Block(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id, const char* _runtimeName); + ~Block(); + + inline const char* name() const { return m_name; } + + private: + + Block(const Block&) = delete; + Block& operator = (const Block&) = delete; + + }; // END of class Block. + + //*********************************************** + + class PROFILER_API ThreadGuard EASY_FINAL { + friend ::ProfileManager; + thread_id_t m_id = 0; + public: + ~ThreadGuard(); + }; // END of class ThreadGuard. + + ////////////////////////////////////////////////////////////////////// + // Core API + // Note: it is better to use macros defined above than a direct calls to API. + +#ifdef BUILD_WITH_EASY_PROFILER + extern "C" { + + /** Returns current time in ticks. + + You can use it if you want to store block explicitly. + + \ingroup profiler + */ + PROFILER_API timestamp_t currentTime(); + + /** Convert ticks to nanoseconds. + + \ingroup profiler + */ + PROFILER_API timestamp_t toNanoseconds(timestamp_t _ticks); + + /** Convert ticks to microseconds. + + \ingroup profiler + */ + PROFILER_API timestamp_t toMicroseconds(timestamp_t _ticks); + + /** Registers static description of a block. + + It is general information which is common for all such blocks. + Includes color, block type (see BlockType), file-name, line-number, compile-time name of a block and enable-flag. + + \note This API function is used by EASY_EVENT, EASY_BLOCK, EASY_FUNCTION macros. + There is no need to invoke this function explicitly. + + \ingroup profiler + */ + PROFILER_API const BaseBlockDescriptor* registerDescription(EasyBlockStatus _status, const char* _autogenUniqueId, const char* _compiletimeName, const char* _filename, int _line, block_type_t _block_type, color_t _color, bool _copyName = false); + + /** Stores event in the blocks list. + + An event ends instantly and has zero duration. + + \note There is no need to invoke this function explicitly - use EASY_EVENT macro instead. + + \param _desc Reference to the previously registered description. + \param _runtimeName Standard zero-terminated string which will be copied to the events buffer. + + \note _runtimeName must be an empty string ("") if you do not want to set name to the event at run-time. + + \ingroup profiler + */ + PROFILER_API void storeEvent(const BaseBlockDescriptor* _desc, const char* _runtimeName = ""); + + /** Stores block explicitly in the blocks list. + + Use this function for additional flexibility if you want to set block duration manually. + + \param _desc Reference to the previously registered description. + \param _runtimeName Standard zero-terminated string which will be copied to the events buffer. + \param _beginTime begin time of the block + \param _endTime end time of the block + + \note _runtimeName must be an empty string ("") if you do not want to set name to the block at run-time. + + \ingroup profiler + */ + PROFILER_API void storeBlock(const BaseBlockDescriptor* _desc, const char* _runtimeName, timestamp_t _beginTime, timestamp_t _endTime); + + /** Begins scoped block. + + \ingroup profiler + */ + PROFILER_API void beginBlock(Block& _block); + + /** Begins non-scoped block. + + \param _desc Reference to the previously registered description (see registerDescription). + \param _runtimeName Standard zero-terminated string which will be copied to the block buffer when block will end. + + \note There is no need to invoke this function explicitly - use EASY_NONSCOPED_BLOCK macro instead. + EASY_NONSCOPED_BLOCK macro could be used for higher flexibility if you have to begin block in one + function and end it in another one. + + \note _runtimeName must be an empty string ("") if you do not want to set name to the block at run-time. + \note _runtimeName is copied only when block ends so you must ensure it's validity until block end. + + \warning You have to end this block explicitly. + + \ingroup profiler + */ + PROFILER_API void beginNonScopedBlock(const BaseBlockDescriptor* _desc, const char* _runtimeName = ""); + + /** Ends last started block. + + Use this only if you want to finish block explicitly. + + \ingroup profiler + */ + PROFILER_API void endBlock(); + + /** Enable or disable profiler. + + \ingroup profiler + */ + PROFILER_API void setEnabled(bool _isEnable); + PROFILER_API bool isEnabled(); + + /** Save all gathered blocks into file. + + \note This also disables profiler. + + \ingroup profiler + */ + PROFILER_API uint32_t dumpBlocksToFile(const char* _filename); + + /** Register current thread and give it a name. + + \note Only first call of registerThread() for the current thread will have an effect. + + \ingroup profiler + */ + PROFILER_API const char* registerThreadScoped(const char* _name, ThreadGuard&); + + /** Register current thread and give it a name. + + \note Only first call of registerThread() for the current thread will have an effect. + + \ingroup profiler + */ + PROFILER_API const char* registerThread(const char* _name); + + /** Enable or disable event tracing. + + \note This change will take an effect on the next call of setEnabled(true); + + \sa setEnabled, EASY_SET_EVENT_TRACING_ENABLED + + \ingroup profiler + */ + PROFILER_API void setEventTracingEnabled(bool _isEnable); + PROFILER_API bool isEventTracingEnabled(); + + /** Set event tracing thread priority (low or normal). + + \note This change will take effect on the next call of setEnabled(true); + + \sa setEnabled, EASY_SET_LOW_PRIORITY_EVENT_TRACING + + \ingroup profiler + */ + PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority); + PROFILER_API bool isLowPriorityEventTracing(); + + /** Set temporary log-file path for Unix event tracing system. + + \note Default value is "/tmp/cs_profiling_info.log". + + \ingroup profiler + */ + PROFILER_API void setContextSwitchLogFilename(const char* _name); + + /** Returns current path to the temporary log-file for Unix event tracing system. + + \ingroup profiler + */ + PROFILER_API const char* getContextSwitchLogFilename(); + + PROFILER_API void startListen(uint16_t _port = ::profiler::DEFAULT_PORT); + PROFILER_API void stopListen(); + PROFILER_API bool isListening(); + + /** Returns current major version. + + \ingroup profiler + */ + PROFILER_API uint8_t versionMajor(); + + /** Returns current minor version. + + \ingroup profiler + */ + PROFILER_API uint8_t versionMinor(); + + /** Returns current version patch. + + \ingroup profiler + */ + PROFILER_API uint16_t versionPatch(); + + /** Returns current version in 32-bit integer format. + + \ingroup profiler + */ + PROFILER_API uint32_t version(); + + /** Returns current version in 32-bit integer format. + + \ingroup profiler + */ + PROFILER_API const char* versionName(); + + /** Returns true if current thread has been marked as Main. + Otherwise, returns false. + */ + PROFILER_API bool isMainThread(); + + /** Returns last frame duration for current thread. + + \param _durationCast desired duration units (could be cpu-ticks or microseconds) + */ + PROFILER_API timestamp_t this_thread_frameTime(Duration _durationCast = ::profiler::MICROSECONDS); + + /** Returns local max of frame duration for current thread. + + Local max is maximum frame duration since last frameTimeLocalMax() call. + + \param _durationCast desired duration units (could be cpu-ticks or microseconds) + */ + PROFILER_API timestamp_t this_thread_frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS); + + /** Returns local average of frame duration for current thread. + + Local average is average frame duration since last frameTimeLocalAvg() call. + + \param _durationCast desired duration units (could be cpu-ticks or microseconds) + */ + PROFILER_API timestamp_t this_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS); + + /** Returns last frame duration for main thread. + + \param _durationCast desired duration units (could be cpu-ticks or microseconds) + */ + PROFILER_API timestamp_t main_thread_frameTime(Duration _durationCast = ::profiler::MICROSECONDS); + + /** Returns local max of frame duration for main thread. + + Local max is maximum frame duration since last frameTimeLocalMax() call. + + \param _durationCast desired duration units (could be cpu-ticks or microseconds) + */ + PROFILER_API timestamp_t main_thread_frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS); + + /** Returns local average of frame duration for main thread. + + Local average is average frame duration since last frameTimeLocalAvg() call. + + \param _durationCast desired duration units (could be cpu-ticks or microseconds) + */ + PROFILER_API timestamp_t main_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS); + + } +#else + inline timestamp_t currentTime() { return 0; } + inline timestamp_t toNanoseconds(timestamp_t) { return 0; } + inline timestamp_t toMicroseconds(timestamp_t) { return 0; } + inline const BaseBlockDescriptor* registerDescription(EasyBlockStatus, const char*, const char*, const char*, int, block_type_t, color_t, bool = false) + { return reinterpret_cast(0xbad); } + inline void endBlock() { } + inline void setEnabled(bool) { } + inline bool isEnabled() { return false; } + inline void storeEvent(const BaseBlockDescriptor*, const char* = "") { } + inline void storeBlock(const BaseBlockDescriptor*, const char*, timestamp_t, timestamp_t) { } + inline void beginBlock(Block&) { } + inline void beginNonScopedBlock(const BaseBlockDescriptor*, const char* = "") { } + inline uint32_t dumpBlocksToFile(const char*) { return 0; } + inline const char* registerThreadScoped(const char*, ThreadGuard&) { return ""; } + inline const char* registerThread(const char*) { return ""; } + inline void setEventTracingEnabled(bool) { } + inline bool isEventTracingEnabled() { return false; } + inline void setLowPriorityEventTracing(bool) { } + inline bool isLowPriorityEventTracing() { return false; } + inline void setContextSwitchLogFilename(const char*) { } + inline const char* getContextSwitchLogFilename() { return ""; } + inline void startListen(uint16_t = ::profiler::DEFAULT_PORT) { } + inline void stopListen() { } + inline bool isListening() { return false; } + inline uint8_t versionMajor() { return 0; } + inline uint8_t versionMinor() { return 0; } + inline uint16_t versionPatch() { return 0; } + inline uint32_t version() { return 0; } + inline const char* versionName() { return "v0.0.0_disabled"; } + inline bool isMainThread() { return false; } + inline timestamp_t this_thread_frameTime(Duration = ::profiler::MICROSECONDS) { return 0; } + inline timestamp_t this_thread_frameTimeLocalMax(Duration = ::profiler::MICROSECONDS) { return 0; } + inline timestamp_t this_thread_frameTimeLocalAvg(Duration = ::profiler::MICROSECONDS) { return 0; } + inline timestamp_t main_thread_frameTime(Duration = ::profiler::MICROSECONDS) { return 0; } + inline timestamp_t main_thread_frameTimeLocalMax(Duration = ::profiler::MICROSECONDS) { return 0; } + inline timestamp_t main_thread_frameTimeLocalAvg(Duration = ::profiler::MICROSECONDS) { return 0; } +#endif + + /** API functions binded to current thread. + + \ingroup profiler + */ + namespace this_thread { + + inline const char* registrate(const char* _name) { + return ::profiler::registerThread(_name); + } + + inline const char* registrate(const char* _name, ThreadGuard& _threadGuard) { + return ::profiler::registerThreadScoped(_name, _threadGuard); + } + + inline timestamp_t frameTime(Duration _durationCast = ::profiler::MICROSECONDS) { + return ::profiler::this_thread_frameTime(_durationCast); + } + + inline timestamp_t frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS) { + return ::profiler::this_thread_frameTimeLocalMax(_durationCast); + } + + inline timestamp_t frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS) { + return ::profiler::this_thread_frameTimeLocalAvg(_durationCast); + } + + inline bool isMain() { + return ::profiler::isMainThread(); + } + + } // END of namespace this_thread. + + /** API functions binded to main thread. + + Could be called from any thread. + + \ingroup profiler + */ + namespace main_thread { + + inline timestamp_t frameTime(Duration _durationCast = ::profiler::MICROSECONDS) { + return ::profiler::main_thread_frameTime(_durationCast); + } + + inline timestamp_t frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS) { + return ::profiler::main_thread_frameTimeLocalMax(_durationCast); + } + + inline timestamp_t frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS) { + return ::profiler::main_thread_frameTimeLocalAvg(_durationCast); + } + + /** Always returns true. + */ + inline bool isMain() { + return true; + } + + } // END of namespace main_thread. + + ////////////////////////////////////////////////////////////////////// + +} // END of namespace profiler. + +#if defined ( __clang__ ) +# pragma clang diagnostic pop +#endif + +#endif // EASY_PROFILER_H diff --git a/src/external/easy/profiler_aux.h b/src/external/easy/profiler_aux.h new file mode 100644 index 0000000..73ccec7 --- /dev/null +++ b/src/external/easy/profiler_aux.h @@ -0,0 +1,209 @@ +/************************************************************************ +* file name : profiler_aux.h +* ----------------- : +* creation time : 2016/06/11 +* author : Victor Zarubkin +* email : v.s.zarubkin@gmail.com +* ----------------- : +* description : This file contains auxiliary profiler macros and funcitons. +* ----------------- : +* change log : * 2016/06/11 Victor Zarubkin: Moved sources from profiler.h +* : +* : * +* ----------------- : +* license : Lightweight profiler library for c++ +* : Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin +* : +* : Licensed under either of +* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) +* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +* : at your option. +* : +* : The MIT License +* : +* : Permission is hereby granted, free of charge, to any person obtaining a copy +* : of this software and associated documentation files (the "Software"), to deal +* : in the Software without restriction, including without limitation the rights +* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +* : of the Software, and to permit persons to whom the Software is furnished +* : to do so, subject to the following conditions: +* : +* : The above copyright notice and this permission notice shall be included in all +* : copies or substantial portions of the Software. +* : +* : 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 OR COPYRIGHT HOLDERS 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. +* : +* : The Apache License, Version 2.0 (the "License") +* : +* : You may not use this file except in compliance with the License. +* : You may obtain a copy of the License at +* : +* : http://www.apache.org/licenses/LICENSE-2.0 +* : +* : Unless required by applicable law or agreed to in writing, software +* : distributed under the License is distributed on an "AS IS" BASIS, +* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* : See the License for the specific language governing permissions and +* : limitations under the License. +************************************************************************/ + +#ifndef EASY_PROFILER_AUX_H +#define EASY_PROFILER_AUX_H + +#include + +#include +#include + +////////////////////////////////////////////////////////////////////////// + +namespace profiler { + + enum EasyBlockStatus : uint8_t { + OFF = 0, ///< The block is OFF + ON = 1, ///< The block is ON (but if it's parent block is off recursively then this block will be off too) + FORCE_ON = ON | 2, ///< The block is ALWAYS ON (even if it's parent has turned off all children) + OFF_RECURSIVE = 4, ///< The block is OFF and all of it's children by call-stack are also OFF. + ON_WITHOUT_CHILDREN = ON | OFF_RECURSIVE, ///< The block is ON but all of it's children are OFF. + FORCE_ON_WITHOUT_CHILDREN = FORCE_ON | OFF_RECURSIVE, ///< The block is ALWAYS ON but all of it's children are OFF. + }; + + struct passthrough_hash EASY_FINAL { + template inline size_t operator () (T _value) const { + return static_cast(_value); + } + }; + +} + +////////////////////////////////////////////////////////////////////////// + +#include +#include + +# define EASY_STRINGIFY(a) #a +# define EASY_STRINGIFICATION(a) EASY_STRINGIFY(a) +# define EASY_TOKEN_JOIN(x, y) x ## y +# define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y) +# define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x) +# define EASY_UNIQUE_FRAME_COUNTER(x) EASY_TOKEN_CONCATENATE(unique_profiler_frame_mark_name_, x) +# define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x) + +#ifdef BUILD_WITH_EASY_PROFILER + +namespace profiler { + + template struct NameSwitch; + + class ForceConstStr EASY_FINAL { + friend NameSwitch; + friend NameSwitch; + + const char* c_str; + + ForceConstStr() = delete; + ForceConstStr(const ForceConstStr&) = delete; + ForceConstStr(ForceConstStr&&) = delete; + ForceConstStr& operator = (const ForceConstStr&) = delete; + ForceConstStr& operator = (ForceConstStr&&) = delete; + + public: + + ForceConstStr(const char* _str) : c_str(_str) {} + ForceConstStr(const ::std::string& _str) : c_str(_str.c_str()) {} + }; + + template struct NameSwitch EASY_FINAL { + static const char* runtime_name(const char* name) { return name; } + static const char* runtime_name(const ::std::string& name) { return name.c_str(); } + static const char* runtime_name(const ForceConstStr&) { return ""; } + + template + static const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; } + static const char* compiletime_name(const char*, const char* autoGeneratedName) { return autoGeneratedName; } + static const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; } + }; + + template <> struct NameSwitch EASY_FINAL { + static const char* runtime_name(const char*) { return ""; } + static const char* runtime_name(const ::std::string& name) { return name.c_str(); } + static const char* runtime_name(const ForceConstStr&) { return ""; } + + template + static const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; } + static const char* compiletime_name(const char* name, const char*) { return name; } + static const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; } + }; + + //*********************************************** + + inline color_t extract_color() { + return ::profiler::colors::Default; + } + + template + inline color_t extract_color(::profiler::EasyBlockStatus, TArgs...) { + return ::profiler::colors::Default; + } + + template + inline color_t extract_color(color_t _color, TArgs...) { + return _color; + } + + template + inline color_t extract_color(T, color_t _color, TArgs...) { + return _color; + } + + template + inline color_t extract_color(TArgs...) { + static_assert(sizeof...(TArgs) < 2, "No profiler::color_t in arguments list for EASY_BLOCK(name, ...)!"); + return ::profiler::colors::Default; + } + + //*********************************************** + + inline EasyBlockStatus extract_enable_flag() { + return ::profiler::ON; + } + + template + inline EasyBlockStatus extract_enable_flag(T, ::profiler::EasyBlockStatus _flag, TArgs...) { + return _flag; + } + + template + inline EasyBlockStatus extract_enable_flag(::profiler::EasyBlockStatus _flag, TArgs...) { + return _flag; + } + + template + inline EasyBlockStatus extract_enable_flag(TArgs...) { + static_assert(sizeof...(TArgs) < 2, "No EasyBlockStatus in arguments list for EASY_BLOCK(name, ...)!"); + return ::profiler::ON; + } + + //*********************************************** + +} // END of namespace profiler. + +# define EASY_UNIQUE_LINE_ID __FILE__ ":" EASY_STRINGIFICATION(__LINE__) +# define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::compiletime_name(name, EASY_UNIQUE_LINE_ID) +# define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::runtime_name(name) +# define EASY_CONST_NAME(name) ::profiler::ForceConstStr(name) + +#else + +# define EASY_CONST_NAME(name) + +#endif // BUILD_WITH_EASY_PROFILER + +////////////////////////////////////////////////////////////////////////// + +#endif // EASY_PROFILER_AUX_H diff --git a/src/external/easy/profiler_colors.h b/src/external/easy/profiler_colors.h new file mode 100644 index 0000000..c40e071 --- /dev/null +++ b/src/external/easy/profiler_colors.h @@ -0,0 +1,412 @@ +/** +Lightweight profiler library for c++ +Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin + +Licensed under either of + * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +at your option. + +The MIT License + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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 OR COPYRIGHT HOLDERS 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. + + +The Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**/ + +#ifndef EASY_PROFILER_COLORS_H +#define EASY_PROFILER_COLORS_H + +#include + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +namespace profiler { + + typedef uint32_t color_t; // Standard four-byte ARGB color format + + namespace colors { + + ///< Change alpha for color. Only 8 major bytes (0xff000000) used from alpha. + inline color_t modify_alpha32(color_t _color, color_t _alpha) { + return (_alpha & 0xff000000) | (_color & 0x00ffffff); + } + + ///< Change alpha for color. + inline color_t modify_alpha8(color_t _color, uint8_t _alpha) { + return (static_cast(_alpha) << 24) | (_color & 0x00ffffff); + } + + ///< Create color from ARGB components. + inline color_t color(uint8_t _red, uint8_t _green, uint8_t _blue, uint8_t _alpha = 0xff) { + return (static_cast(_alpha) << 24) | (static_cast(_red) << 16) | (static_cast(_green) << 8) | static_cast(_blue); + } + +#if !defined(EASY_OPTION_BUILTIN_COLORS) || EASY_OPTION_BUILTIN_COLORS != 0 + // Google Material Design colors + // See https://material.google.com/style/color.html + + const color_t Red50 = 0xffffebee; + const color_t Red100 = 0xffffcdd2; + const color_t Red200 = 0xffef9a9a; + const color_t Red300 = 0xffe57373; + const color_t Red400 = 0xffef5350; + const color_t Red500 = 0xfff44336; + const color_t Red600 = 0xffe53935; + const color_t Red700 = 0xffd32f2f; + const color_t Red800 = 0xffc62828; + const color_t Red900 = 0xffb71c1c; + const color_t RedA100 = 0xffff8a80; + const color_t RedA200 = 0xffff5252; + const color_t RedA400 = 0xffff1744; + const color_t RedA700 = 0xffd50000; + + const color_t Pink50 = 0xfffce4ec; + const color_t Pink100 = 0xfff8bbd0; + const color_t Pink200 = 0xfff48fb1; + const color_t Pink300 = 0xfff06292; + const color_t Pink400 = 0xffec407a; + const color_t Pink500 = 0xffe91e63; + const color_t Pink600 = 0xffd81b60; + const color_t Pink700 = 0xffc2185b; + const color_t Pink800 = 0xffad1457; + const color_t Pink900 = 0xff880e4f; + const color_t PinkA100 = 0xffff80ab; + const color_t PinkA200 = 0xffff4081; + const color_t PinkA400 = 0xfff50057; + const color_t PinkA700 = 0xffc51162; + + const color_t Purple50 = 0xfff3e5f5; + const color_t Purple100 = 0xffe1bee7; + const color_t Purple200 = 0xffce93d8; + const color_t Purple300 = 0xffba68c8; + const color_t Purple400 = 0xffab47bc; + const color_t Purple500 = 0xff9c27b0; + const color_t Purple600 = 0xff8e24aa; + const color_t Purple700 = 0xff7b1fa2; + const color_t Purple800 = 0xff6a1b9a; + const color_t Purple900 = 0xff4a148c; + const color_t PurpleA100 = 0xffea80fc; + const color_t PurpleA200 = 0xffe040fb; + const color_t PurpleA400 = 0xffd500f9; + const color_t PurpleA700 = 0xffaa00ff; + + const color_t DeepPurple50 = 0xffede7f6; + const color_t DeepPurple100 = 0xffd1c4e9; + const color_t DeepPurple200 = 0xffb39ddb; + const color_t DeepPurple300 = 0xff9575cd; + const color_t DeepPurple400 = 0xff7e57c2; + const color_t DeepPurple500 = 0xff673ab7; + const color_t DeepPurple600 = 0xff5e35b1; + const color_t DeepPurple700 = 0xff512da8; + const color_t DeepPurple800 = 0xff4527a0; + const color_t DeepPurple900 = 0xff311b92; + const color_t DeepPurpleA100 = 0xffb388ff; + const color_t DeepPurpleA200 = 0xff7c4dff; + const color_t DeepPurpleA400 = 0xff651fff; + const color_t DeepPurpleA700 = 0xff6200ea; + + const color_t Indigo50 = 0xffe8eaf6; + const color_t Indigo100 = 0xffc5cae9; + const color_t Indigo200 = 0xff9fa8da; + const color_t Indigo300 = 0xff7986cb; + const color_t Indigo400 = 0xff5c6bc0; + const color_t Indigo500 = 0xff3f51b5; + const color_t Indigo600 = 0xff3949ab; + const color_t Indigo700 = 0xff303f9f; + const color_t Indigo800 = 0xff283593; + const color_t Indigo900 = 0xff1a237e; + const color_t IndigoA100 = 0xff8c9eff; + const color_t IndigoA200 = 0xff536dfe; + const color_t IndigoA400 = 0xff3d5afe; + const color_t IndigoA700 = 0xff304ffe; + + const color_t Blue50 = 0xffe3f2fd; + const color_t Blue100 = 0xffbbdefb; + const color_t Blue200 = 0xff90caf9; + const color_t Blue300 = 0xff64b5f6; + const color_t Blue400 = 0xff42a5f5; + const color_t Blue500 = 0xff2196f3; + const color_t Blue600 = 0xff1e88e5; + const color_t Blue700 = 0xff1976d2; + const color_t Blue800 = 0xff1565c0; + const color_t Blue900 = 0xff0d47a1; + const color_t BlueA100 = 0xff82b1ff; + const color_t BlueA200 = 0xff448aff; + const color_t BlueA400 = 0xff2979ff; + const color_t BlueA700 = 0xff2962ff; + + const color_t LightBlue50 = 0xffe1f5fe; + const color_t LightBlue100 = 0xffb3e5fc; + const color_t LightBlue200 = 0xff81d4fa; + const color_t LightBlue300 = 0xff4fc3f7; + const color_t LightBlue400 = 0xff29b6f6; + const color_t LightBlue500 = 0xff03a9f4; + const color_t LightBlue600 = 0xff039be5; + const color_t LightBlue700 = 0xff0288d1; + const color_t LightBlue800 = 0xff0277bd; + const color_t LightBlue900 = 0xff01579b; + const color_t LightBlueA100 = 0xff80d8ff; + const color_t LightBlueA200 = 0xff40c4ff; + const color_t LightBlueA400 = 0xff00b0ff; + const color_t LightBlueA700 = 0xff0091ea; + + const color_t Cyan50 = 0xffe0f7fa; + const color_t Cyan100 = 0xffb2ebf2; + const color_t Cyan200 = 0xff80deea; + const color_t Cyan300 = 0xff4dd0e1; + const color_t Cyan400 = 0xff26c6da; + const color_t Cyan500 = 0xff00bcd4; + const color_t Cyan600 = 0xff00acc1; + const color_t Cyan700 = 0xff0097a7; + const color_t Cyan800 = 0xff00838f; + const color_t Cyan900 = 0xff006064; + const color_t CyanA100 = 0xff84ffff; + const color_t CyanA200 = 0xff18ffff; + const color_t CyanA400 = 0xff00e5ff; + const color_t CyanA700 = 0xff00b8d4; + + const color_t Teal50 = 0xffe0f2f1; + const color_t Teal100 = 0xffb2dfdb; + const color_t Teal200 = 0xff80cbc4; + const color_t Teal300 = 0xff4db6ac; + const color_t Teal400 = 0xff26a69a; + const color_t Teal500 = 0xff009688; + const color_t Teal600 = 0xff00897b; + const color_t Teal700 = 0xff00796b; + const color_t Teal800 = 0xff00695c; + const color_t Teal900 = 0xff004d40; + const color_t TealA100 = 0xffa7ffeb; + const color_t TealA200 = 0xff64ffda; + const color_t TealA400 = 0xff1de9b6; + const color_t TealA700 = 0xff00bfa5; + + const color_t Green50 = 0xffe8f5e9; + const color_t Green100 = 0xffc8e6c9; + const color_t Green200 = 0xffa5d6a7; + const color_t Green300 = 0xff81c784; + const color_t Green400 = 0xff66bb6a; + const color_t Green500 = 0xff4caf50; + const color_t Green600 = 0xff43a047; + const color_t Green700 = 0xff388e3c; + const color_t Green800 = 0xff2e7d32; + const color_t Green900 = 0xff1b5e20; + const color_t GreenA100 = 0xffb9f6ca; + const color_t GreenA200 = 0xff69f0ae; + const color_t GreenA400 = 0xff00e676; + const color_t GreenA700 = 0xff00c853; + + const color_t LightGreen50 = 0xfff1f8e9; + const color_t LightGreen100 = 0xffdcedc8; + const color_t LightGreen200 = 0xffc5e1a5; + const color_t LightGreen300 = 0xffaed581; + const color_t LightGreen400 = 0xff9ccc65; + const color_t LightGreen500 = 0xff8bc34a; + const color_t LightGreen600 = 0xff7cb342; + const color_t LightGreen700 = 0xff689f38; + const color_t LightGreen800 = 0xff558b2f; + const color_t LightGreen900 = 0xff33691e; + const color_t LightGreenA100 = 0xffccff90; + const color_t LightGreenA200 = 0xffb2ff59; + const color_t LightGreenA400 = 0xff76ff03; + const color_t LightGreenA700 = 0xff64dd17; + + const color_t Lime50 = 0xfff9ebe7; + const color_t Lime100 = 0xfff0f4c3; + const color_t Lime200 = 0xffe6ee9c; + const color_t Lime300 = 0xffdce775; + const color_t Lime400 = 0xffd4e157; + const color_t Lime500 = 0xffcddc39; + const color_t Lime600 = 0xffc0ca33; + const color_t Lime700 = 0xffafb42b; + const color_t Lime800 = 0xff9e9d24; + const color_t Lime900 = 0xff827717; + const color_t LimeA100 = 0xfff4ff81; + const color_t LimeA200 = 0xffeeff41; + const color_t LimeA400 = 0xffc6ff00; + const color_t LimeA700 = 0xffaeea00; + + const color_t Yellow50 = 0xfffffde7; + const color_t Yellow100 = 0xfffff9c4; + const color_t Yellow200 = 0xfffff59d; + const color_t Yellow300 = 0xfffff176; + const color_t Yellow400 = 0xffffee58; + const color_t Yellow500 = 0xffffeb3b; + const color_t Yellow600 = 0xfffdd835; + const color_t Yellow700 = 0xfffbc02d; + const color_t Yellow800 = 0xfff9a825; + const color_t Yellow900 = 0xfff57f17; + const color_t YellowA100 = 0xffffff8d; + const color_t YellowA200 = 0xffffff00; + const color_t YellowA400 = 0xffffea00; + const color_t YellowA700 = 0xffffd600; + + const color_t Amber50 = 0xfffff8e1; + const color_t Amber100 = 0xffffecb3; + const color_t Amber200 = 0xffffe082; + const color_t Amber300 = 0xffffd54f; + const color_t Amber400 = 0xffffca28; + const color_t Amber500 = 0xffffc107; + const color_t Amber600 = 0xffffb300; + const color_t Amber700 = 0xffffa000; + const color_t Amber800 = 0xffff8f00; + const color_t Amber900 = 0xffff6f00; + const color_t AmberA100 = 0xffffe57f; + const color_t AmberA200 = 0xffffd740; + const color_t AmberA400 = 0xffffc400; + const color_t AmberA700 = 0xffffab00; + + const color_t Orange50 = 0xfffff3e0; + const color_t Orange100 = 0xffffe0b2; + const color_t Orange200 = 0xffffcc80; + const color_t Orange300 = 0xffffb74d; + const color_t Orange400 = 0xffffa726; + const color_t Orange500 = 0xffff9800; + const color_t Orange600 = 0xfffb8c00; + const color_t Orange700 = 0xfff57c00; + const color_t Orange800 = 0xffef6c00; + const color_t Orange900 = 0xffe65100; + const color_t OrangeA100 = 0xffffd180; + const color_t OrangeA200 = 0xffffab40; + const color_t OrangeA400 = 0xffff9100; + const color_t OrangeA700 = 0xffff6d00; + + const color_t DeepOrange50 = 0xfffbe9e7; + const color_t DeepOrange100 = 0xffffccbc; + const color_t DeepOrange200 = 0xffffab91; + const color_t DeepOrange300 = 0xffff8a65; + const color_t DeepOrange400 = 0xffff7043; + const color_t DeepOrange500 = 0xffff5722; + const color_t DeepOrange600 = 0xfff4511e; + const color_t DeepOrange700 = 0xffe64a19; + const color_t DeepOrange800 = 0xffd84315; + const color_t DeepOrange900 = 0xffbf360c; + const color_t DeepOrangeA100 = 0xffff9e80; + const color_t DeepOrangeA200 = 0xffff6e40; + const color_t DeepOrangeA400 = 0xffff3d00; + const color_t DeepOrangeA700 = 0xffdd2c00; + + const color_t Brown50 = 0xffefebe9; + const color_t Brown100 = 0xffd7ccc8; + const color_t Brown200 = 0xffbcaaa4; + const color_t Brown300 = 0xffa1887f; + const color_t Brown400 = 0xff8d6e63; + const color_t Brown500 = 0xff795548; + const color_t Brown600 = 0xff6d4c41; + const color_t Brown700 = 0xff5d4037; + const color_t Brown800 = 0xff4e342e; + const color_t Brown900 = 0xff3e2723; + + const color_t Grey50 = 0xfffafafa; + const color_t Grey100 = 0xfff5f5f5; + const color_t Grey200 = 0xffeeeeee; + const color_t Grey300 = 0xffe0e0e0; + const color_t Grey400 = 0xffbdbdbd; + const color_t Grey500 = 0xff9e9e9e; + const color_t Grey600 = 0xff757575; + const color_t Grey700 = 0xff616161; + const color_t Grey800 = 0xff424242; + const color_t Grey900 = 0xff212121; + + const color_t BlueGrey50 = 0xffeceff1; + const color_t BlueGrey100 = 0xffcfd8dc; + const color_t BlueGrey200 = 0xffb0bec5; + const color_t BlueGrey300 = 0xff90a4ae; + const color_t BlueGrey400 = 0xff78909c; + const color_t BlueGrey500 = 0xff607d8b; + const color_t BlueGrey600 = 0xff546e7a; + const color_t BlueGrey700 = 0xff455a64; + const color_t BlueGrey800 = 0xff37474f; + const color_t BlueGrey900 = 0xff263238; + + const color_t Black = 0xff000000; + const color_t White = 0xffffffff; + const color_t Null = 0x00000000; + + + const color_t Red = Red500; + const color_t DarkRed = Red900; + const color_t Coral = Red200; + const color_t RichRed = 0xffff0000; + const color_t Pink = Pink500; + const color_t Rose = PinkA100; + const color_t Purple = Purple500; + const color_t Magenta = PurpleA200; + const color_t DarkMagenta = PurpleA700; + const color_t DeepPurple = DeepPurple500; + const color_t Indigo = Indigo500; + const color_t Blue = Blue500; + const color_t DarkBlue = Blue900; + const color_t RichBlue = 0xff0000ff; + const color_t LightBlue = LightBlue500; + const color_t SkyBlue = LightBlueA100; + const color_t Navy = LightBlue800; + const color_t Cyan = Cyan500; + const color_t DarkCyan = Cyan900; + const color_t Teal = Teal500; + const color_t DarkTeal = Teal900; + const color_t Green = Green500; + const color_t DarkGreen = Green900; + const color_t RichGreen = 0xff00ff00; + const color_t LightGreen = LightGreen500; + const color_t Mint = LightGreen900; + const color_t Lime = Lime500; + const color_t Olive = Lime900; + const color_t Yellow = Yellow500; + const color_t RichYellow = YellowA200; + const color_t Amber = Amber500; + const color_t Gold = Amber300; + const color_t PaleGold = AmberA100; + const color_t Orange = Orange500; + const color_t Skin = Orange100; + const color_t DeepOrange = DeepOrange500; + const color_t Brick = DeepOrange900; + const color_t Brown = Brown500; + const color_t DarkBrown = Brown900; + const color_t CreamWhite = Orange50; + const color_t Wheat = Amber100; + const color_t Grey = Grey500; + const color_t Dark = Grey900; + const color_t Silver = Grey300; + const color_t BlueGrey = BlueGrey500; + + const color_t Default = Wheat; +#else + const color_t Default = 0xffffecb3; +#endif // #if !defined(EASY_OPTION_BUILTIN_COLORS) || EASY_OPTION_BUILTIN_COLORS == 0 + + } // END of namespace colors. + +} // END of namespace profiler. + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +#endif // EASY_PROFILER_COLORS_H diff --git a/src/external/easy/reader.h b/src/external/easy/reader.h new file mode 100644 index 0000000..1958017 --- /dev/null +++ b/src/external/easy/reader.h @@ -0,0 +1,416 @@ +/** +Lightweight profiler library for c++ +Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin + +Licensed under either of + * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +at your option. + +The MIT License + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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 OR COPYRIGHT HOLDERS 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. + + +The Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**/ + +#ifndef PROFILER_READER____H +#define PROFILER_READER____H + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace profiler { + + typedef uint32_t calls_number_t; + typedef uint32_t block_index_t; + +#pragma pack(push, 1) + struct BlockStatistics EASY_FINAL + { + ::profiler::timestamp_t total_duration; ///< Total duration of all block calls + ::profiler::timestamp_t total_children_duration; ///< Total duration of all children of all block calls + ::profiler::block_index_t min_duration_block; ///< Will be used in GUI to jump to the block with min duration + ::profiler::block_index_t max_duration_block; ///< Will be used in GUI to jump to the block with max duration + ::profiler::block_index_t parent_block; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats" + ::profiler::calls_number_t calls_number; ///< Block calls number + + explicit BlockStatistics(::profiler::timestamp_t _duration, ::profiler::block_index_t _block_index, ::profiler::block_index_t _parent_index) + : total_duration(_duration) + , total_children_duration(0) + , min_duration_block(_block_index) + , max_duration_block(_block_index) + , parent_block(_parent_index) + , calls_number(1) + { + } + + //BlockStatistics() = default; + + inline ::profiler::timestamp_t average_duration() const + { + return total_duration / calls_number; + } + + }; // END of struct BlockStatistics. +#pragma pack(pop) + + extern "C" PROFILER_API void release_stats(BlockStatistics*& _stats); + + ////////////////////////////////////////////////////////////////////////// + + class BlocksTree EASY_FINAL + { + typedef BlocksTree This; + + public: + + typedef ::std::vector blocks_t; + typedef ::std::vector<::profiler::block_index_t> children_t; + + children_t children; ///< List of children blocks. May be empty. + ::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.) + ::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks) + ::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks) + ::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread + uint8_t depth; ///< Maximum number of sublevels (maximum children depth) + + BlocksTree() + : node(nullptr) + , per_parent_stats(nullptr) + , per_frame_stats(nullptr) + , per_thread_stats(nullptr) + , depth(0) + { + + } + + BlocksTree(This&& that) : BlocksTree() + { + make_move(::std::forward(that)); + } + + This& operator = (This&& that) + { + make_move(::std::forward(that)); + return *this; + } + + ~BlocksTree() + { + release_stats(per_thread_stats); + release_stats(per_parent_stats); + release_stats(per_frame_stats); + } + + bool operator < (const This& other) const + { + if (!node || !other.node) + return false; + return node->begin() < other.node->begin(); + } + + void shrink_to_fit() + { + //for (auto& child : children) + // child.shrink_to_fit(); + + // shrink version 1: + //children.shrink_to_fit(); + + // shrink version 2: + //children_t new_children; + //new_children.reserve(children.size()); + //::std::move(children.begin(), children.end(), ::std::back_inserter(new_children)); + //new_children.swap(children); + } + + private: + + BlocksTree(const This&) = delete; + This& operator = (const This&) = delete; + + void make_move(This&& that) + { + if (per_thread_stats != that.per_thread_stats) + release_stats(per_thread_stats); + + if (per_parent_stats != that.per_parent_stats) + release_stats(per_parent_stats); + + if (per_frame_stats != that.per_frame_stats) + release_stats(per_frame_stats); + + children = ::std::move(that.children); + node = that.node; + per_parent_stats = that.per_parent_stats; + per_frame_stats = that.per_frame_stats; + per_thread_stats = that.per_thread_stats; + depth = that.depth; + + that.node = nullptr; + that.per_parent_stats = nullptr; + that.per_frame_stats = nullptr; + that.per_thread_stats = nullptr; + } + + }; // END of class BlocksTree. + + ////////////////////////////////////////////////////////////////////////// + + class BlocksTreeRoot EASY_FINAL + { + typedef BlocksTreeRoot This; + + public: + + BlocksTree::children_t children; ///< List of children indexes + BlocksTree::children_t sync; ///< List of context-switch events + BlocksTree::children_t events; ///< List of events indexes + std::string thread_name; ///< Name of this thread + ::profiler::timestamp_t profiled_time; ///< Profiled time of this thread (sum of all children duration) + ::profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches) + ::profiler::thread_id_t thread_id; ///< System Id of this thread + ::profiler::block_index_t blocks_number; ///< Total blocks number including their children + uint8_t depth; ///< Maximum stack depth (number of levels) + + BlocksTreeRoot() : profiled_time(0), wait_time(0), thread_id(0), blocks_number(0), depth(0) + { + } + + BlocksTreeRoot(This&& that) + : children(::std::move(that.children)) + , sync(::std::move(that.sync)) + , events(::std::move(that.events)) + , thread_name(::std::move(that.thread_name)) + , profiled_time(that.profiled_time) + , wait_time(that.wait_time) + , thread_id(that.thread_id) + , blocks_number(that.blocks_number) + , depth(that.depth) + { + } + + This& operator = (This&& that) + { + children = ::std::move(that.children); + sync = ::std::move(that.sync); + events = ::std::move(that.events); + thread_name = ::std::move(that.thread_name); + profiled_time = that.profiled_time; + wait_time = that.wait_time; + thread_id = that.thread_id; + blocks_number = that.blocks_number; + depth = that.depth; + return *this; + } + + inline bool got_name() const + { + return !thread_name.empty(); + } + + inline const char* name() const + { + return thread_name.c_str(); + } + + bool operator < (const This& other) const + { + return thread_id < other.thread_id; + } + + private: + + BlocksTreeRoot(const This&) = delete; + This& operator = (const This&) = delete; + + }; // END of class BlocksTreeRoot. + + typedef ::profiler::BlocksTree::blocks_t blocks_t; + typedef ::std::unordered_map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot, ::profiler::passthrough_hash> thread_blocks_tree_t; + + ////////////////////////////////////////////////////////////////////////// + + class PROFILER_API SerializedData EASY_FINAL + { + char* m_data; + size_t m_size; + + public: + + SerializedData() : m_data(nullptr), m_size(0) + { + } + + SerializedData(SerializedData&& that) : m_data(that.m_data), m_size(that.m_size) + { + that.m_data = nullptr; + that.m_size = 0; + } + + ~SerializedData() + { + clear(); + } + + void set(uint64_t _size); + void extend(uint64_t _size); + + SerializedData& operator = (SerializedData&& that) + { + set(that.m_data, that.m_size); + that.m_data = nullptr; + that.m_size = 0; + return *this; + } + + char* operator [] (uint64_t i) + { + return m_data + i; + } + + const char* operator [] (uint64_t i) const + { + return m_data + i; + } + + bool empty() const + { + return m_size == 0; + } + + uint64_t size() const + { + return m_size; + } + + char* data() + { + return m_data; + } + + const char* data() const + { + return m_data; + } + + void clear() + { + set(nullptr, 0); + } + + void swap(SerializedData& other) + { + char* d = other.m_data; + uint64_t sz = other.m_size; + + other.m_data = m_data; + other.m_size = m_size; + + m_data = d; + m_size = sz; + } + + private: + + void set(char* _data, uint64_t _size); + + SerializedData(const SerializedData&) = delete; + SerializedData& operator = (const SerializedData&) = delete; + + }; // END of class SerializedData. + + ////////////////////////////////////////////////////////////////////////// + + typedef ::std::vector descriptors_list_t; + +} // END of namespace profiler. + +extern "C" { + + PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic& progress, const char* filename, + ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, + ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, + bool gather_statistics, + ::std::stringstream& _log); + + PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic& progress, ::std::stringstream& str, + ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, + ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, + bool gather_statistics, + ::std::stringstream& _log); + + PROFILER_API bool readDescriptionsFromStream(::std::atomic& progress, ::std::stringstream& str, + ::profiler::SerializedData& serialized_descriptors, + ::profiler::descriptors_list_t& descriptors, + ::std::stringstream& _log); +} + +inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, + ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, + bool gather_statistics, + ::std::stringstream& _log) +{ + ::std::atomic progress = ATOMIC_VAR_INIT(0); + return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, total_descriptors_number, gather_statistics, _log); +} + +inline bool readDescriptionsFromStream(::std::stringstream& str, + ::profiler::SerializedData& serialized_descriptors, + ::profiler::descriptors_list_t& descriptors, + ::std::stringstream& _log) +{ + ::std::atomic progress = ATOMIC_VAR_INIT(0); + return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // PROFILER_READER____H diff --git a/src/external/easy/serialized_block.h b/src/external/easy/serialized_block.h new file mode 100644 index 0000000..9dce1eb --- /dev/null +++ b/src/external/easy/serialized_block.h @@ -0,0 +1,112 @@ +/** +Lightweight profiler library for c++ +Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin + +Licensed under either of + * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +at your option. + +The MIT License + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + 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 OR COPYRIGHT HOLDERS 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. + + +The Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**/ + +#ifndef EASY_PROFILER_SERIALIZED_BLOCK_H +#define EASY_PROFILER_SERIALIZED_BLOCK_H + +#include + +namespace profiler { + + ////////////////////////////////////////////////////////////////////////// + + class PROFILER_API SerializedBlock EASY_FINAL : public BaseBlockData + { + friend ::ProfileManager; + friend ::ThreadStorage; + + public: + + inline const char* data() const { return reinterpret_cast(this); } + inline const char* name() const { return data() + sizeof(BaseBlockData); } + + private: + + SerializedBlock(const ::profiler::Block& block, uint16_t name_length); + + SerializedBlock(const SerializedBlock&) = delete; + SerializedBlock& operator = (const SerializedBlock&) = delete; + ~SerializedBlock() = delete; + + }; // END of SerializedBlock. + + ////////////////////////////////////////////////////////////////////////// + +#pragma pack(push, 1) + class PROFILER_API SerializedBlockDescriptor EASY_FINAL : public BaseBlockDescriptor + { + uint16_t m_nameLength; + + public: + + inline const char* data() const { + return reinterpret_cast(this); + } + + inline const char* name() const { + static const auto shift = sizeof(BaseBlockDescriptor) + sizeof(decltype(m_nameLength)); + return data() + shift; + } + + inline const char* file() const { + return name() + m_nameLength; + } + + inline void setStatus(EasyBlockStatus _status) + { + m_status = _status; + } + + private: + + SerializedBlockDescriptor(const SerializedBlockDescriptor&) = delete; + SerializedBlockDescriptor& operator = (const SerializedBlockDescriptor&) = delete; + ~SerializedBlockDescriptor() = delete; + + }; // END of SerializedBlockDescriptor. +#pragma pack(pop) + + ////////////////////////////////////////////////////////////////////////// + +} // END of namespace profiler. + +#endif // EASY_PROFILER_SERIALIZED_BLOCK_H