mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 05:06:40 +00:00
Initial commit
This commit is contained in:
+39
@@ -0,0 +1,39 @@
|
||||
file(GLOB easy_profiler_src
|
||||
src/base_block_descriptor.cpp
|
||||
src/block.cpp
|
||||
src/block_descriptor.cpp
|
||||
src/easy_socket.cpp
|
||||
src/event_trace_win.cpp
|
||||
src/nonscoped_block.cpp
|
||||
src/profile_manager.cpp
|
||||
src/profiler.cpp
|
||||
src/reader.cpp
|
||||
src/serialized_block.cpp
|
||||
src/thread_storage.cpp
|
||||
src/writer.cpp
|
||||
)
|
||||
|
||||
|
||||
if (MINGW)
|
||||
if (CLANG)
|
||||
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-unused-variable -Wno-writable-strings -Wno-braced-scalar-init -Wno-defaulted-function-deleted -Wno-unknown-pragmas -Wno-reorder-ctor -femulated-tls")
|
||||
else()
|
||||
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-reorder-ctor -Wno-reorder -Wno-unknown-pragmas -Wno-format -Wno-class-memaccess")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (CLANG)
|
||||
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-reorder-ctor -Wno-defaulted-function-deleted -Wno-braced-scalar-init -Wno-writable-strings -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -Wno-format")
|
||||
else()
|
||||
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DEASY_PROFILER_STATIC")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(easy_profiler_obj OBJECT ${easy_profiler_src})
|
||||
add_library(easy_profiler STATIC $<TARGET_OBJECTS:easy_profiler_obj>)
|
||||
|
||||
target_include_directories(easy_profiler PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
||||
target_include_directories(easy_profiler_obj PRIVATE $<TARGET_PROPERTY:easy_profiler,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
Copyright (c) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_ARBITRARY_VALUE_H
|
||||
#define EASY_PROFILER_ARBITRARY_VALUE_H
|
||||
|
||||
#include <easy/details/arbitrary_value_public_types.h>
|
||||
|
||||
//
|
||||
// USING_EASY_PROFILER is defined in details/profiler_in_use.h
|
||||
// if defined BUILD_WITH_EASY_PROFILER and not defined DISABLE_EASY_PROFILER
|
||||
//
|
||||
|
||||
//
|
||||
// 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 <easy/profiler.h>
|
||||
// to disable profiler for certain source-file or project.
|
||||
//
|
||||
|
||||
#ifdef USING_EASY_PROFILER
|
||||
|
||||
/** Macro used to create a unique Value Identification Number.
|
||||
|
||||
Use this if you want to change the same value from different places in your code.
|
||||
Otherwise do not mind.
|
||||
|
||||
\code
|
||||
struct A {
|
||||
int someCount;
|
||||
};
|
||||
|
||||
void foo(const A& a) {
|
||||
EASY_VALUE("foo count", a.someCount); // Value ID is automatically set to (uint64_t)&a.someCount
|
||||
|
||||
// This notation is completely the same as EASY_VALUE("foo count", a.someCount, EASY_VIN(a.someCount));
|
||||
}
|
||||
|
||||
void bar(const A& b) {
|
||||
EASY_VALUE("bar count", b.someCount); // Same ID as for "foo count" if &b == &a (and different ID otherwise)
|
||||
}
|
||||
|
||||
void baz(const A& c) {
|
||||
EASY_VALUE("baz count", c.someCount, EASY_VIN(EASY_FUNC_NAME)); // Different ID from "foo count" and "bar count"
|
||||
EASY_VALUE("qux count", 100500, EASY_VIN(EASY_FUNC_NAME)); // Same ID as for "baz count"
|
||||
}
|
||||
\endcode
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_VIN(member) ::profiler::ValueId(member)
|
||||
|
||||
/** Macro used to identify global value which would be recognized by it's name in GUI.
|
||||
|
||||
\code
|
||||
struct A {
|
||||
int someCount;
|
||||
};
|
||||
|
||||
struct B {
|
||||
int someOtherCount;
|
||||
};
|
||||
|
||||
void foo(const A& a) {
|
||||
EASY_VALUE("Count", a.someCount, EASY_GLOBAL_VIN);
|
||||
}
|
||||
|
||||
void bar(const B& b) {
|
||||
EASY_VALUE("Count", b.someOtherCount, EASY_GLOBAL_VIN); // Same ID as for foo::"Count" despite of &b != &a
|
||||
}
|
||||
\endcode
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_GLOBAL_VIN ::profiler::ValueId()
|
||||
|
||||
/** Macro used to identify unique value.
|
||||
|
||||
\code
|
||||
struct A {
|
||||
int someCount;
|
||||
};
|
||||
|
||||
void foo(const A& a) {
|
||||
// All these values would have different IDs despite of names, pointers and values are the same
|
||||
EASY_VALUE("foo count", a.someCount, EASY_UNIQUE_VIN);
|
||||
EASY_VALUE("foo count", a.someCount, EASY_UNIQUE_VIN);
|
||||
EASY_VALUE("foo count", a.someCount, EASY_UNIQUE_VIN);
|
||||
}
|
||||
\endcode
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_UNIQUE_VIN ::profiler::ValueId(EASY_UNIQUE_DESC(__LINE__))
|
||||
|
||||
/** Macro used to store single arbitrary value.
|
||||
|
||||
\note Also stores a time-stamp of it's occurrence like an Event.
|
||||
|
||||
\note To store a dynamic array (which size is unknown at compile time), please, use EASY_ARRAY macro.
|
||||
|
||||
\note Currently arbitrary values support only compile-time names.
|
||||
|
||||
\sa EASY_ARRAY, EASY_TEXT, EASY_STRING
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_VALUE(name, value, ...)\
|
||||
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::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
|
||||
::profiler::setValue(EASY_UNIQUE_DESC(__LINE__), value, ::profiler::extract_value_id(value, ## __VA_ARGS__));
|
||||
|
||||
/** Macro used to store an array of arbitrary values.
|
||||
|
||||
\note Also stores a time-stamp of it's occurrence like an Event.
|
||||
|
||||
\note Currently arbitrary values support only compile-time names.
|
||||
|
||||
\warning Max data size (sizeof(value) * size) is MAX_BLOCK_DATA_SIZE. Passing bigger size has undefined behavior.
|
||||
|
||||
\sa EASY_VALUE, EASY_TEXT, EASY_STRING, MAX_BLOCK_DATA_SIZE
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_ARRAY(name, value, size, ...)\
|
||||
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::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
|
||||
::profiler::setValue(EASY_UNIQUE_DESC(__LINE__), value, ::profiler::extract_value_id(value, ## __VA_ARGS__), size);
|
||||
|
||||
/** Macro used to store custom text.
|
||||
|
||||
Could be C-string or std::string.
|
||||
|
||||
\note Also stores a time-stamp of it's occurrence like an Event.
|
||||
|
||||
\note Currently arbitrary values support only compile-time names.
|
||||
|
||||
\warning Max string length is MAX_BLOCK_DATA_SIZE (including trailing '\0'). Passing bigger size has undefined behavior.
|
||||
|
||||
\sa EASY_VALUE, EASY_ARRAY, EASY_STRING, MAX_BLOCK_DATA_SIZE
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_TEXT(name, text, ...)\
|
||||
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::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
|
||||
::profiler::setText(EASY_UNIQUE_DESC(__LINE__), text, ::profiler::extract_value_id(text , ## __VA_ARGS__));
|
||||
|
||||
/** Macro used to store custom text of specified length.
|
||||
|
||||
Same as EASY_TEXT, but with explicitly specified length.
|
||||
Use this for C-strings of known length (compile-time or run-time).
|
||||
|
||||
\note Recommendation (not a requirement): Take into account a zero-terminator '\0' symbol (e.g. strlen("BlaBla") + 1).
|
||||
|
||||
\note Also stores a time-stamp of it's occurrence like an Event.
|
||||
|
||||
\note Currently arbitrary values support only compile-time names.
|
||||
|
||||
\warning Max string length is MAX_BLOCK_DATA_SIZE (including trailing '\0'). Passing bigger size has undefined behavior.
|
||||
|
||||
\sa EASY_VALUE, EASY_ARRAY, EASY_TEXT, MAX_BLOCK_DATA_SIZE
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
# define EASY_STRING(name, text, size, ...)\
|
||||
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::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
|
||||
::profiler::setText(EASY_UNIQUE_DESC(__LINE__), text, ::profiler::extract_value_id(text, ## __VA_ARGS__), size);
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
|
||||
extern "C" PROFILER_API void storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data,
|
||||
uint16_t _size, bool _isArray, ValueId _vin);
|
||||
|
||||
template <class T>
|
||||
inline void setValue(const BaseBlockDescriptor* _desc, T _value, ValueId _vin)
|
||||
{
|
||||
static_assert(!::std::is_pointer<T>::value,
|
||||
"You should not pass pointers into EASY_VALUE. Pass a reference instead.");
|
||||
|
||||
using Type = typename ::std::remove_reference<typename ::std::remove_cv<T>::type>::type;
|
||||
|
||||
static_assert(StdToDataType<Type>::data_type != DataType::TypesCount,
|
||||
"You should use standard builtin scalar types as profiler::Value type!");
|
||||
|
||||
storeValue(_desc, StdToDataType<Type>::data_type, &_value, static_cast<uint16_t>(sizeof(Type)), false, _vin);
|
||||
}
|
||||
|
||||
///< WARNING: Passing _arraySize > (MAX_BLOCK_DATA_SIZE / sizeof(T)) may cause undefined behavior!
|
||||
template <class T>
|
||||
inline void setValue(const BaseBlockDescriptor* _desc, const T* _valueArray, ValueId _vin, uint16_t _arraySize)
|
||||
{
|
||||
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
|
||||
"You should use standard builtin scalar types as profiler::Value type!");
|
||||
|
||||
storeValue(_desc, StdToDataType<T>::data_type, _valueArray, static_cast<uint16_t>(sizeof(T) * _arraySize), true, _vin);
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
inline void setValue(const BaseBlockDescriptor* _desc, const T (&_value)[N], ValueId _vin)
|
||||
{
|
||||
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
|
||||
"You should use standard builtin scalar types as profiler::Value type!");
|
||||
|
||||
static_assert(sizeof(_value) <= MAX_BLOCK_DATA_SIZE, "Maximum arbitrary values data size exceeded.");
|
||||
|
||||
storeValue(_desc, StdToDataType<T>::data_type, _value, static_cast<uint16_t>(sizeof(_value)), true, _vin);
|
||||
}
|
||||
|
||||
///< WARNING: Passing _textLength > MAX_BLOCK_DATA_SIZE may cause undefined behavior!
|
||||
inline void setText(const BaseBlockDescriptor* _desc, const char* _text, ValueId _vin, uint16_t _textLength)
|
||||
{
|
||||
storeValue(_desc, DataType::String, _text, _textLength, true, _vin);
|
||||
}
|
||||
|
||||
///< WARNING: Passing _text with length > MAX_BLOCK_DATA_SIZE may cause undefined behavior!
|
||||
inline void setText(const BaseBlockDescriptor* _desc, const char* _text, ValueId _vin)
|
||||
{
|
||||
storeValue(_desc, DataType::String, _text, static_cast<uint16_t>(strlen(_text) + 1), true, _vin);
|
||||
}
|
||||
|
||||
///< WARNING: Passing _text with length > MAX_BLOCK_DATA_SIZE may cause undefined behavior!
|
||||
inline void setText(const BaseBlockDescriptor* _desc, const ::std::string& _text, ValueId _vin)
|
||||
{
|
||||
storeValue(_desc, DataType::String, _text.c_str(), static_cast<uint16_t>(_text.size() + 1), true, _vin);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
inline void setText(const BaseBlockDescriptor* _desc, const char (&_text)[N], ValueId _vin)
|
||||
{
|
||||
static_assert(N <= MAX_BLOCK_DATA_SIZE, "Maximum arbitrary values data size exceeded.");
|
||||
storeValue(_desc, DataType::String, &_text[0], static_cast<uint16_t>(N), true, _vin);
|
||||
}
|
||||
|
||||
} // end of namespace profiler.
|
||||
|
||||
#else
|
||||
|
||||
# if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||
# endif
|
||||
|
||||
# define EASY_GLOBAL_VIN
|
||||
# define EASY_UNIQUE_VIN
|
||||
# define EASY_VIN(member)
|
||||
# define EASY_VALUE(...)
|
||||
# define EASY_ARRAY(...)
|
||||
# define EASY_TEXT(...)
|
||||
# define EASY_STRING(...)
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
|
||||
inline void storeValue(const BaseBlockDescriptor*, DataType, const void*, uint16_t, bool, ValueId) {}
|
||||
|
||||
template <class T>
|
||||
inline void setValue(const BaseBlockDescriptor*, T, ValueId) {}
|
||||
|
||||
template <class T>
|
||||
inline void setValue(const BaseBlockDescriptor*, const T*, ValueId, uint16_t) {}
|
||||
|
||||
template <class T, size_t N>
|
||||
inline void setValue(const BaseBlockDescriptor*, const T (&)[N], ValueId) {}
|
||||
|
||||
inline void setText(const BaseBlockDescriptor*, const char*, ValueId, uint16_t) {}
|
||||
|
||||
inline void setText(const BaseBlockDescriptor*, const char*, ValueId) {}
|
||||
|
||||
inline void setText(const BaseBlockDescriptor*, const ::std::string&, ValueId) {}
|
||||
|
||||
template <size_t N>
|
||||
inline void setText(const BaseBlockDescriptor*, const char (&)[N], ValueId) {}
|
||||
|
||||
} // end of namespace profiler.
|
||||
|
||||
# if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
|
||||
#endif // USING_EASY_PROFILER
|
||||
|
||||
#endif // EASY_PROFILER_ARBITRARY_VALUE_H
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_ARBITRARY_VALUE_AUX_H
|
||||
#define EASY_PROFILER_ARBITRARY_VALUE_AUX_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include <easy/details/easy_compiler_support.h>
|
||||
|
||||
struct ThreadStorage;
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
|
||||
using vin_t = uint64_t;
|
||||
|
||||
class ValueId EASY_FINAL
|
||||
{
|
||||
friend ::ThreadStorage;
|
||||
const void* m_id;
|
||||
|
||||
public:
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
inline EASY_CONSTEXPR_FCN ValueId(const ValueId& _another) : m_id(_another.m_id) {}
|
||||
inline EASY_CONSTEXPR_FCN ValueId(ValueId&& _another) : m_id(_another.m_id) {}
|
||||
#else
|
||||
inline EASY_CONSTEXPR_FCN ValueId(const ValueId&) = default;
|
||||
inline EASY_CONSTEXPR_FCN ValueId(ValueId&&) = default;
|
||||
#endif
|
||||
|
||||
explicit inline EASY_CONSTEXPR_FCN ValueId() : m_id(nullptr) {}
|
||||
explicit inline EASY_CONSTEXPR_FCN ValueId(const void* _member) : m_id(_member) {}
|
||||
|
||||
template <class T>
|
||||
explicit inline EASY_CONSTEXPR_FCN ValueId(const T& _member) : m_id(&_member) {}
|
||||
|
||||
template <class T, size_t N>
|
||||
explicit inline EASY_CONSTEXPR_FCN ValueId(const T (&_member)[N]) : m_id(_member) {}
|
||||
|
||||
ValueId& operator = (const ValueId&) = delete;
|
||||
ValueId& operator = (ValueId&&) = delete;
|
||||
};
|
||||
|
||||
namespace {
|
||||
template <class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN bool subextract_value_id(TArgs...);
|
||||
|
||||
template <>
|
||||
inline EASY_CONSTEXPR_FCN bool subextract_value_id<>() { return false; }
|
||||
|
||||
template <class T>
|
||||
inline EASY_CONSTEXPR_FCN bool subextract_value_id(T) { return false; }
|
||||
|
||||
inline EASY_CONSTEXPR_FCN ValueId subextract_value_id(ValueId _value) { return _value; }
|
||||
|
||||
template <class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN ValueId subextract_value_id(ValueId _value, TArgs...) { return _value; }
|
||||
|
||||
template <class T, class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN auto subextract_value_id(T, TArgs... _args) -> decltype(subextract_value_id(_args...)) {
|
||||
return subextract_value_id(_args...);
|
||||
}
|
||||
|
||||
struct GetFirst {
|
||||
template <class T, class ... TArgs>
|
||||
static EASY_CONSTEXPR_FCN ValueId get(const T& _first, TArgs...) { return ValueId(_first); }
|
||||
|
||||
template <class T, size_t N, class ... TArgs>
|
||||
static EASY_CONSTEXPR_FCN ValueId get(const T (&_first)[N], TArgs...) { return ValueId(_first); }
|
||||
};
|
||||
|
||||
struct GetRest {
|
||||
template <class T, class ... TArgs>
|
||||
static EASY_CONSTEXPR_FCN ValueId get(const T&, TArgs... _args) { return subextract_value_id(_args...); }
|
||||
};
|
||||
} // end of noname namespace.
|
||||
|
||||
template <class T, class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN ValueId extract_value_id(const T& _first, TArgs... _args) {
|
||||
return ::std::conditional<::std::is_same<ValueId, decltype(subextract_value_id(_args...))>::value, GetRest, GetFirst>
|
||||
::type::get(_first, _args...);
|
||||
}
|
||||
|
||||
template <class T, size_t N, class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN ValueId extract_value_id(const T (&_first)[N], TArgs... _args) {
|
||||
return ::std::conditional<::std::is_same<ValueId, decltype(subextract_value_id(_args...))>::value, GetRest, GetFirst>
|
||||
::type::get(_first, _args...);
|
||||
}
|
||||
|
||||
} // end of namespace profiler.
|
||||
|
||||
#endif // EASY_PROFILER_ARBITRARY_VALUE_AUX_H
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_ARBITRARY_VALUE_PUBLIC_TYPES_H
|
||||
#define EASY_PROFILER_ARBITRARY_VALUE_PUBLIC_TYPES_H
|
||||
|
||||
#include <easy/details/arbitrary_value_aux.h>
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
|
||||
enum class DataType : uint8_t
|
||||
{
|
||||
Bool = 0,
|
||||
Char,
|
||||
Int8,
|
||||
Uint8,
|
||||
Int16,
|
||||
Uint16,
|
||||
Int32,
|
||||
Uint32,
|
||||
Int64,
|
||||
Uint64,
|
||||
Float,
|
||||
Double,
|
||||
String,
|
||||
|
||||
TypesCount
|
||||
}; // end of enum class DataType.
|
||||
|
||||
template <DataType dataType> struct StdType;
|
||||
|
||||
template <class T> struct StdToDataType EASY_FINAL {
|
||||
EASY_STATIC_CONSTEXPR auto data_type = DataType::TypesCount;
|
||||
};
|
||||
|
||||
# define EASY_DATATYPE_CONVERSION(DataTypeName, StdTypeName)\
|
||||
template <> struct StdType<DataTypeName> EASY_FINAL { using value_type = StdTypeName; };\
|
||||
template <> struct StdToDataType<StdTypeName> EASY_FINAL { EASY_STATIC_CONSTEXPR auto data_type = DataTypeName; }
|
||||
|
||||
EASY_DATATYPE_CONVERSION(DataType::Bool , bool );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Char , char );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Int8 , int8_t );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Uint8 , uint8_t );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Int16 , int16_t );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Uint16, uint16_t);
|
||||
EASY_DATATYPE_CONVERSION(DataType::Int32 , int32_t );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Uint32, uint32_t);
|
||||
EASY_DATATYPE_CONVERSION(DataType::Int64 , int64_t );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Uint64, uint64_t);
|
||||
EASY_DATATYPE_CONVERSION(DataType::Float , float );
|
||||
EASY_DATATYPE_CONVERSION(DataType::Double, double );
|
||||
|
||||
# undef EASY_DATATYPE_CONVERSION
|
||||
|
||||
template <> struct StdType<DataType::String> EASY_FINAL { using value_type = char; };
|
||||
template <> struct StdToDataType<const char*> EASY_FINAL { EASY_STATIC_CONSTEXPR auto data_type = DataType::String; };
|
||||
|
||||
} // end of namespace profiler.
|
||||
|
||||
#endif //EASY_PROFILER_ARBITRARY_VALUE_PUBLIC_TYPES_H
|
||||
@@ -0,0 +1,254 @@
|
||||
/************************************************************************
|
||||
* 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-2019 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 <cstddef>
|
||||
|
||||
#if defined(_WIN32) && !defined(EASY_PROFILER_STATIC)
|
||||
// Visual Studio and MinGW
|
||||
# ifdef _BUILD_PROFILER
|
||||
# define PROFILER_API __declspec(dllexport)
|
||||
# else
|
||||
# define PROFILER_API __declspec(dllimport)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# if __cplusplus >= 201703L
|
||||
# define EASY_STD 17
|
||||
# elif __cplusplus >= 201402L
|
||||
# define EASY_STD 14
|
||||
# else
|
||||
# define EASY_STD 11
|
||||
# endif
|
||||
#else
|
||||
# define EASY_STD 11
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Visual Studio
|
||||
|
||||
# if defined(EASY_OPTION_PRETTY_PRINT_FUNCTIONS) && EASY_OPTION_PRETTY_PRINT_FUNCTIONS != 0
|
||||
# define EASY_FUNC_NAME __FUNCSIG__
|
||||
# else
|
||||
# define EASY_FUNC_NAME __FUNCTION__
|
||||
# endif
|
||||
|
||||
# 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
|
||||
|
||||
// No constexpr support before Visual Studio 2015
|
||||
# define EASY_CONSTEXPR const
|
||||
# define EASY_STATIC_CONSTEXPR static const
|
||||
# define EASY_CONSTEXPR_FCN
|
||||
|
||||
// No noexcept support before Visual Studio 2015
|
||||
# define EASY_NOEXCEPT throw()
|
||||
|
||||
// No alignof support before Visual Studio 2015
|
||||
# define EASY_ALIGNOF(x) __alignof(x)
|
||||
# endif
|
||||
|
||||
# if EASY_STD > 11 && _MSC_VER >= 1900
|
||||
# define EASY_LAMBDA_MOVE_CAPTURE
|
||||
# endif
|
||||
|
||||
# define EASY_FORCE_INLINE __forceinline
|
||||
|
||||
#elif defined(__clang__)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Clang Compiler
|
||||
|
||||
# define EASY_COMPILER_VERSION (__clang_major__ * 10 + __clang_minor__)
|
||||
|
||||
# if EASY_COMPILER_VERSION < 33 || (defined(__APPLE_CC__) && __APPLE_CC__ < 8000)
|
||||
// There is no support for C++11 thread_local keyword prior to Clang v3.3 and Apple LLVM clang 8.0. Use __thread instead.
|
||||
# define EASY_THREAD_LOCAL __thread
|
||||
# endif
|
||||
|
||||
# if EASY_COMPILER_VERSION < 31
|
||||
// No constexpr support before Clang v3.1
|
||||
# define EASY_CONSTEXPR const
|
||||
# define EASY_STATIC_CONSTEXPR static const
|
||||
# define EASY_CONSTEXPR_FCN
|
||||
# endif
|
||||
|
||||
# if EASY_COMPILER_VERSION < 29
|
||||
// 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 v2.9
|
||||
# define EASY_FINAL
|
||||
# endif
|
||||
|
||||
# if EASY_STD > 11 && EASY_COMPILER_VERSION >= 34
|
||||
# define EASY_LAMBDA_MOVE_CAPTURE
|
||||
# endif
|
||||
|
||||
# define EASY_FORCE_INLINE inline __attribute__((always_inline))
|
||||
# undef EASY_COMPILER_VERSION
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GNU Compiler
|
||||
|
||||
# define EASY_COMPILER_VERSION (__GNUC__ * 10 + __GNUC_MINOR__)
|
||||
|
||||
# if EASY_COMPILER_VERSION < 48
|
||||
// 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 EASY_COMPILER_VERSION < 46
|
||||
// No constexpr support before GCC v4.6
|
||||
# define EASY_CONSTEXPR const
|
||||
# define EASY_STATIC_CONSTEXPR static const
|
||||
# define EASY_CONSTEXPR_FCN
|
||||
|
||||
// No noexcept support before GCC v4.6
|
||||
# define EASY_NOEXCEPT throw()
|
||||
# endif
|
||||
|
||||
# if EASY_COMPILER_VERSION < 43
|
||||
// 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 EASY_COMPILER_VERSION < 47
|
||||
// There is no support for C++11 final keyword prior to gcc 4.7
|
||||
# define EASY_FINAL
|
||||
# endif
|
||||
|
||||
# if EASY_STD > 11 && EASY_COMPILER_VERSION >= 49
|
||||
# define EASY_LAMBDA_MOVE_CAPTURE
|
||||
# endif
|
||||
|
||||
# define EASY_FORCE_INLINE inline __attribute__((always_inline))
|
||||
# undef EASY_COMPILER_VERSION
|
||||
|
||||
#else
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: Add other compilers support
|
||||
|
||||
static_assert(false, "EasyProfiler is not configured for using your compiler type. Please, contact developers.");
|
||||
#endif
|
||||
// END
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Default values
|
||||
|
||||
#ifndef EASY_FUNC_NAME
|
||||
# if defined(EASY_OPTION_PRETTY_PRINT_FUNCTIONS) && EASY_OPTION_PRETTY_PRINT_FUNCTIONS != 0
|
||||
# define EASY_FUNC_NAME __PRETTY_FUNCTION__
|
||||
# else
|
||||
# define EASY_FUNC_NAME __func__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef EASY_THREAD_LOCAL
|
||||
# define EASY_THREAD_LOCAL thread_local
|
||||
# define EASY_CXX11_TLS_AVAILABLE
|
||||
#endif
|
||||
|
||||
#ifndef EASY_LOCAL_STATIC_PTR
|
||||
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer) static VarType VarName = VarInitializer
|
||||
# define EASY_MAGIC_STATIC_AVAILABLE
|
||||
#endif
|
||||
|
||||
#ifndef EASY_FINAL
|
||||
# define EASY_FINAL final
|
||||
#endif
|
||||
|
||||
#ifndef EASY_FORCE_INLINE
|
||||
# define EASY_FORCE_INLINE inline
|
||||
#endif
|
||||
|
||||
#ifndef EASY_CONSTEXPR
|
||||
# define EASY_CONSTEXPR constexpr
|
||||
# define EASY_STATIC_CONSTEXPR static constexpr
|
||||
# define EASY_CONSTEXPR_FCN constexpr
|
||||
# define EASY_CONSTEXPR_AVAILABLE
|
||||
#endif
|
||||
|
||||
#ifndef EASY_NOEXCEPT
|
||||
# define EASY_NOEXCEPT noexcept
|
||||
# define EASY_NOEXCEPT_AVAILABLE
|
||||
#endif
|
||||
|
||||
#ifndef EASY_ALIGNOF
|
||||
# define EASY_ALIGNOF(x) alignof(x)
|
||||
#endif
|
||||
|
||||
#ifndef PROFILER_API
|
||||
# define PROFILER_API
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER_COMPILER_SUPPORT_H
|
||||
@@ -0,0 +1,218 @@
|
||||
/************************************************************************
|
||||
* 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-2019 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 <stdint.h>
|
||||
|
||||
#include <easy/details/easy_compiler_support.h>
|
||||
#include <easy/details/profiler_colors.h>
|
||||
#include <easy/details/profiler_in_use.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
# 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 USING_EASY_PROFILER
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
template <const bool> struct NameSwitch;
|
||||
|
||||
class ForceConstStr EASY_FINAL
|
||||
{
|
||||
friend NameSwitch<true>;
|
||||
friend NameSwitch<false>;
|
||||
|
||||
const char* c_str;
|
||||
|
||||
public:
|
||||
|
||||
ForceConstStr() = delete;
|
||||
ForceConstStr(const ForceConstStr&) = delete;
|
||||
ForceConstStr(ForceConstStr&&) = delete;
|
||||
ForceConstStr& operator = (const ForceConstStr&) = delete;
|
||||
ForceConstStr& operator = (ForceConstStr&&) = delete;
|
||||
|
||||
explicit EASY_CONSTEXPR_FCN ForceConstStr(const char* _str) : c_str(_str) {}
|
||||
explicit ForceConstStr(const ::std::string& _str) : c_str(_str.c_str()) {}
|
||||
};
|
||||
|
||||
template <const bool IS_REF> 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 EASY_CONSTEXPR_FCN const char* runtime_name(const ForceConstStr&) { return ""; }
|
||||
|
||||
template <class T>
|
||||
static EASY_CONSTEXPR_FCN const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
|
||||
static EASY_CONSTEXPR_FCN const char* compiletime_name(const char*, const char* autoGeneratedName) { return autoGeneratedName; }
|
||||
static EASY_CONSTEXPR_FCN const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
|
||||
};
|
||||
|
||||
template <> struct NameSwitch<true> EASY_FINAL
|
||||
{
|
||||
static EASY_CONSTEXPR_FCN const char* runtime_name(const char*) { return ""; }
|
||||
static EASY_CONSTEXPR_FCN const char* runtime_name(const ForceConstStr&) { return ""; }
|
||||
static const char* runtime_name(const ::std::string& name) { return name.c_str(); }
|
||||
|
||||
template <class T>
|
||||
static EASY_CONSTEXPR_FCN const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
|
||||
static EASY_CONSTEXPR_FCN const char* compiletime_name(const char* name, const char*) { return name; }
|
||||
static EASY_CONSTEXPR_FCN const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
|
||||
};
|
||||
|
||||
//***********************************************
|
||||
|
||||
template <class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN color_t extract_color(TArgs...);
|
||||
|
||||
template <>
|
||||
inline EASY_CONSTEXPR_FCN color_t extract_color<>() {
|
||||
return ::profiler::colors::Default;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline EASY_CONSTEXPR_FCN color_t extract_color(T) {
|
||||
return ::profiler::colors::Default;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline EASY_CONSTEXPR_FCN color_t extract_color<color_t>(color_t _color) {
|
||||
return _color;
|
||||
}
|
||||
|
||||
template <class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN color_t extract_color(color_t _color, TArgs...) {
|
||||
return _color;
|
||||
}
|
||||
|
||||
template <class T, class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN color_t extract_color(T, TArgs... _args) {
|
||||
return extract_color(_args...);
|
||||
}
|
||||
|
||||
//***********************************************
|
||||
|
||||
template <class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(TArgs...);
|
||||
|
||||
template <>
|
||||
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag<>() {
|
||||
return ::profiler::ON;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(T) {
|
||||
return ::profiler::ON;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(EasyBlockStatus _flag) {
|
||||
return _flag;
|
||||
}
|
||||
|
||||
template <class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(EasyBlockStatus _flag, TArgs...) {
|
||||
return _flag;
|
||||
}
|
||||
|
||||
template <class T, class ... TArgs>
|
||||
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(T, TArgs... _args) {
|
||||
return extract_enable_flag(_args...);
|
||||
}
|
||||
|
||||
//***********************************************
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
# define EASY_UNIQUE_LINE_ID __FILE__ ":" EASY_STRINGIFICATION(__LINE__)
|
||||
# define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::compiletime_name(name, EASY_UNIQUE_LINE_ID)
|
||||
# define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::runtime_name(name)
|
||||
# define EASY_CONST_NAME(name) ::profiler::ForceConstStr(name)
|
||||
|
||||
#else
|
||||
|
||||
# define EASY_CONST_NAME(name)
|
||||
|
||||
#endif // USING_EASY_PROFILER
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER_AUX_H
|
||||
@@ -0,0 +1,413 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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 <cstdint>
|
||||
#include <easy/details/easy_compiler_support.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace profiler {
|
||||
|
||||
using color_t = uint32_t; // Standard four-byte ARGB color format
|
||||
|
||||
namespace colors {
|
||||
|
||||
///< Change alpha for color. Only 8 major bytes (0xff000000) used from alpha.
|
||||
inline EASY_CONSTEXPR_FCN color_t modify_alpha32(color_t _color, color_t _alpha) {
|
||||
return (_alpha & 0xff000000) | (_color & 0x00ffffff);
|
||||
}
|
||||
|
||||
///< Change alpha for color.
|
||||
inline EASY_CONSTEXPR_FCN color_t modify_alpha8(color_t _color, uint8_t _alpha) {
|
||||
return (static_cast<color_t>(_alpha) << 24) | (_color & 0x00ffffff);
|
||||
}
|
||||
|
||||
///< Create color from ARGB components.
|
||||
inline EASY_CONSTEXPR_FCN color_t color(uint8_t _red, uint8_t _green, uint8_t _blue, uint8_t _alpha = 0xff) {
|
||||
return (static_cast<color_t>(_alpha) << 24) | (static_cast<color_t>(_red) << 16) | (static_cast<color_t>(_green) << 8) | static_cast<color_t>(_blue);
|
||||
}
|
||||
|
||||
#if !defined(EASY_OPTION_BUILTIN_COLORS) || EASY_OPTION_BUILTIN_COLORS != 0
|
||||
// Google Material Design colors
|
||||
// See https://material.google.com/style/color.html
|
||||
|
||||
EASY_CONSTEXPR color_t Red50 = 0xffffebee;
|
||||
EASY_CONSTEXPR color_t Red100 = 0xffffcdd2;
|
||||
EASY_CONSTEXPR color_t Red200 = 0xffef9a9a;
|
||||
EASY_CONSTEXPR color_t Red300 = 0xffe57373;
|
||||
EASY_CONSTEXPR color_t Red400 = 0xffef5350;
|
||||
EASY_CONSTEXPR color_t Red500 = 0xfff44336;
|
||||
EASY_CONSTEXPR color_t Red600 = 0xffe53935;
|
||||
EASY_CONSTEXPR color_t Red700 = 0xffd32f2f;
|
||||
EASY_CONSTEXPR color_t Red800 = 0xffc62828;
|
||||
EASY_CONSTEXPR color_t Red900 = 0xffb71c1c;
|
||||
EASY_CONSTEXPR color_t RedA100 = 0xffff8a80;
|
||||
EASY_CONSTEXPR color_t RedA200 = 0xffff5252;
|
||||
EASY_CONSTEXPR color_t RedA400 = 0xffff1744;
|
||||
EASY_CONSTEXPR color_t RedA700 = 0xffd50000;
|
||||
|
||||
EASY_CONSTEXPR color_t Pink50 = 0xfffce4ec;
|
||||
EASY_CONSTEXPR color_t Pink100 = 0xfff8bbd0;
|
||||
EASY_CONSTEXPR color_t Pink200 = 0xfff48fb1;
|
||||
EASY_CONSTEXPR color_t Pink300 = 0xfff06292;
|
||||
EASY_CONSTEXPR color_t Pink400 = 0xffec407a;
|
||||
EASY_CONSTEXPR color_t Pink500 = 0xffe91e63;
|
||||
EASY_CONSTEXPR color_t Pink600 = 0xffd81b60;
|
||||
EASY_CONSTEXPR color_t Pink700 = 0xffc2185b;
|
||||
EASY_CONSTEXPR color_t Pink800 = 0xffad1457;
|
||||
EASY_CONSTEXPR color_t Pink900 = 0xff880e4f;
|
||||
EASY_CONSTEXPR color_t PinkA100 = 0xffff80ab;
|
||||
EASY_CONSTEXPR color_t PinkA200 = 0xffff4081;
|
||||
EASY_CONSTEXPR color_t PinkA400 = 0xfff50057;
|
||||
EASY_CONSTEXPR color_t PinkA700 = 0xffc51162;
|
||||
|
||||
EASY_CONSTEXPR color_t Purple50 = 0xfff3e5f5;
|
||||
EASY_CONSTEXPR color_t Purple100 = 0xffe1bee7;
|
||||
EASY_CONSTEXPR color_t Purple200 = 0xffce93d8;
|
||||
EASY_CONSTEXPR color_t Purple300 = 0xffba68c8;
|
||||
EASY_CONSTEXPR color_t Purple400 = 0xffab47bc;
|
||||
EASY_CONSTEXPR color_t Purple500 = 0xff9c27b0;
|
||||
EASY_CONSTEXPR color_t Purple600 = 0xff8e24aa;
|
||||
EASY_CONSTEXPR color_t Purple700 = 0xff7b1fa2;
|
||||
EASY_CONSTEXPR color_t Purple800 = 0xff6a1b9a;
|
||||
EASY_CONSTEXPR color_t Purple900 = 0xff4a148c;
|
||||
EASY_CONSTEXPR color_t PurpleA100 = 0xffea80fc;
|
||||
EASY_CONSTEXPR color_t PurpleA200 = 0xffe040fb;
|
||||
EASY_CONSTEXPR color_t PurpleA400 = 0xffd500f9;
|
||||
EASY_CONSTEXPR color_t PurpleA700 = 0xffaa00ff;
|
||||
|
||||
EASY_CONSTEXPR color_t DeepPurple50 = 0xffede7f6;
|
||||
EASY_CONSTEXPR color_t DeepPurple100 = 0xffd1c4e9;
|
||||
EASY_CONSTEXPR color_t DeepPurple200 = 0xffb39ddb;
|
||||
EASY_CONSTEXPR color_t DeepPurple300 = 0xff9575cd;
|
||||
EASY_CONSTEXPR color_t DeepPurple400 = 0xff7e57c2;
|
||||
EASY_CONSTEXPR color_t DeepPurple500 = 0xff673ab7;
|
||||
EASY_CONSTEXPR color_t DeepPurple600 = 0xff5e35b1;
|
||||
EASY_CONSTEXPR color_t DeepPurple700 = 0xff512da8;
|
||||
EASY_CONSTEXPR color_t DeepPurple800 = 0xff4527a0;
|
||||
EASY_CONSTEXPR color_t DeepPurple900 = 0xff311b92;
|
||||
EASY_CONSTEXPR color_t DeepPurpleA100 = 0xffb388ff;
|
||||
EASY_CONSTEXPR color_t DeepPurpleA200 = 0xff7c4dff;
|
||||
EASY_CONSTEXPR color_t DeepPurpleA400 = 0xff651fff;
|
||||
EASY_CONSTEXPR color_t DeepPurpleA700 = 0xff6200ea;
|
||||
|
||||
EASY_CONSTEXPR color_t Indigo50 = 0xffe8eaf6;
|
||||
EASY_CONSTEXPR color_t Indigo100 = 0xffc5cae9;
|
||||
EASY_CONSTEXPR color_t Indigo200 = 0xff9fa8da;
|
||||
EASY_CONSTEXPR color_t Indigo300 = 0xff7986cb;
|
||||
EASY_CONSTEXPR color_t Indigo400 = 0xff5c6bc0;
|
||||
EASY_CONSTEXPR color_t Indigo500 = 0xff3f51b5;
|
||||
EASY_CONSTEXPR color_t Indigo600 = 0xff3949ab;
|
||||
EASY_CONSTEXPR color_t Indigo700 = 0xff303f9f;
|
||||
EASY_CONSTEXPR color_t Indigo800 = 0xff283593;
|
||||
EASY_CONSTEXPR color_t Indigo900 = 0xff1a237e;
|
||||
EASY_CONSTEXPR color_t IndigoA100 = 0xff8c9eff;
|
||||
EASY_CONSTEXPR color_t IndigoA200 = 0xff536dfe;
|
||||
EASY_CONSTEXPR color_t IndigoA400 = 0xff3d5afe;
|
||||
EASY_CONSTEXPR color_t IndigoA700 = 0xff304ffe;
|
||||
|
||||
EASY_CONSTEXPR color_t Blue50 = 0xffe3f2fd;
|
||||
EASY_CONSTEXPR color_t Blue100 = 0xffbbdefb;
|
||||
EASY_CONSTEXPR color_t Blue200 = 0xff90caf9;
|
||||
EASY_CONSTEXPR color_t Blue300 = 0xff64b5f6;
|
||||
EASY_CONSTEXPR color_t Blue400 = 0xff42a5f5;
|
||||
EASY_CONSTEXPR color_t Blue500 = 0xff2196f3;
|
||||
EASY_CONSTEXPR color_t Blue600 = 0xff1e88e5;
|
||||
EASY_CONSTEXPR color_t Blue700 = 0xff1976d2;
|
||||
EASY_CONSTEXPR color_t Blue800 = 0xff1565c0;
|
||||
EASY_CONSTEXPR color_t Blue900 = 0xff0d47a1;
|
||||
EASY_CONSTEXPR color_t BlueA100 = 0xff82b1ff;
|
||||
EASY_CONSTEXPR color_t BlueA200 = 0xff448aff;
|
||||
EASY_CONSTEXPR color_t BlueA400 = 0xff2979ff;
|
||||
EASY_CONSTEXPR color_t BlueA700 = 0xff2962ff;
|
||||
|
||||
EASY_CONSTEXPR color_t LightBlue50 = 0xffe1f5fe;
|
||||
EASY_CONSTEXPR color_t LightBlue100 = 0xffb3e5fc;
|
||||
EASY_CONSTEXPR color_t LightBlue200 = 0xff81d4fa;
|
||||
EASY_CONSTEXPR color_t LightBlue300 = 0xff4fc3f7;
|
||||
EASY_CONSTEXPR color_t LightBlue400 = 0xff29b6f6;
|
||||
EASY_CONSTEXPR color_t LightBlue500 = 0xff03a9f4;
|
||||
EASY_CONSTEXPR color_t LightBlue600 = 0xff039be5;
|
||||
EASY_CONSTEXPR color_t LightBlue700 = 0xff0288d1;
|
||||
EASY_CONSTEXPR color_t LightBlue800 = 0xff0277bd;
|
||||
EASY_CONSTEXPR color_t LightBlue900 = 0xff01579b;
|
||||
EASY_CONSTEXPR color_t LightBlueA100 = 0xff80d8ff;
|
||||
EASY_CONSTEXPR color_t LightBlueA200 = 0xff40c4ff;
|
||||
EASY_CONSTEXPR color_t LightBlueA400 = 0xff00b0ff;
|
||||
EASY_CONSTEXPR color_t LightBlueA700 = 0xff0091ea;
|
||||
|
||||
EASY_CONSTEXPR color_t Cyan50 = 0xffe0f7fa;
|
||||
EASY_CONSTEXPR color_t Cyan100 = 0xffb2ebf2;
|
||||
EASY_CONSTEXPR color_t Cyan200 = 0xff80deea;
|
||||
EASY_CONSTEXPR color_t Cyan300 = 0xff4dd0e1;
|
||||
EASY_CONSTEXPR color_t Cyan400 = 0xff26c6da;
|
||||
EASY_CONSTEXPR color_t Cyan500 = 0xff00bcd4;
|
||||
EASY_CONSTEXPR color_t Cyan600 = 0xff00acc1;
|
||||
EASY_CONSTEXPR color_t Cyan700 = 0xff0097a7;
|
||||
EASY_CONSTEXPR color_t Cyan800 = 0xff00838f;
|
||||
EASY_CONSTEXPR color_t Cyan900 = 0xff006064;
|
||||
EASY_CONSTEXPR color_t CyanA100 = 0xff84ffff;
|
||||
EASY_CONSTEXPR color_t CyanA200 = 0xff18ffff;
|
||||
EASY_CONSTEXPR color_t CyanA400 = 0xff00e5ff;
|
||||
EASY_CONSTEXPR color_t CyanA700 = 0xff00b8d4;
|
||||
|
||||
EASY_CONSTEXPR color_t Teal50 = 0xffe0f2f1;
|
||||
EASY_CONSTEXPR color_t Teal100 = 0xffb2dfdb;
|
||||
EASY_CONSTEXPR color_t Teal200 = 0xff80cbc4;
|
||||
EASY_CONSTEXPR color_t Teal300 = 0xff4db6ac;
|
||||
EASY_CONSTEXPR color_t Teal400 = 0xff26a69a;
|
||||
EASY_CONSTEXPR color_t Teal500 = 0xff009688;
|
||||
EASY_CONSTEXPR color_t Teal600 = 0xff00897b;
|
||||
EASY_CONSTEXPR color_t Teal700 = 0xff00796b;
|
||||
EASY_CONSTEXPR color_t Teal800 = 0xff00695c;
|
||||
EASY_CONSTEXPR color_t Teal900 = 0xff004d40;
|
||||
EASY_CONSTEXPR color_t TealA100 = 0xffa7ffeb;
|
||||
EASY_CONSTEXPR color_t TealA200 = 0xff64ffda;
|
||||
EASY_CONSTEXPR color_t TealA400 = 0xff1de9b6;
|
||||
EASY_CONSTEXPR color_t TealA700 = 0xff00bfa5;
|
||||
|
||||
EASY_CONSTEXPR color_t Green50 = 0xffe8f5e9;
|
||||
EASY_CONSTEXPR color_t Green100 = 0xffc8e6c9;
|
||||
EASY_CONSTEXPR color_t Green200 = 0xffa5d6a7;
|
||||
EASY_CONSTEXPR color_t Green300 = 0xff81c784;
|
||||
EASY_CONSTEXPR color_t Green400 = 0xff66bb6a;
|
||||
EASY_CONSTEXPR color_t Green500 = 0xff4caf50;
|
||||
EASY_CONSTEXPR color_t Green600 = 0xff43a047;
|
||||
EASY_CONSTEXPR color_t Green700 = 0xff388e3c;
|
||||
EASY_CONSTEXPR color_t Green800 = 0xff2e7d32;
|
||||
EASY_CONSTEXPR color_t Green900 = 0xff1b5e20;
|
||||
EASY_CONSTEXPR color_t GreenA100 = 0xffb9f6ca;
|
||||
EASY_CONSTEXPR color_t GreenA200 = 0xff69f0ae;
|
||||
EASY_CONSTEXPR color_t GreenA400 = 0xff00e676;
|
||||
EASY_CONSTEXPR color_t GreenA700 = 0xff00c853;
|
||||
|
||||
EASY_CONSTEXPR color_t LightGreen50 = 0xfff1f8e9;
|
||||
EASY_CONSTEXPR color_t LightGreen100 = 0xffdcedc8;
|
||||
EASY_CONSTEXPR color_t LightGreen200 = 0xffc5e1a5;
|
||||
EASY_CONSTEXPR color_t LightGreen300 = 0xffaed581;
|
||||
EASY_CONSTEXPR color_t LightGreen400 = 0xff9ccc65;
|
||||
EASY_CONSTEXPR color_t LightGreen500 = 0xff8bc34a;
|
||||
EASY_CONSTEXPR color_t LightGreen600 = 0xff7cb342;
|
||||
EASY_CONSTEXPR color_t LightGreen700 = 0xff689f38;
|
||||
EASY_CONSTEXPR color_t LightGreen800 = 0xff558b2f;
|
||||
EASY_CONSTEXPR color_t LightGreen900 = 0xff33691e;
|
||||
EASY_CONSTEXPR color_t LightGreenA100 = 0xffccff90;
|
||||
EASY_CONSTEXPR color_t LightGreenA200 = 0xffb2ff59;
|
||||
EASY_CONSTEXPR color_t LightGreenA400 = 0xff76ff03;
|
||||
EASY_CONSTEXPR color_t LightGreenA700 = 0xff64dd17;
|
||||
|
||||
EASY_CONSTEXPR color_t Lime50 = 0xfff9ebe7;
|
||||
EASY_CONSTEXPR color_t Lime100 = 0xfff0f4c3;
|
||||
EASY_CONSTEXPR color_t Lime200 = 0xffe6ee9c;
|
||||
EASY_CONSTEXPR color_t Lime300 = 0xffdce775;
|
||||
EASY_CONSTEXPR color_t Lime400 = 0xffd4e157;
|
||||
EASY_CONSTEXPR color_t Lime500 = 0xffcddc39;
|
||||
EASY_CONSTEXPR color_t Lime600 = 0xffc0ca33;
|
||||
EASY_CONSTEXPR color_t Lime700 = 0xffafb42b;
|
||||
EASY_CONSTEXPR color_t Lime800 = 0xff9e9d24;
|
||||
EASY_CONSTEXPR color_t Lime900 = 0xff827717;
|
||||
EASY_CONSTEXPR color_t LimeA100 = 0xfff4ff81;
|
||||
EASY_CONSTEXPR color_t LimeA200 = 0xffeeff41;
|
||||
EASY_CONSTEXPR color_t LimeA400 = 0xffc6ff00;
|
||||
EASY_CONSTEXPR color_t LimeA700 = 0xffaeea00;
|
||||
|
||||
EASY_CONSTEXPR color_t Yellow50 = 0xfffffde7;
|
||||
EASY_CONSTEXPR color_t Yellow100 = 0xfffff9c4;
|
||||
EASY_CONSTEXPR color_t Yellow200 = 0xfffff59d;
|
||||
EASY_CONSTEXPR color_t Yellow300 = 0xfffff176;
|
||||
EASY_CONSTEXPR color_t Yellow400 = 0xffffee58;
|
||||
EASY_CONSTEXPR color_t Yellow500 = 0xffffeb3b;
|
||||
EASY_CONSTEXPR color_t Yellow600 = 0xfffdd835;
|
||||
EASY_CONSTEXPR color_t Yellow700 = 0xfffbc02d;
|
||||
EASY_CONSTEXPR color_t Yellow800 = 0xfff9a825;
|
||||
EASY_CONSTEXPR color_t Yellow900 = 0xfff57f17;
|
||||
EASY_CONSTEXPR color_t YellowA100 = 0xffffff8d;
|
||||
EASY_CONSTEXPR color_t YellowA200 = 0xffffff00;
|
||||
EASY_CONSTEXPR color_t YellowA400 = 0xffffea00;
|
||||
EASY_CONSTEXPR color_t YellowA700 = 0xffffd600;
|
||||
|
||||
EASY_CONSTEXPR color_t Amber50 = 0xfffff8e1;
|
||||
EASY_CONSTEXPR color_t Amber100 = 0xffffecb3;
|
||||
EASY_CONSTEXPR color_t Amber200 = 0xffffe082;
|
||||
EASY_CONSTEXPR color_t Amber300 = 0xffffd54f;
|
||||
EASY_CONSTEXPR color_t Amber400 = 0xffffca28;
|
||||
EASY_CONSTEXPR color_t Amber500 = 0xffffc107;
|
||||
EASY_CONSTEXPR color_t Amber600 = 0xffffb300;
|
||||
EASY_CONSTEXPR color_t Amber700 = 0xffffa000;
|
||||
EASY_CONSTEXPR color_t Amber800 = 0xffff8f00;
|
||||
EASY_CONSTEXPR color_t Amber900 = 0xffff6f00;
|
||||
EASY_CONSTEXPR color_t AmberA100 = 0xffffe57f;
|
||||
EASY_CONSTEXPR color_t AmberA200 = 0xffffd740;
|
||||
EASY_CONSTEXPR color_t AmberA400 = 0xffffc400;
|
||||
EASY_CONSTEXPR color_t AmberA700 = 0xffffab00;
|
||||
|
||||
EASY_CONSTEXPR color_t Orange50 = 0xfffff3e0;
|
||||
EASY_CONSTEXPR color_t Orange100 = 0xffffe0b2;
|
||||
EASY_CONSTEXPR color_t Orange200 = 0xffffcc80;
|
||||
EASY_CONSTEXPR color_t Orange300 = 0xffffb74d;
|
||||
EASY_CONSTEXPR color_t Orange400 = 0xffffa726;
|
||||
EASY_CONSTEXPR color_t Orange500 = 0xffff9800;
|
||||
EASY_CONSTEXPR color_t Orange600 = 0xfffb8c00;
|
||||
EASY_CONSTEXPR color_t Orange700 = 0xfff57c00;
|
||||
EASY_CONSTEXPR color_t Orange800 = 0xffef6c00;
|
||||
EASY_CONSTEXPR color_t Orange900 = 0xffe65100;
|
||||
EASY_CONSTEXPR color_t OrangeA100 = 0xffffd180;
|
||||
EASY_CONSTEXPR color_t OrangeA200 = 0xffffab40;
|
||||
EASY_CONSTEXPR color_t OrangeA400 = 0xffff9100;
|
||||
EASY_CONSTEXPR color_t OrangeA700 = 0xffff6d00;
|
||||
|
||||
EASY_CONSTEXPR color_t DeepOrange50 = 0xfffbe9e7;
|
||||
EASY_CONSTEXPR color_t DeepOrange100 = 0xffffccbc;
|
||||
EASY_CONSTEXPR color_t DeepOrange200 = 0xffffab91;
|
||||
EASY_CONSTEXPR color_t DeepOrange300 = 0xffff8a65;
|
||||
EASY_CONSTEXPR color_t DeepOrange400 = 0xffff7043;
|
||||
EASY_CONSTEXPR color_t DeepOrange500 = 0xffff5722;
|
||||
EASY_CONSTEXPR color_t DeepOrange600 = 0xfff4511e;
|
||||
EASY_CONSTEXPR color_t DeepOrange700 = 0xffe64a19;
|
||||
EASY_CONSTEXPR color_t DeepOrange800 = 0xffd84315;
|
||||
EASY_CONSTEXPR color_t DeepOrange900 = 0xffbf360c;
|
||||
EASY_CONSTEXPR color_t DeepOrangeA100 = 0xffff9e80;
|
||||
EASY_CONSTEXPR color_t DeepOrangeA200 = 0xffff6e40;
|
||||
EASY_CONSTEXPR color_t DeepOrangeA400 = 0xffff3d00;
|
||||
EASY_CONSTEXPR color_t DeepOrangeA700 = 0xffdd2c00;
|
||||
|
||||
EASY_CONSTEXPR color_t Brown50 = 0xffefebe9;
|
||||
EASY_CONSTEXPR color_t Brown100 = 0xffd7ccc8;
|
||||
EASY_CONSTEXPR color_t Brown200 = 0xffbcaaa4;
|
||||
EASY_CONSTEXPR color_t Brown300 = 0xffa1887f;
|
||||
EASY_CONSTEXPR color_t Brown400 = 0xff8d6e63;
|
||||
EASY_CONSTEXPR color_t Brown500 = 0xff795548;
|
||||
EASY_CONSTEXPR color_t Brown600 = 0xff6d4c41;
|
||||
EASY_CONSTEXPR color_t Brown700 = 0xff5d4037;
|
||||
EASY_CONSTEXPR color_t Brown800 = 0xff4e342e;
|
||||
EASY_CONSTEXPR color_t Brown900 = 0xff3e2723;
|
||||
|
||||
EASY_CONSTEXPR color_t Grey50 = 0xfffafafa;
|
||||
EASY_CONSTEXPR color_t Grey100 = 0xfff5f5f5;
|
||||
EASY_CONSTEXPR color_t Grey200 = 0xffeeeeee;
|
||||
EASY_CONSTEXPR color_t Grey300 = 0xffe0e0e0;
|
||||
EASY_CONSTEXPR color_t Grey400 = 0xffbdbdbd;
|
||||
EASY_CONSTEXPR color_t Grey500 = 0xff9e9e9e;
|
||||
EASY_CONSTEXPR color_t Grey600 = 0xff757575;
|
||||
EASY_CONSTEXPR color_t Grey700 = 0xff616161;
|
||||
EASY_CONSTEXPR color_t Grey800 = 0xff424242;
|
||||
EASY_CONSTEXPR color_t Grey900 = 0xff212121;
|
||||
|
||||
EASY_CONSTEXPR color_t BlueGrey50 = 0xffeceff1;
|
||||
EASY_CONSTEXPR color_t BlueGrey100 = 0xffcfd8dc;
|
||||
EASY_CONSTEXPR color_t BlueGrey200 = 0xffb0bec5;
|
||||
EASY_CONSTEXPR color_t BlueGrey300 = 0xff90a4ae;
|
||||
EASY_CONSTEXPR color_t BlueGrey400 = 0xff78909c;
|
||||
EASY_CONSTEXPR color_t BlueGrey500 = 0xff607d8b;
|
||||
EASY_CONSTEXPR color_t BlueGrey600 = 0xff546e7a;
|
||||
EASY_CONSTEXPR color_t BlueGrey700 = 0xff455a64;
|
||||
EASY_CONSTEXPR color_t BlueGrey800 = 0xff37474f;
|
||||
EASY_CONSTEXPR color_t BlueGrey900 = 0xff263238;
|
||||
|
||||
EASY_CONSTEXPR color_t Black = 0xff000000;
|
||||
EASY_CONSTEXPR color_t White = 0xffffffff;
|
||||
EASY_CONSTEXPR color_t Null = 0x00000000;
|
||||
|
||||
|
||||
EASY_CONSTEXPR color_t Red = Red500;
|
||||
EASY_CONSTEXPR color_t DarkRed = Red900;
|
||||
EASY_CONSTEXPR color_t Coral = Red200;
|
||||
EASY_CONSTEXPR color_t RichRed = 0xffff0000;
|
||||
EASY_CONSTEXPR color_t Pink = Pink500;
|
||||
EASY_CONSTEXPR color_t Rose = PinkA100;
|
||||
EASY_CONSTEXPR color_t Purple = Purple500;
|
||||
EASY_CONSTEXPR color_t Magenta = PurpleA200;
|
||||
EASY_CONSTEXPR color_t DarkMagenta = PurpleA700;
|
||||
EASY_CONSTEXPR color_t DeepPurple = DeepPurple500;
|
||||
EASY_CONSTEXPR color_t Indigo = Indigo500;
|
||||
EASY_CONSTEXPR color_t Blue = Blue500;
|
||||
EASY_CONSTEXPR color_t DarkBlue = Blue900;
|
||||
EASY_CONSTEXPR color_t RichBlue = 0xff0000ff;
|
||||
EASY_CONSTEXPR color_t LightBlue = LightBlue500;
|
||||
EASY_CONSTEXPR color_t SkyBlue = LightBlueA100;
|
||||
EASY_CONSTEXPR color_t Navy = LightBlue800;
|
||||
EASY_CONSTEXPR color_t Cyan = Cyan500;
|
||||
EASY_CONSTEXPR color_t DarkCyan = Cyan900;
|
||||
EASY_CONSTEXPR color_t Teal = Teal500;
|
||||
EASY_CONSTEXPR color_t DarkTeal = Teal900;
|
||||
EASY_CONSTEXPR color_t Green = Green500;
|
||||
EASY_CONSTEXPR color_t DarkGreen = Green900;
|
||||
EASY_CONSTEXPR color_t RichGreen = 0xff00ff00;
|
||||
EASY_CONSTEXPR color_t LightGreen = LightGreen500;
|
||||
EASY_CONSTEXPR color_t Mint = LightGreen900;
|
||||
EASY_CONSTEXPR color_t Lime = Lime500;
|
||||
EASY_CONSTEXPR color_t Olive = Lime900;
|
||||
EASY_CONSTEXPR color_t Yellow = Yellow500;
|
||||
EASY_CONSTEXPR color_t RichYellow = YellowA200;
|
||||
EASY_CONSTEXPR color_t Amber = Amber500;
|
||||
EASY_CONSTEXPR color_t Gold = Amber300;
|
||||
EASY_CONSTEXPR color_t PaleGold = AmberA100;
|
||||
EASY_CONSTEXPR color_t Orange = Orange500;
|
||||
EASY_CONSTEXPR color_t Skin = Orange100;
|
||||
EASY_CONSTEXPR color_t DeepOrange = DeepOrange500;
|
||||
EASY_CONSTEXPR color_t Brick = DeepOrange900;
|
||||
EASY_CONSTEXPR color_t Brown = Brown500;
|
||||
EASY_CONSTEXPR color_t DarkBrown = Brown900;
|
||||
EASY_CONSTEXPR color_t CreamWhite = Orange50;
|
||||
EASY_CONSTEXPR color_t Wheat = Amber100;
|
||||
EASY_CONSTEXPR color_t Grey = Grey500;
|
||||
EASY_CONSTEXPR color_t Dark = Grey900;
|
||||
EASY_CONSTEXPR color_t Silver = Grey300;
|
||||
EASY_CONSTEXPR color_t BlueGrey = BlueGrey500;
|
||||
|
||||
EASY_CONSTEXPR color_t Default = Wheat;
|
||||
#else
|
||||
EASY_CONSTEXPR 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
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_IN_USE_H
|
||||
#define EASY_PROFILER_IN_USE_H
|
||||
|
||||
//
|
||||
// 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 <easy/profiler.h>
|
||||
// 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
|
||||
|
||||
#endif
|
||||
|
||||
#endif // EASY_PROFILER_IN_USE_H
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_PUBLIC_TYPES_H
|
||||
#define EASY_PROFILER_PUBLIC_TYPES_H
|
||||
|
||||
#include <easy/details/profiler_aux.h>
|
||||
|
||||
class NonscopedBlock;
|
||||
class ProfileManager;
|
||||
struct ThreadStorage;
|
||||
|
||||
namespace profiler {
|
||||
|
||||
using timestamp_t = uint64_t;
|
||||
using thread_id_t = uint64_t;
|
||||
using block_id_t = uint32_t;
|
||||
|
||||
enum class BlockType : uint8_t
|
||||
{
|
||||
Event = 0,
|
||||
Block,
|
||||
Value,
|
||||
|
||||
TypesCount
|
||||
};
|
||||
using block_type_t = BlockType;
|
||||
|
||||
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)
|
||||
int32_t 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
|
||||
|
||||
explicit BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color) EASY_NOEXCEPT;
|
||||
|
||||
public:
|
||||
|
||||
BaseBlockDescriptor() = delete;
|
||||
|
||||
inline block_id_t id() const EASY_NOEXCEPT { return m_id; }
|
||||
inline int32_t line() const EASY_NOEXCEPT { return m_line; }
|
||||
inline color_t color() const EASY_NOEXCEPT { return m_color; }
|
||||
inline block_type_t type() const EASY_NOEXCEPT { return m_type; }
|
||||
inline EasyBlockStatus status() const EASY_NOEXCEPT { return m_status; }
|
||||
|
||||
}; // END of class BaseBlockDescriptor.
|
||||
|
||||
//***********************************************
|
||||
|
||||
class PROFILER_API Event
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
|
||||
protected:
|
||||
|
||||
timestamp_t m_begin;
|
||||
timestamp_t m_end;
|
||||
|
||||
public:
|
||||
|
||||
Event() = delete;
|
||||
|
||||
Event(const Event&) = default;
|
||||
explicit Event(timestamp_t _begin_time) EASY_NOEXCEPT;
|
||||
explicit Event(timestamp_t _begin_time, timestamp_t _end_time) EASY_NOEXCEPT;
|
||||
|
||||
inline timestamp_t begin() const EASY_NOEXCEPT { return m_begin; }
|
||||
inline timestamp_t end() const EASY_NOEXCEPT { return m_end; }
|
||||
inline timestamp_t duration() const EASY_NOEXCEPT { return m_end - m_begin; }
|
||||
|
||||
}; // END class Event.
|
||||
|
||||
class PROFILER_API BaseBlockData : public Event
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
|
||||
protected:
|
||||
|
||||
block_id_t m_id;
|
||||
|
||||
public:
|
||||
|
||||
BaseBlockData() = delete;
|
||||
|
||||
BaseBlockData(const BaseBlockData&) = default;
|
||||
explicit BaseBlockData(timestamp_t _begin_time, block_id_t _id) EASY_NOEXCEPT;
|
||||
explicit BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id) EASY_NOEXCEPT;
|
||||
|
||||
inline block_id_t id() const EASY_NOEXCEPT { return m_id; }
|
||||
inline void setId(block_id_t _id) EASY_NOEXCEPT { m_id = _id; }
|
||||
|
||||
}; // 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) EASY_NOEXCEPT;
|
||||
void finish();
|
||||
void finish(timestamp_t _time) EASY_NOEXCEPT;
|
||||
inline bool finished() const EASY_NOEXCEPT { return m_end >= m_begin; }
|
||||
inline EasyBlockStatus status() const EASY_NOEXCEPT { return m_status; }
|
||||
inline void setStatus(EasyBlockStatus _status) EASY_NOEXCEPT { m_status = _status; }
|
||||
|
||||
public:
|
||||
|
||||
Block(const Block&) = delete;
|
||||
Block& operator = (const Block&) = delete;
|
||||
|
||||
Block(Block&& that) EASY_NOEXCEPT;
|
||||
Block(const BaseBlockDescriptor* _desc, const char* _runtimeName, bool _scoped = true) EASY_NOEXCEPT;
|
||||
Block(timestamp_t _begin_time, block_id_t _id, const char* _runtimeName) EASY_NOEXCEPT;
|
||||
Block(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id, const char* _runtimeName) EASY_NOEXCEPT;
|
||||
~Block();
|
||||
|
||||
inline const char* name() const EASY_NOEXCEPT { return m_name; }
|
||||
|
||||
}; // END of class Block.
|
||||
|
||||
//***********************************************
|
||||
|
||||
class PROFILER_API ThreadGuard EASY_FINAL
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
thread_id_t m_id = 0;
|
||||
|
||||
public:
|
||||
|
||||
~ThreadGuard();
|
||||
|
||||
}; // END of class ThreadGuard.
|
||||
|
||||
EASY_CONSTEXPR uint16_t MAX_BLOCK_DATA_SIZE = 2048 + 512 + 256; ///< Estimated maximum size of block dynamic name or EASY_VALUE data size
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
#endif // EASY_PROFILER_PUBLIC_TYPES_H
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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 <easy/details/easy_compiler_support.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace profiler { namespace net {
|
||||
|
||||
EASY_CONSTEXPR uint32_t EASY_MESSAGE_SIGN = 20160909;
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
enum class MessageType : uint8_t
|
||||
{
|
||||
Undefined = 0,
|
||||
|
||||
Request_Start_Capture,
|
||||
Reply_Capturing_Started,
|
||||
Request_Stop_Capture,
|
||||
|
||||
Reply_Blocks,
|
||||
Reply_Blocks_End,
|
||||
|
||||
Connection_Accepted,
|
||||
|
||||
Request_Blocks_Description,
|
||||
Reply_Blocks_Description,
|
||||
Reply_Blocks_Description_End,
|
||||
|
||||
Change_Block_Status,
|
||||
Change_Event_Tracing_Status,
|
||||
Change_Event_Tracing_Priority,
|
||||
|
||||
Ping,
|
||||
|
||||
Request_MainThread_FPS,
|
||||
Reply_MainThread_FPS,
|
||||
};
|
||||
|
||||
struct Message
|
||||
{
|
||||
uint32_t magic_number = EASY_MESSAGE_SIGN;
|
||||
MessageType type = MessageType::Undefined;
|
||||
|
||||
bool isEasyNetMessage() const EASY_NOEXCEPT {
|
||||
return EASY_MESSAGE_SIGN == magic_number;
|
||||
}
|
||||
|
||||
explicit Message(MessageType _t) EASY_NOEXCEPT : type(_t) { }
|
||||
|
||||
Message() = default;
|
||||
};
|
||||
|
||||
struct DataMessage : public Message
|
||||
{
|
||||
uint32_t size = 0; // bytes
|
||||
|
||||
explicit DataMessage(MessageType _t = MessageType::Reply_Blocks) : Message(_t) {}
|
||||
explicit DataMessage(uint32_t _s, MessageType _t = MessageType::Reply_Blocks) : Message(_t), size(_s) {}
|
||||
|
||||
const char* data() const { return reinterpret_cast<const char*>(this) + sizeof(DataMessage); }
|
||||
};
|
||||
|
||||
struct BlockStatusMessage : public Message
|
||||
{
|
||||
uint32_t id;
|
||||
uint8_t status;
|
||||
|
||||
explicit BlockStatusMessage(uint32_t _id, uint8_t _status)
|
||||
: Message(MessageType::Change_Block_Status), id(_id), status(_status) { }
|
||||
|
||||
BlockStatusMessage() = delete;
|
||||
};
|
||||
|
||||
struct EasyProfilerStatus : public Message
|
||||
{
|
||||
bool isProfilerEnabled;
|
||||
bool isEventTracingEnabled;
|
||||
bool isLowPriorityEventTracing;
|
||||
|
||||
explicit EasyProfilerStatus(bool _enabled, bool _ETenabled, bool _ETlowp)
|
||||
: Message(MessageType::Connection_Accepted)
|
||||
, isProfilerEnabled(_enabled)
|
||||
, isEventTracingEnabled(_ETenabled)
|
||||
, isLowPriorityEventTracing(_ETlowp)
|
||||
{
|
||||
}
|
||||
|
||||
EasyProfilerStatus() = delete;
|
||||
};
|
||||
|
||||
struct BoolMessage : public Message
|
||||
{
|
||||
bool flag = false;
|
||||
|
||||
explicit BoolMessage(MessageType _t, bool _flag = false)
|
||||
: Message(_t), flag(_flag) { }
|
||||
|
||||
BoolMessage() = default;
|
||||
};
|
||||
|
||||
struct TimestampMessage : public Message
|
||||
{
|
||||
uint32_t maxValue = 0;
|
||||
uint32_t avgValue = 0;
|
||||
|
||||
explicit 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
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef EASY_PROPROTOCOL_H
|
||||
#define EASY_PROPROTOCOL_H
|
||||
///C++
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
///this
|
||||
#include <easy/serialized_block.h>
|
||||
//#include <easy/profiler.h>
|
||||
|
||||
///for actual version vistit https://github.com/yse/easy_profiler/wiki/.prof-file-format-v1.3.0
|
||||
|
||||
namespace profiler {
|
||||
|
||||
namespace reader {
|
||||
|
||||
struct BlockDescriptor;
|
||||
|
||||
struct BlocksInfo //12
|
||||
{
|
||||
uint32_t totalBlocksCount; //4 bytes
|
||||
uint64_t totalBlocksMemory; //8 bytes
|
||||
};
|
||||
|
||||
struct DescriptorsInfo //12
|
||||
{
|
||||
uint32_t allDescriptorsCount; //4 bytes
|
||||
uint64_t allDescriptorsMemory; //8 bytes
|
||||
};
|
||||
|
||||
struct FileHeader //64
|
||||
{
|
||||
uint32_t signature; //4
|
||||
uint32_t version; //4
|
||||
uint64_t processId; //8
|
||||
int64_t cpuFrequency; //8
|
||||
uint64_t beginTime; //8
|
||||
uint64_t endTime; //8
|
||||
BlocksInfo serializedBlocksInfo; //12
|
||||
DescriptorsInfo blocksDescriptorInfo; //12
|
||||
};
|
||||
|
||||
struct BlockInfo
|
||||
{
|
||||
uint64_t beginTime;
|
||||
uint64_t endTime;
|
||||
const BlockDescriptor* descriptor;
|
||||
uint32_t blockIndex;
|
||||
};
|
||||
|
||||
struct ContextSwitchEvent
|
||||
{
|
||||
uint64_t beginTime;
|
||||
uint64_t endTime;
|
||||
uint64_t targetThreadId;
|
||||
std::string targetProcess; ///< Contains process id and process name
|
||||
};
|
||||
|
||||
struct BlockDescriptor
|
||||
{
|
||||
uint32_t parentId; ///< This will differ from id if this descriptor was created from runtime named block
|
||||
uint32_t id;
|
||||
int lineNumber;
|
||||
uint32_t argbColor;
|
||||
uint8_t blockType;
|
||||
uint8_t status;
|
||||
std::string blockName;
|
||||
std::string fileName;
|
||||
};
|
||||
|
||||
} //namespace reader
|
||||
|
||||
} //namespace profiler
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_SOCKET_H
|
||||
#define EASY_PROFILER_SOCKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <easy/details/easy_compiler_support.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// Unix
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netdb.h>
|
||||
# include <stdio.h>
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
# include <netinet/in.h> //for android-build
|
||||
|
||||
#else
|
||||
|
||||
// Windows
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include <ws2tcpip.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
#endif
|
||||
|
||||
class PROFILER_API EasySocket EASY_FINAL
|
||||
{
|
||||
public:
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef SOCKET socket_t;
|
||||
#else
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
enum class ConnectionState : int8_t
|
||||
{
|
||||
Disconnected = -1,
|
||||
Unknown,
|
||||
Connected,
|
||||
Connecting
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
socket_t m_socket = 0;
|
||||
socket_t m_replySocket = 0;
|
||||
int m_wsaret = -1;
|
||||
|
||||
struct hostent* m_server = nullptr;
|
||||
struct sockaddr_in m_serverAddress;
|
||||
|
||||
ConnectionState m_state = ConnectionState::Unknown;
|
||||
|
||||
public:
|
||||
|
||||
EasySocket();
|
||||
~EasySocket();
|
||||
|
||||
void setReceiveTimeout(int milliseconds);
|
||||
|
||||
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();
|
||||
|
||||
ConnectionState state() const;
|
||||
bool isDisconnected() const;
|
||||
bool isConnected() const;
|
||||
|
||||
private:
|
||||
|
||||
void checkResult(int result);
|
||||
bool checkSocket(socket_t s) const;
|
||||
void setBlocking(socket_t s, bool blocking);
|
||||
|
||||
}; // end of class EasySocket.
|
||||
|
||||
#endif // EASY_PROFILER_SOCKET_H
|
||||
@@ -0,0 +1,911 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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 <easy/details/profiler_public_types.h>
|
||||
|
||||
#define MAX_DYNAMIC_BLOCK_NAME_SIZE_ESTIMATED MAX_BLOCK_DATA_SIZE
|
||||
|
||||
#if defined ( __clang__ )
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||
#endif
|
||||
|
||||
//
|
||||
// USING_EASY_PROFILER is defined in details/profiler_in_use.h
|
||||
// if defined BUILD_WITH_EASY_PROFILER and not defined DISABLE_EASY_PROFILER
|
||||
//
|
||||
|
||||
//
|
||||
// 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 <easy/profiler.h>
|
||||
// to disable profiler for certain source-file or project.
|
||||
//
|
||||
|
||||
#ifdef USING_EASY_PROFILER
|
||||
|
||||
// EasyProfiler core API:
|
||||
|
||||
/** Macro for beginning of a scoped block with custom name and color.
|
||||
|
||||
\code
|
||||
#include <easy/profiler.h>
|
||||
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::BlockType::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 <easy/profiler.h>
|
||||
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::BlockType::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 <easy/profiler.h>
|
||||
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_BLOCK(EASY_FUNC_NAME, ## __VA_ARGS__)
|
||||
|
||||
/** Macro for completion of last opened block explicitly.
|
||||
|
||||
\code
|
||||
#include <easy/profiler.h>
|
||||
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 immediately 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::BlockType::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__) = nullptr;\
|
||||
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)\
|
||||
static EASY_THREAD_LOCAL const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\
|
||||
::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 immediately 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
|
||||
|
||||
/** Alias for EASY_PROFILER_ENABLE.
|
||||
|
||||
Added for clarification.
|
||||
|
||||
\sa EASY_PROFILER_ENABLE
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define EASY_START_CAPTURE EASY_PROFILER_ENABLE
|
||||
|
||||
/** Alias for EASY_PROFILER_DISABLE.
|
||||
|
||||
Added for clarification.
|
||||
|
||||
\sa EASY_PROFILER_DISABLE
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define EASY_STOP_CAPTURE EASY_PROFILER_DISABLE
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace profiler {
|
||||
|
||||
EASY_CONSTEXPR uint16_t DEFAULT_PORT = EASY_DEFAULT_PORT;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Core API
|
||||
// Note: It is better to use macros defined above than a direct calls to API.
|
||||
// But some API functions does not have macro wrappers...
|
||||
|
||||
#ifdef USING_EASY_PROFILER
|
||||
extern "C" {
|
||||
|
||||
/** Returns current time in ticks.
|
||||
|
||||
You can use it if you want to store block explicitly.
|
||||
|
||||
\retval Current CPU time in ticks.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API timestamp_t now();
|
||||
|
||||
/** Convert ticks to nanoseconds.
|
||||
|
||||
\retval _ticks converted to nanoseconds.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API timestamp_t toNanoseconds(timestamp_t _ticks);
|
||||
|
||||
/** Convert ticks to microseconds.
|
||||
|
||||
\retval _ticks converted 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.
|
||||
|
||||
\retval Pointer to registered block description.
|
||||
|
||||
\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.
|
||||
|
||||
AKA start or stop profiling (capturing blocks).
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API void setEnabled(bool _isEnable);
|
||||
PROFILER_API bool isEnabled();
|
||||
|
||||
/** Save all gathered blocks into file.
|
||||
|
||||
\note This also disables profiler.
|
||||
|
||||
\retval Number of saved blocks. If 0 then nothing was profiled or an error occurred.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API uint32_t dumpBlocksToFile(const char* _filename);
|
||||
|
||||
/** Register current thread and give it a name.
|
||||
|
||||
Also creates a scoped ThreadGuard which would unregister thread on it's destructor.
|
||||
This helps for memory management while using an old compiler whitout thread_local support.
|
||||
|
||||
\note Only first call of registerThread() for the current thread will have an effect.
|
||||
|
||||
\note Use this function if you want to build your source code with an old compiler (MSVC < 2013, GCC < 4.8, Clang < 3.3).
|
||||
Otherwise there is no need in this function because a thread_local ThreadGuard created inside.
|
||||
|
||||
\retval Registered name of the thread. It may differ from _name if the thread was registered before.
|
||||
|
||||
\sa registerThread, ThreadGuard
|
||||
|
||||
\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.
|
||||
|
||||
\retval Registered name of the thread. It may differ from _name if the thread was registered before.
|
||||
|
||||
\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();
|
||||
|
||||
/** Start listening for network commands.
|
||||
|
||||
Launches a separate listening thread which would listen to the network commands (start, stop, etc.).
|
||||
The listening thread sends all profiled blocks via network after receiving network command 'stop'.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API void startListen(uint16_t _port = ::profiler::DEFAULT_PORT);
|
||||
|
||||
/** Stops listening thread.
|
||||
|
||||
\note This would be invoked automatically on application exit.
|
||||
|
||||
\note Does not send any messages to the network, just stops thread.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API void stopListen();
|
||||
|
||||
/** Check if listening thread launched.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
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.
|
||||
|
||||
\note Format is: 0x MAJ-MAJ MIN-MIN PATCH-PATCH-PATCH-PATCH
|
||||
For example v1.3.0 is: 0x01030000
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API uint32_t version();
|
||||
|
||||
/** Returns current version string.
|
||||
|
||||
Example: "v1.3.0"
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API const char* versionName();
|
||||
|
||||
/** Returns true if current thread has been marked as Main.
|
||||
Otherwise, returns false.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API bool isMainThread();
|
||||
|
||||
/** Returns last frame duration for current thread.
|
||||
|
||||
\param _durationCast desired duration units (could be cpu-ticks or microseconds)
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
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)
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
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)
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
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)
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
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)
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
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)
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
PROFILER_API timestamp_t main_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS);
|
||||
|
||||
}
|
||||
#else
|
||||
inline EASY_CONSTEXPR_FCN timestamp_t now() { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN timestamp_t toNanoseconds(timestamp_t) { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN 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<const BaseBlockDescriptor*>(0xbad); }
|
||||
inline void endBlock() { }
|
||||
inline void setEnabled(bool) { }
|
||||
inline EASY_CONSTEXPR_FCN 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 EASY_CONSTEXPR_FCN bool isEventTracingEnabled() { return false; }
|
||||
inline void setLowPriorityEventTracing(bool) { }
|
||||
inline EASY_CONSTEXPR_FCN bool isLowPriorityEventTracing() { return false; }
|
||||
inline void setContextSwitchLogFilename(const char*) { }
|
||||
inline EASY_CONSTEXPR_FCN const char* getContextSwitchLogFilename() { return ""; }
|
||||
inline void startListen(uint16_t = ::profiler::DEFAULT_PORT) { }
|
||||
inline void stopListen() { }
|
||||
inline EASY_CONSTEXPR_FCN bool isListening() { return false; }
|
||||
inline EASY_CONSTEXPR_FCN uint8_t versionMajor() { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN uint8_t versionMinor() { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN uint16_t versionPatch() { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN uint32_t version() { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN const char* versionName() { return "v0.0.0_disabled"; }
|
||||
inline EASY_CONSTEXPR_FCN bool isMainThread() { return false; }
|
||||
inline EASY_CONSTEXPR_FCN timestamp_t this_thread_frameTime(Duration = ::profiler::MICROSECONDS) { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN timestamp_t this_thread_frameTimeLocalMax(Duration = ::profiler::MICROSECONDS) { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN timestamp_t this_thread_frameTimeLocalAvg(Duration = ::profiler::MICROSECONDS) { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN timestamp_t main_thread_frameTime(Duration = ::profiler::MICROSECONDS) { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN timestamp_t main_thread_frameTimeLocalMax(Duration = ::profiler::MICROSECONDS) { return 0; }
|
||||
inline EASY_CONSTEXPR_FCN 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 EASY_CONSTEXPR_FCN bool isMain() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // END of namespace main_thread.
|
||||
|
||||
/** Alias for isEnabled().
|
||||
|
||||
Added for clarification.
|
||||
|
||||
\sa isEnabled
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
EASY_FORCE_INLINE bool isCapturing() { return isEnabled(); }
|
||||
|
||||
/** Alias for EASY_PROFILER_ENABLE.
|
||||
|
||||
Added for clarification.
|
||||
|
||||
\sa EASY_PROFILER_ENABLE
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
EASY_FORCE_INLINE void startCapture() { EASY_PROFILER_ENABLE; }
|
||||
|
||||
/** Alias for EASY_PROFILER_DISABLE.
|
||||
|
||||
Added for clarification.
|
||||
|
||||
\sa EASY_PROFILER_DISABLE
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
EASY_FORCE_INLINE void stopCapture() { EASY_PROFILER_DISABLE; }
|
||||
|
||||
/** Alias for now().
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
EASY_FORCE_INLINE timestamp_t currentTime() { return now(); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
#if defined ( __clang__ )
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // EASY_PROFILER_H
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_READER_H
|
||||
#define EASY_PROFILER_READER_H
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <easy/serialized_block.h>
|
||||
#include <easy/details/arbitrary_value_public_types.h>
|
||||
#include <easy/utility.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace profiler {
|
||||
|
||||
using processid_t = uint64_t;
|
||||
using calls_number_t = uint32_t;
|
||||
using block_index_t = uint32_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct BlockStatistics EASY_FINAL
|
||||
{
|
||||
profiler::timestamp_t total_duration; ///< Total duration of all block calls
|
||||
profiler::timestamp_t median_duration; ///< Median 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)
|
||||
, median_duration(0)
|
||||
, 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
|
||||
{
|
||||
using This = BlocksTree;
|
||||
|
||||
public:
|
||||
|
||||
using blocks_t = std::vector<This>;
|
||||
using children_t = std::vector<profiler::block_index_t>;
|
||||
|
||||
children_t children; ///< List of children blocks. May be empty.
|
||||
|
||||
union {
|
||||
profiler::SerializedBlock* node; ///< Pointer to serialized data for regular block (id, name, begin, end etc.)
|
||||
profiler::SerializedCSwitch* cs; ///< Pointer to serialized data for context switch (thread_id, name, begin, end etc.)
|
||||
profiler::ArbitraryValue* value; ///< Pointer to serialized data for arbitrary value
|
||||
};
|
||||
|
||||
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(const This&) = delete;
|
||||
This& operator = (const This&) = delete;
|
||||
|
||||
BlocksTree() EASY_NOEXCEPT
|
||||
: node(nullptr)
|
||||
, per_parent_stats(nullptr)
|
||||
, per_frame_stats(nullptr)
|
||||
, per_thread_stats(nullptr)
|
||||
, depth(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BlocksTree(This&& that) EASY_NOEXCEPT
|
||||
: BlocksTree()
|
||||
{
|
||||
make_move(std::forward<This&&>(that));
|
||||
}
|
||||
|
||||
This& operator = (This&& that) EASY_NOEXCEPT
|
||||
{
|
||||
make_move(std::forward<This&&>(that));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~BlocksTree() EASY_NOEXCEPT
|
||||
{
|
||||
release_stats(per_thread_stats);
|
||||
release_stats(per_parent_stats);
|
||||
release_stats(per_frame_stats);
|
||||
}
|
||||
|
||||
bool operator < (const This& other) const EASY_NOEXCEPT
|
||||
{
|
||||
if (node == nullptr || other.node == nullptr)
|
||||
return false;
|
||||
return node->begin() < other.node->begin();
|
||||
}
|
||||
|
||||
void shrink_to_fit() EASY_NOEXCEPT
|
||||
{
|
||||
//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:
|
||||
|
||||
void make_move(This&& that) EASY_NOEXCEPT
|
||||
{
|
||||
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.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Bookmark EASY_FINAL
|
||||
{
|
||||
EASY_STATIC_CONSTEXPR size_t BaseSize = sizeof(profiler::timestamp_t) +
|
||||
sizeof(profiler::color_t) + 1;
|
||||
|
||||
std::string text;
|
||||
profiler::timestamp_t pos;
|
||||
profiler::color_t color;
|
||||
};
|
||||
|
||||
using bookmarks_t = std::vector<Bookmark>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BlocksTreeRoot EASY_FINAL
|
||||
{
|
||||
using This = BlocksTreeRoot;
|
||||
|
||||
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 frames_number; ///< Total frames number (top-level blocks)
|
||||
profiler::block_index_t blocks_number; ///< Total blocks number including their children
|
||||
uint8_t depth; ///< Maximum stack depth (number of levels)
|
||||
|
||||
BlocksTreeRoot(const This&) = delete;
|
||||
This& operator = (const This&) = delete;
|
||||
|
||||
BlocksTreeRoot() EASY_NOEXCEPT
|
||||
: profiled_time(0), wait_time(0), thread_id(0), frames_number(0), blocks_number(0), depth(0)
|
||||
{
|
||||
}
|
||||
|
||||
BlocksTreeRoot(This&& that) EASY_NOEXCEPT
|
||||
: 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)
|
||||
, frames_number(that.frames_number)
|
||||
, blocks_number(that.blocks_number)
|
||||
, depth(that.depth)
|
||||
{
|
||||
}
|
||||
|
||||
This& operator = (This&& that) EASY_NOEXCEPT
|
||||
{
|
||||
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;
|
||||
frames_number = that.frames_number;
|
||||
blocks_number = that.blocks_number;
|
||||
depth = that.depth;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool got_name() const EASY_NOEXCEPT
|
||||
{
|
||||
return !thread_name.empty();
|
||||
}
|
||||
|
||||
inline const char* name() const EASY_NOEXCEPT
|
||||
{
|
||||
return thread_name.c_str();
|
||||
}
|
||||
|
||||
bool operator < (const This& other) const EASY_NOEXCEPT
|
||||
{
|
||||
return thread_id < other.thread_id;
|
||||
}
|
||||
|
||||
}; // END of class BlocksTreeRoot.
|
||||
|
||||
struct BeginEndTime
|
||||
{
|
||||
profiler::timestamp_t beginTime;
|
||||
profiler::timestamp_t endTime;
|
||||
};
|
||||
|
||||
using blocks_t = profiler::BlocksTree::blocks_t;
|
||||
using thread_blocks_tree_t = std::unordered_map<profiler::thread_id_t, profiler::BlocksTreeRoot, ::estd::hash<profiler::thread_id_t> >;
|
||||
using block_getter_fn = std::function<const profiler::BlocksTree&(profiler::block_index_t)>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PROFILER_API SerializedData EASY_FINAL
|
||||
{
|
||||
uint64_t m_size;
|
||||
char* m_data;
|
||||
|
||||
public:
|
||||
|
||||
SerializedData(const SerializedData&) = delete;
|
||||
SerializedData& operator = (const SerializedData&) = delete;
|
||||
|
||||
SerializedData();
|
||||
|
||||
SerializedData(SerializedData&& that);
|
||||
|
||||
~SerializedData();
|
||||
|
||||
void set(uint64_t _size);
|
||||
|
||||
void extend(uint64_t _size);
|
||||
|
||||
SerializedData& operator = (SerializedData&& that);
|
||||
|
||||
char* operator [] (uint64_t i);
|
||||
|
||||
const char* operator [] (uint64_t i) const;
|
||||
|
||||
bool empty() const;
|
||||
|
||||
uint64_t size() const;
|
||||
|
||||
char* data();
|
||||
|
||||
const char* data() const;
|
||||
|
||||
void clear();
|
||||
|
||||
void swap(SerializedData& other);
|
||||
|
||||
private:
|
||||
|
||||
void set(char* _data, uint64_t _size);
|
||||
|
||||
}; // END of class SerializedData.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using descriptors_list_t = std::vector<SerializedBlockDescriptor*>;
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
extern "C" {
|
||||
|
||||
PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
|
||||
profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
profiler::blocks_t& _blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
std::ostream& _log);
|
||||
|
||||
PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& str,
|
||||
profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
profiler::blocks_t& _blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
std::ostream& _log);
|
||||
|
||||
PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& str,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
std::ostream& _log);
|
||||
|
||||
}
|
||||
|
||||
inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors, profiler::blocks_t& _blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
std::ostream& _log)
|
||||
{
|
||||
std::atomic<int> progress(0);
|
||||
return fillTreesFromFile(progress, filename, begin_end_time, serialized_blocks, serialized_descriptors,
|
||||
descriptors, _blocks, threaded_trees, bookmarks, descriptors_count, version, pid,
|
||||
gather_statistics, _log);
|
||||
}
|
||||
|
||||
inline bool readDescriptionsFromStream(std::istream& str,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
std::ostream& _log)
|
||||
{
|
||||
std::atomic<int> progress(0);
|
||||
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER_READER_H
|
||||
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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 <easy/details/profiler_public_types.h>
|
||||
#include <easy/details/arbitrary_value_public_types.h>
|
||||
|
||||
class CSwitchBlock;
|
||||
|
||||
namespace profiler {
|
||||
|
||||
template <DataType dataType, bool isArray>
|
||||
struct Value;
|
||||
|
||||
template <bool isArray>
|
||||
struct Value<DataType::TypesCount, isArray>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PROFILER_API SerializedBlock EASY_FINAL : public BaseBlockData
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
friend ::ThreadStorage;
|
||||
|
||||
public:
|
||||
|
||||
inline const char* data() const { return reinterpret_cast<const char*>(this); }
|
||||
|
||||
///< Run-time block name is stored right after main BaseBlockData data
|
||||
inline const char* name() const { return data() + sizeof(BaseBlockData); }
|
||||
|
||||
SerializedBlock(const SerializedBlock&) = delete;
|
||||
SerializedBlock& operator = (const SerializedBlock&) = delete;
|
||||
SerializedBlock(SerializedBlock&&) = delete;
|
||||
SerializedBlock& operator = (SerializedBlock&&) = delete;
|
||||
~SerializedBlock() = delete;
|
||||
|
||||
private:
|
||||
|
||||
explicit SerializedBlock(const Block& block, uint16_t name_length);
|
||||
|
||||
}; // END of SerializedBlock.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma pack(push, 1)
|
||||
class PROFILER_API CSwitchEvent : public Event
|
||||
{
|
||||
thread_id_t m_thread_id;
|
||||
|
||||
public:
|
||||
|
||||
CSwitchEvent() = default;
|
||||
CSwitchEvent(const CSwitchEvent&) = default;
|
||||
explicit CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid) EASY_NOEXCEPT;
|
||||
|
||||
inline thread_id_t tid() const EASY_NOEXCEPT { return m_thread_id; }
|
||||
|
||||
}; // END of class CSwitchEvent.
|
||||
#pragma pack(pop)
|
||||
|
||||
class PROFILER_API SerializedCSwitch EASY_FINAL : public CSwitchEvent
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
friend ::ThreadStorage;
|
||||
|
||||
public:
|
||||
|
||||
inline const char* data() const { return reinterpret_cast<const char*>(this); }
|
||||
|
||||
///< Run-time block name is stored right after main CSwitchEvent data
|
||||
inline const char* name() const { return data() + sizeof(CSwitchEvent); }
|
||||
|
||||
SerializedCSwitch(const SerializedCSwitch&) = delete;
|
||||
SerializedCSwitch& operator = (const SerializedCSwitch&) = delete;
|
||||
SerializedCSwitch(SerializedCSwitch&&) = delete;
|
||||
SerializedCSwitch& operator = (SerializedCSwitch&&) = delete;
|
||||
~SerializedCSwitch() = delete;
|
||||
|
||||
private:
|
||||
|
||||
explicit SerializedCSwitch(const CSwitchBlock& block, uint16_t name_length);
|
||||
|
||||
}; // END of SerializedCSwitch.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma pack(push, 1)
|
||||
class PROFILER_API SerializedBlockDescriptor EASY_FINAL : public BaseBlockDescriptor
|
||||
{
|
||||
uint16_t m_nameLength; ///< Length of the name including trailing '\0' sybmol
|
||||
|
||||
public:
|
||||
|
||||
inline const char* data() const {
|
||||
return reinterpret_cast<const char*>(this);
|
||||
}
|
||||
|
||||
///< Name is stored right after m_nameLength
|
||||
inline const char* name() const {
|
||||
static const auto shift = sizeof(BaseBlockDescriptor) + sizeof(decltype(m_nameLength));
|
||||
return data() + shift;
|
||||
}
|
||||
|
||||
///< File name is stored right after the name
|
||||
inline const char* file() const {
|
||||
return name() + m_nameLength;
|
||||
}
|
||||
|
||||
inline void setStatus(EasyBlockStatus _status) EASY_NOEXCEPT {
|
||||
m_status = _status;
|
||||
}
|
||||
|
||||
// Instances of this class can not be created or destroyed directly
|
||||
SerializedBlockDescriptor() = delete;
|
||||
SerializedBlockDescriptor(const SerializedBlockDescriptor&) = delete;
|
||||
SerializedBlockDescriptor& operator = (const SerializedBlockDescriptor&) = delete;
|
||||
SerializedBlockDescriptor(SerializedBlockDescriptor&&) = delete;
|
||||
SerializedBlockDescriptor& operator = (SerializedBlockDescriptor&&) = delete;
|
||||
~SerializedBlockDescriptor() = delete;
|
||||
|
||||
}; // END of SerializedBlockDescriptor.
|
||||
//#pragma pack(pop)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//#pragma pack(push, 1)
|
||||
class PROFILER_API ArbitraryValue : protected BaseBlockData
|
||||
{
|
||||
friend ::ThreadStorage;
|
||||
|
||||
protected:
|
||||
|
||||
char m_nameStub; ///< Artificial padding which is used to imitate SerializedBlock::name() == 0 behavior
|
||||
char m_padding; ///< Padding to the bound of 2 bytes
|
||||
uint16_t m_size;
|
||||
DataType m_type;
|
||||
bool m_isArray;
|
||||
vin_t m_value_id;
|
||||
|
||||
explicit ArbitraryValue(timestamp_t _timestamp, vin_t _vin, block_id_t _id,
|
||||
uint16_t _size, DataType _type, bool _isArray)
|
||||
: BaseBlockData(_timestamp, _timestamp, _id)
|
||||
, m_nameStub(0)
|
||||
, m_padding(0)
|
||||
, m_size(_size)
|
||||
, m_type(_type)
|
||||
, m_isArray(_isArray)
|
||||
, m_value_id(_vin)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
using BaseBlockData::id;
|
||||
using Event::begin;
|
||||
|
||||
~ArbitraryValue() = delete;
|
||||
|
||||
const char* data() const {
|
||||
return reinterpret_cast<const char*>(this) + sizeof(ArbitraryValue);
|
||||
}
|
||||
|
||||
uint16_t data_size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
vin_t value_id() const {
|
||||
return m_value_id;
|
||||
}
|
||||
|
||||
DataType type() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
bool isArray() const {
|
||||
return m_isArray;
|
||||
}
|
||||
|
||||
template <DataType dataType>
|
||||
const Value<dataType, false>* toValue() const {
|
||||
return m_type == dataType ? static_cast<const Value<dataType, false>*>(this) : nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const Value<StdToDataType<T>::data_type, false>* toValue() const {
|
||||
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
|
||||
"You should use standard builtin scalar types as profiler::Value type!");
|
||||
return toValue<StdToDataType<T>::data_type>();
|
||||
}
|
||||
|
||||
template <DataType dataType>
|
||||
const Value<dataType, true>* toArray() const {
|
||||
return m_isArray && m_type == dataType ? static_cast<const Value<dataType, true>*>(this) : nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const Value<StdToDataType<T>::data_type, true>* toArray() const {
|
||||
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
|
||||
"You should use standard builtin scalar types as profiler::Value type!");
|
||||
return toArray<StdToDataType<T>::data_type>();
|
||||
}
|
||||
}; // end of class ArbitraryValue.
|
||||
#pragma pack(pop)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <DataType dataType>
|
||||
struct Value<dataType, false> EASY_FINAL : public ArbitraryValue {
|
||||
using value_type = typename StdType<dataType>::value_type;
|
||||
value_type value() const { return *reinterpret_cast<const value_type*>(data()); }
|
||||
~Value() = delete;
|
||||
};
|
||||
|
||||
|
||||
template <DataType dataType>
|
||||
struct Value<dataType, true> EASY_FINAL : public ArbitraryValue {
|
||||
using value_type = typename StdType<dataType>::value_type;
|
||||
const value_type* value() const { return reinterpret_cast<const value_type*>(data()); }
|
||||
uint16_t size() const { return m_size / sizeof(value_type); }
|
||||
value_type operator [] (int i) const { return value()[i]; }
|
||||
value_type at(int i) const { return value()[i]; }
|
||||
~Value() = delete;
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct Value<DataType::String, true> EASY_FINAL : public ArbitraryValue {
|
||||
using value_type = char;
|
||||
const char* value() const { return data(); }
|
||||
uint16_t size() const { return m_size; }
|
||||
char operator [] (int i) const { return data()[i]; }
|
||||
char at(int i) const { return data()[i]; }
|
||||
const char* c_str() const { return data(); }
|
||||
~Value() = delete;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <DataType dataType>
|
||||
using SingleValue = Value<dataType, false>;
|
||||
|
||||
template <DataType dataType>
|
||||
using ArrayValue = Value<dataType, true>;
|
||||
|
||||
using StringValue = Value<DataType::String, true>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
#endif // EASY_PROFILER_SERIALIZED_BLOCK_H
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
|
||||
#ifndef EASY_PROFILER_UTILITY_H
|
||||
#define EASY_PROFILER_UTILITY_H
|
||||
|
||||
#include <easy/details/easy_compiler_support.h>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <math.h>
|
||||
|
||||
namespace estd {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
template <class T, bool BiggerThanPtr> struct hasher {
|
||||
using type = const T&;
|
||||
EASY_FORCE_INLINE size_t operator () (type value) const { return ::std::hash<T> {}(value); } };
|
||||
|
||||
template <class T> struct hasher<T, false> {
|
||||
using type = T;
|
||||
EASY_FORCE_INLINE size_t operator () (type value) const { return static_cast<size_t>(value); } };
|
||||
}
|
||||
|
||||
template <class T> struct hash EASY_FINAL : public ::estd::detail::hasher<T, (sizeof(T) > sizeof(void*))> {
|
||||
using Parent = ::estd::detail::hasher<T, (sizeof(T) > sizeof(void*))>;
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1910
|
||||
// TODO: Try to compile "using Parent::operator();" in MSVC 2017
|
||||
size_t operator () (typename Parent::type value) const { return Parent::operator () (value); }
|
||||
#else
|
||||
using Parent::operator();
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> struct hash<T*> EASY_FINAL {
|
||||
EASY_FORCE_INLINE size_t operator () (const T* value) const { return reinterpret_cast<size_t>(value); } };
|
||||
|
||||
template <class T> struct hash<const T*> EASY_FINAL {
|
||||
EASY_FORCE_INLINE size_t operator () (const T* value) const { return reinterpret_cast<size_t>(value); } };
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T, class Q, class W>
|
||||
inline EASY_CONSTEXPR_FCN Q clamp(T min_value, Q value, W max_value) {
|
||||
return static_cast<Q>(min_value < value ? (value < max_value ? value : max_value) : min_value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
EASY_FORCE_INLINE EASY_CONSTEXPR_FCN T sqr(T value) {
|
||||
return value * value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
EASY_FORCE_INLINE EASY_CONSTEXPR_FCN int sign(T value) { return value < 0 ? -1 : 1; }
|
||||
|
||||
template <class T>
|
||||
inline EASY_CONSTEXPR_FCN T absmin(T a, T b) { return abs(a) < abs(b) ? a : b; }
|
||||
|
||||
template <int N, class T>
|
||||
inline T logn(T value) {
|
||||
EASY_STATIC_CONSTEXPR double div = 1.0 / log2((double)N);
|
||||
return log2(value) * div;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end of namespace estd.
|
||||
|
||||
#endif // EASY_PROFILER_UTILITY_H
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_WRITER_H
|
||||
#define EASY_PROFILER_WRITER_H
|
||||
|
||||
#include <easy/reader.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
|
||||
const profiler::SerializedData& serialized_descriptors,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
profiler::processid_t pid,
|
||||
std::ostream& log);
|
||||
|
||||
PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<int>& progress, std::ostream& str,
|
||||
const profiler::SerializedData& serialized_descriptors,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
profiler::processid_t pid,
|
||||
std::ostream& log);
|
||||
}
|
||||
|
||||
inline profiler::block_index_t writeTreesToFile(const char* filename,
|
||||
const profiler::SerializedData& serialized_descriptors,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
profiler::processid_t pid,
|
||||
std::ostream& log)
|
||||
{
|
||||
std::atomic<int> progress(0);
|
||||
return writeTreesToFile(progress, filename, serialized_descriptors, descriptors, descriptors_count, trees,
|
||||
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
|
||||
}
|
||||
|
||||
inline profiler::block_index_t writeTreesToStream(std::ostream& str,
|
||||
const profiler::SerializedData& serialized_descriptors,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
profiler::processid_t pid,
|
||||
std::ostream& log)
|
||||
{
|
||||
std::atomic<int> progress(0);
|
||||
return writeTreesToStream(progress, str, serialized_descriptors, descriptors, descriptors_count, trees,
|
||||
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
|
||||
}
|
||||
|
||||
#endif //EASY_PROFILER_WRITER_H
|
||||
@@ -0,0 +1,274 @@
|
||||
/************************************************
|
||||
* creation time : 2017/08/20
|
||||
* author : Blake Martin
|
||||
* email : rationalcoder@gmail.com
|
||||
************************************************/
|
||||
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_ALIGNMENT_HELPERS_H
|
||||
#define EASY_PROFILER_ALIGNMENT_HELPERS_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <easy/details/easy_compiler_support.h>
|
||||
|
||||
//! Checks if a pointer is aligned.
|
||||
//! \param ptr The pointer to check.
|
||||
//! \param alignment The alignement (must be a power of 2)
|
||||
//! \returns true if the memory is aligned.
|
||||
//!
|
||||
template <uint32_t ALIGNMENT>
|
||||
EASY_FORCE_INLINE bool is_aligned(void* ptr)
|
||||
{
|
||||
static_assert((ALIGNMENT & 1) == 0, "Alignment must be a power of two.");
|
||||
return ((uintptr_t)ptr & (ALIGNMENT-1)) == 0;
|
||||
}
|
||||
|
||||
EASY_FORCE_INLINE void unaligned_zero16(void* ptr)
|
||||
{
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
*(uint16_t*)ptr = 0;
|
||||
#else
|
||||
((char*)ptr)[0] = 0;
|
||||
((char*)ptr)[1] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
EASY_FORCE_INLINE void unaligned_zero32(void* ptr)
|
||||
{
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
*(uint32_t*)ptr = 0;
|
||||
#else
|
||||
((char*)ptr)[0] = 0;
|
||||
((char*)ptr)[1] = 0;
|
||||
((char*)ptr)[2] = 0;
|
||||
((char*)ptr)[3] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
EASY_FORCE_INLINE void unaligned_zero64(void* ptr)
|
||||
{
|
||||
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
// Assume unaligned is more common.
|
||||
if (!is_aligned<alignof(uint64_t)>(ptr)) {
|
||||
((char*)ptr)[0] = 0;
|
||||
((char*)ptr)[1] = 0;
|
||||
((char*)ptr)[2] = 0;
|
||||
((char*)ptr)[3] = 0;
|
||||
((char*)ptr)[4] = 0;
|
||||
((char*)ptr)[5] = 0;
|
||||
((char*)ptr)[6] = 0;
|
||||
((char*)ptr)[7] = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
*(uint64_t*)ptr = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE void unaligned_store16(void* ptr, T val)
|
||||
{
|
||||
static_assert(sizeof(T) == 2, "16 bit type required.");
|
||||
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
*(T*)ptr = val;
|
||||
#else
|
||||
const char* const temp = (const char*)&val;
|
||||
((char*)ptr)[0] = temp[0];
|
||||
((char*)ptr)[1] = temp[1];
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE void unaligned_store32(void* ptr, T val)
|
||||
{
|
||||
static_assert(sizeof(T) == 4, "32 bit type required.");
|
||||
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
*(T*)ptr = val;
|
||||
#else
|
||||
const char* const temp = (const char*)&val;
|
||||
((char*)ptr)[0] = temp[0];
|
||||
((char*)ptr)[1] = temp[1];
|
||||
((char*)ptr)[2] = temp[2];
|
||||
((char*)ptr)[3] = temp[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE void unaligned_store64(void* ptr, T val)
|
||||
{
|
||||
static_assert(sizeof(T) == 8, "64 bit type required.");
|
||||
|
||||
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
// Assume unaligned is more common.
|
||||
if (!is_aligned<alignof(T)>(ptr)) {
|
||||
const char* const temp = (const char*)&val;
|
||||
((char*)ptr)[0] = temp[0];
|
||||
((char*)ptr)[1] = temp[1];
|
||||
((char*)ptr)[2] = temp[2];
|
||||
((char*)ptr)[3] = temp[3];
|
||||
((char*)ptr)[4] = temp[4];
|
||||
((char*)ptr)[5] = temp[5];
|
||||
((char*)ptr)[6] = temp[6];
|
||||
((char*)ptr)[7] = temp[7];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
*(T*)ptr = val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE T unaligned_load16(const void* ptr)
|
||||
{
|
||||
static_assert(sizeof(T) == 2, "16 bit type required.");
|
||||
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
return *(const T*)ptr;
|
||||
#else
|
||||
T value;
|
||||
((char*)&value)[0] = ((const char*)ptr)[0];
|
||||
((char*)&value)[1] = ((const char*)ptr)[1];
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE T unaligned_load16(const void* ptr, T* val)
|
||||
{
|
||||
static_assert(sizeof(T) == 2, "16 bit type required.");
|
||||
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
*val = *(const T*)ptr;
|
||||
#else
|
||||
((char*)val)[0] = ((const char*)ptr)[0];
|
||||
((char*)val)[1] = ((const char*)ptr)[1];
|
||||
#endif
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE T unaligned_load32(const void* ptr)
|
||||
{
|
||||
static_assert(sizeof(T) == 4, "32 bit type required.");
|
||||
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
return *(const T*)ptr;
|
||||
#else
|
||||
T value;
|
||||
((char*)&value)[0] = ((const char*)ptr)[0];
|
||||
((char*)&value)[1] = ((const char*)ptr)[1];
|
||||
((char*)&value)[2] = ((const char*)ptr)[2];
|
||||
((char*)&value)[3] = ((const char*)ptr)[3];
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE T unaligned_load32(const void* ptr, T* val)
|
||||
{
|
||||
static_assert(sizeof(T) == 4, "32 bit type required.");
|
||||
|
||||
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
*val = *(const T*)ptr;
|
||||
#else
|
||||
((char*)&val)[0] = ((const char*)ptr)[0];
|
||||
((char*)&val)[1] = ((const char*)ptr)[1];
|
||||
((char*)&val)[2] = ((const char*)ptr)[2];
|
||||
((char*)&val)[3] = ((const char*)ptr)[3];
|
||||
#endif
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE T unaligned_load64(const void* ptr)
|
||||
{
|
||||
static_assert(sizeof(T) == 8, "64 bit type required.");
|
||||
|
||||
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
if (!is_aligned<alignof(T)>(ptr)) {
|
||||
T value;
|
||||
((char*)&value)[0] = ((const char*)ptr)[0];
|
||||
((char*)&value)[1] = ((const char*)ptr)[1];
|
||||
((char*)&value)[2] = ((const char*)ptr)[2];
|
||||
((char*)&value)[3] = ((const char*)ptr)[3];
|
||||
((char*)&value)[4] = ((const char*)ptr)[4];
|
||||
((char*)&value)[5] = ((const char*)ptr)[5];
|
||||
((char*)&value)[6] = ((const char*)ptr)[6];
|
||||
((char*)&value)[7] = ((const char*)ptr)[7];
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
return *(const T*)ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EASY_FORCE_INLINE T unaligned_load64(const void* ptr, T* val)
|
||||
{
|
||||
static_assert(sizeof(T) == 8, "64 bit type required.");
|
||||
|
||||
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
|
||||
if (!is_aligned<alignof(T)>(ptr)) {
|
||||
((char*)&val)[0] = ((const char*)ptr)[0];
|
||||
((char*)&val)[1] = ((const char*)ptr)[1];
|
||||
((char*)&val)[2] = ((const char*)ptr)[2];
|
||||
((char*)&val)[3] = ((const char*)ptr)[3];
|
||||
((char*)&val)[4] = ((const char*)ptr)[4];
|
||||
((char*)&val)[5] = ((const char*)ptr)[5];
|
||||
((char*)&val)[6] = ((const char*)ptr)[6];
|
||||
((char*)&val)[7] = ((const char*)ptr)[7];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
*val = *(const T*)ptr;
|
||||
return *val;
|
||||
}
|
||||
|
||||
#endif //EASY_PROFILER_ALIGNMENT_HELPERS_H
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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.
|
||||
|
||||
**/
|
||||
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
|
||||
BaseBlockDescriptor::BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line,
|
||||
block_type_t _block_type, color_t _color) EASY_NOEXCEPT
|
||||
: m_id(_id)
|
||||
, m_line(_line)
|
||||
, m_type(_block_type)
|
||||
, m_color(_color)
|
||||
, m_status(_status)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // end of namespace profiler.
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
/************************************************************************
|
||||
* file name : block.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/02/16
|
||||
* authors : Sergey Yagovtsev, Victor Zarubkin
|
||||
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of profiling blocks
|
||||
* :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2019 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.
|
||||
************************************************************************/
|
||||
|
||||
#include <easy/profiler.h>
|
||||
#include "profile_manager.h"
|
||||
#include "current_time.h"
|
||||
|
||||
namespace profiler {
|
||||
|
||||
#ifndef EASY_PROFILER_API_DISABLED
|
||||
Event::Event(timestamp_t _begin_time) EASY_NOEXCEPT : m_begin(_begin_time), m_end(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Event::Event(timestamp_t _begin_time, timestamp_t _end_time) EASY_NOEXCEPT : m_begin(_begin_time), m_end(_end_time)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id) EASY_NOEXCEPT
|
||||
: Event(_begin_time)
|
||||
, m_id(_descriptor_id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _descriptor_id) EASY_NOEXCEPT
|
||||
: Event(_begin_time, _end_time)
|
||||
, m_id(_descriptor_id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(Block&& that) EASY_NOEXCEPT
|
||||
: BaseBlockData(that.m_begin, that.m_id)
|
||||
, m_name(that.m_name)
|
||||
, m_status(that.m_status)
|
||||
, m_isScoped(that.m_isScoped)
|
||||
{
|
||||
m_end = that.m_end;
|
||||
that.m_end = that.m_begin;
|
||||
}
|
||||
|
||||
Block::Block(timestamp_t _begin_time, block_id_t _descriptor_id, const char* _runtimeName) EASY_NOEXCEPT
|
||||
: BaseBlockData(_begin_time, _descriptor_id)
|
||||
, m_name(_runtimeName)
|
||||
, m_status(::profiler::ON)
|
||||
, m_isScoped(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _descriptor_id, const char* _runtimeName) EASY_NOEXCEPT
|
||||
: BaseBlockData(_begin_time, _end_time, _descriptor_id)
|
||||
, m_name(_runtimeName)
|
||||
, m_status(::profiler::ON)
|
||||
, m_isScoped(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(const BaseBlockDescriptor* _descriptor, const char* _runtimeName, bool _scoped) EASY_NOEXCEPT
|
||||
: BaseBlockData(1ULL, _descriptor->id())
|
||||
, m_name(_runtimeName)
|
||||
, m_status(_descriptor->status())
|
||||
, m_isScoped(_scoped)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Block::start()
|
||||
{
|
||||
m_begin = profiler::clock::now();
|
||||
}
|
||||
|
||||
void Block::start(timestamp_t _time) EASY_NOEXCEPT
|
||||
{
|
||||
m_begin = _time;
|
||||
}
|
||||
|
||||
void Block::finish()
|
||||
{
|
||||
m_end = profiler::clock::now();
|
||||
}
|
||||
|
||||
void Block::finish(timestamp_t _time) EASY_NOEXCEPT
|
||||
{
|
||||
m_end = _time;
|
||||
}
|
||||
|
||||
Block::~Block()
|
||||
{
|
||||
if (!finished())
|
||||
::profiler::endBlock();
|
||||
}
|
||||
#else
|
||||
Event::Event(timestamp_t) EASY_NOEXCEPT : m_begin(0), m_end(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Event::Event(timestamp_t, timestamp_t) EASY_NOEXCEPT : m_begin(0), m_end(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t, block_id_t) EASY_NOEXCEPT
|
||||
: Event(0, 0)
|
||||
, m_id(~0U)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t, timestamp_t, block_id_t) EASY_NOEXCEPT
|
||||
: Event(0, 0)
|
||||
, m_id(~0U)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(Block&& that) EASY_NOEXCEPT
|
||||
: BaseBlockData(0, ~0U)
|
||||
, m_name("")
|
||||
, m_status(::profiler::OFF)
|
||||
, m_isScoped(that.m_isScoped)
|
||||
{
|
||||
}
|
||||
|
||||
Block::Block(timestamp_t, block_id_t, const char*) EASY_NOEXCEPT
|
||||
: BaseBlockData(0, ~0U)
|
||||
, m_name("")
|
||||
, m_status(::profiler::OFF)
|
||||
, m_isScoped(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(timestamp_t, timestamp_t, block_id_t, const char*) EASY_NOEXCEPT
|
||||
: BaseBlockData(0, ~0U)
|
||||
, m_name("")
|
||||
, m_status(::profiler::OFF)
|
||||
, m_isScoped(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(const BaseBlockDescriptor*, const char*, bool _scoped) EASY_NOEXCEPT
|
||||
: BaseBlockData(0, ~0U)
|
||||
, m_name("")
|
||||
, m_status(::profiler::OFF)
|
||||
, m_isScoped(_scoped)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Block::start()
|
||||
{
|
||||
}
|
||||
|
||||
void Block::start(timestamp_t) EASY_NOEXCEPT
|
||||
{
|
||||
}
|
||||
|
||||
void Block::finish()
|
||||
{
|
||||
}
|
||||
|
||||
void Block::finish(timestamp_t) EASY_NOEXCEPT
|
||||
{
|
||||
}
|
||||
|
||||
Block::~Block()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSwitchEvent::CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid) EASY_NOEXCEPT
|
||||
: Event(_begin_time)
|
||||
, m_thread_id(_tid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
CSwitchBlock::CSwitchBlock(profiler::timestamp_t _begin_time, profiler::thread_id_t _tid, const char* _runtimeName) EASY_NOEXCEPT
|
||||
: profiler::CSwitchEvent(_begin_time, _tid)
|
||||
, m_name(_runtimeName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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.
|
||||
|
||||
**/
|
||||
|
||||
#include <memory.h>
|
||||
#include "block_descriptor.h"
|
||||
|
||||
#if EASY_BLOCK_DESC_FULL_COPY == 0
|
||||
# define EASY_BLOCK_DESC_STRING_LEN(s) static_cast<uint16_t>(strlen(s) + 1)
|
||||
# define EASY_BLOCK_DESC_STRING_VAL(s) s
|
||||
#else
|
||||
# define EASY_BLOCK_DESC_STRING_LEN(s) static_cast<uint16_t>(s.size() + 1)
|
||||
# define EASY_BLOCK_DESC_STRING_VAL(s) s.c_str()
|
||||
#endif
|
||||
|
||||
BlockDescriptor::BlockDescriptor(profiler::block_id_t _id, profiler::EasyBlockStatus _status, const char* _name,
|
||||
const char* _filename, int _line, profiler::block_type_t _block_type,
|
||||
profiler::color_t _color)
|
||||
: Parent(_id, _status, _line, _block_type, _color)
|
||||
, m_filename(_filename)
|
||||
, m_name(_name)
|
||||
{
|
||||
}
|
||||
|
||||
const char* BlockDescriptor::name() const
|
||||
{
|
||||
return EASY_BLOCK_DESC_STRING_VAL(m_name);
|
||||
}
|
||||
|
||||
const char* BlockDescriptor::filename() const
|
||||
{
|
||||
return EASY_BLOCK_DESC_STRING_VAL(m_filename);
|
||||
}
|
||||
|
||||
uint16_t BlockDescriptor::nameSize() const
|
||||
{
|
||||
return EASY_BLOCK_DESC_STRING_LEN(m_name);
|
||||
}
|
||||
|
||||
uint16_t BlockDescriptor::filenameSize() const
|
||||
{
|
||||
return EASY_BLOCK_DESC_STRING_LEN(m_filename);
|
||||
}
|
||||
|
||||
void BlockDescriptor::destroy(BlockDescriptor* instance)
|
||||
{
|
||||
#if EASY_BLOCK_DESC_FULL_COPY == 0
|
||||
if (instance != nullptr)
|
||||
instance->~BlockDescriptor();
|
||||
free(instance);
|
||||
#else
|
||||
delete instance;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_BLOCK_DESCRIPTOR_H
|
||||
#define EASY_PROFILER_BLOCK_DESCRIPTOR_H
|
||||
|
||||
#include <string>
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
|
||||
#ifndef EASY_BLOCK_DESC_FULL_COPY
|
||||
# define EASY_BLOCK_DESC_FULL_COPY 1
|
||||
#endif
|
||||
|
||||
class BlockDescriptor : public profiler::BaseBlockDescriptor
|
||||
{
|
||||
friend ProfileManager;
|
||||
|
||||
using Parent = profiler::BaseBlockDescriptor;
|
||||
|
||||
#if EASY_BLOCK_DESC_FULL_COPY == 0
|
||||
using string_t = const char*;
|
||||
#else
|
||||
using string_t = std::string;
|
||||
#endif
|
||||
|
||||
string_t m_filename; ///< Source file name where this block is declared
|
||||
string_t m_name; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier
|
||||
|
||||
public:
|
||||
|
||||
BlockDescriptor() = delete;
|
||||
BlockDescriptor(const BlockDescriptor&) = delete;
|
||||
BlockDescriptor& operator = (const BlockDescriptor&) = delete;
|
||||
|
||||
BlockDescriptor(profiler::block_id_t _id, profiler::EasyBlockStatus _status, const char* _name,
|
||||
const char* _filename, int _line, profiler::block_type_t _block_type, profiler::color_t _color);
|
||||
|
||||
const char* name() const;
|
||||
const char* filename() const;
|
||||
uint16_t nameSize() const;
|
||||
uint16_t filenameSize() const;
|
||||
|
||||
static void destroy(BlockDescriptor* instance);
|
||||
|
||||
}; // END of class BlockDescriptor.
|
||||
|
||||
#endif //EASY_PROFILER_BLOCK_DESCRIPTOR_H
|
||||
+414
@@ -0,0 +1,414 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_CHUNK_ALLOCATOR_H
|
||||
#define EASY_PROFILER_CHUNK_ALLOCATOR_H
|
||||
|
||||
#include <easy/details/easy_compiler_support.h>
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
#include "alignment_helpers.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASY_ENABLE_ALIGNMENT
|
||||
# define EASY_ENABLE_ALIGNMENT 0
|
||||
#endif
|
||||
|
||||
#ifndef EASY_ALIGNMENT_SIZE
|
||||
# define EASY_ALIGNMENT_SIZE EASY_ALIGNOF(std::max_align_t)
|
||||
#endif
|
||||
|
||||
EASY_CONSTEXPR auto EASY_ALIGN_SIZE = EASY_ALIGNMENT_SIZE;
|
||||
|
||||
#if EASY_ENABLE_ALIGNMENT == 0
|
||||
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
|
||||
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
|
||||
# define EASY_FREE(MEMPTR) free(MEMPTR)
|
||||
#else
|
||||
// MSVC and GNUC aligned versions of malloc are defined in malloc.h
|
||||
# include <malloc.h>
|
||||
# if defined(_MSC_VER)
|
||||
# define EASY_ALIGNED(TYPE, VAR, A) __declspec(align(A)) TYPE VAR
|
||||
# define EASY_MALLOC(MEMSIZE, A) _aligned_malloc(MEMSIZE, A)
|
||||
# define EASY_FREE(MEMPTR) _aligned_free(MEMPTR)
|
||||
# elif defined(__GNUC__)
|
||||
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR __attribute__((aligned(A)))
|
||||
# define EASY_MALLOC(MEMSIZE, A) memalign(A, MEMSIZE)
|
||||
# define EASY_FREE(MEMPTR) free(MEMPTR)
|
||||
# else
|
||||
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
|
||||
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
|
||||
# define EASY_FREE(MEMPTR) free(MEMPTR)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <const uint16_t N>
|
||||
class chunk_allocator
|
||||
{
|
||||
static_assert(N != 0, "chunk_allocator<N> N must be a positive value");
|
||||
|
||||
struct chunk { EASY_ALIGNED(char, data[N], EASY_ALIGNMENT_SIZE); chunk* prev = nullptr; };
|
||||
|
||||
struct chunk_list
|
||||
{
|
||||
chunk* last;
|
||||
|
||||
chunk_list(const chunk_list&) = delete;
|
||||
chunk_list(chunk_list&&) = delete;
|
||||
|
||||
chunk_list() : last(nullptr)
|
||||
{
|
||||
static_assert(sizeof(char) == 1, "easy_profiler logic error: sizeof(char) != 1 for this platform! Please, contact easy_profiler authors to resolve your problem.");
|
||||
emplace_back();
|
||||
}
|
||||
|
||||
~chunk_list()
|
||||
{
|
||||
do free_last(); while (last != nullptr);
|
||||
}
|
||||
|
||||
void clear_all_except_last()
|
||||
{
|
||||
while (last->prev != nullptr)
|
||||
free_last();
|
||||
zero_last_chunk_size();
|
||||
}
|
||||
|
||||
void emplace_back()
|
||||
{
|
||||
auto prev = last;
|
||||
last = ::new (EASY_MALLOC(sizeof(chunk), EASY_ALIGNMENT_SIZE)) chunk();
|
||||
last->prev = prev;
|
||||
zero_last_chunk_size();
|
||||
}
|
||||
|
||||
/** Invert current chunks list to enable to iterate over chunks list in direct order.
|
||||
|
||||
This method is used by serialize().
|
||||
*/
|
||||
void invert()
|
||||
{
|
||||
chunk* next = nullptr;
|
||||
|
||||
while (last->prev != nullptr) {
|
||||
auto p = last->prev;
|
||||
last->prev = next;
|
||||
next = last;
|
||||
last = p;
|
||||
}
|
||||
|
||||
last->prev = next;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void free_last()
|
||||
{
|
||||
auto p = last;
|
||||
last = last->prev;
|
||||
EASY_FREE(p);
|
||||
}
|
||||
|
||||
void zero_last_chunk_size()
|
||||
{
|
||||
// Although there is no need for unaligned access stuff b/c a new chunk will
|
||||
// usually be at least 8 byte aligned (and we only need 2 byte alignment),
|
||||
// this is the only way I have been able to get rid of the GCC strict-aliasing warning
|
||||
// without using std::memset. It's an extra line, but is just as fast as *(uint16_t*)last->data = 0;
|
||||
char* const data = last->data;
|
||||
*(uint16_t*)data = (uint16_t)0;
|
||||
}
|
||||
};
|
||||
|
||||
// Used in serialize(): workaround for no constexpr support in MSVC 2013.
|
||||
EASY_STATIC_CONSTEXPR int_fast32_t MaxChunkOffset = N - sizeof(uint16_t);
|
||||
EASY_STATIC_CONSTEXPR uint16_t OneBeforeN = static_cast<uint16_t>(N - 1);
|
||||
|
||||
chunk_list m_chunks; ///< List of chunks.
|
||||
chunk* m_markedChunk; ///< Chunk marked by last closed frame
|
||||
uint32_t m_size; ///< Number of elements stored(# of times allocate() has been called.)
|
||||
uint32_t m_markedSize; ///< Number of elements to the moment when put_mark() has been called.
|
||||
uint16_t m_chunkOffset; ///< Number of bytes used in the current chunk.
|
||||
uint16_t m_markedChunkOffset; ///< Last byte in marked chunk for serializing.
|
||||
|
||||
public:
|
||||
|
||||
chunk_allocator(const chunk_allocator&) = delete;
|
||||
chunk_allocator(chunk_allocator&&) = delete;
|
||||
|
||||
chunk_allocator() : m_markedChunk(nullptr), m_size(0), m_markedSize(0), m_chunkOffset(0), m_markedChunkOffset(0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Allocate n bytes.
|
||||
|
||||
Automatically checks if there is enough preserved memory to store additional n bytes
|
||||
and allocates additional buffer if needed.
|
||||
*/
|
||||
void* allocate(uint16_t n)
|
||||
{
|
||||
++m_size;
|
||||
|
||||
if (!need_expand(n))
|
||||
{
|
||||
// Temp to avoid extra load due to this* aliasing.
|
||||
uint16_t chunkOffset = m_chunkOffset;
|
||||
char* data = m_chunks.last->data + chunkOffset;
|
||||
chunkOffset += n + sizeof(uint16_t);
|
||||
m_chunkOffset = chunkOffset;
|
||||
|
||||
unaligned_store16(data, n);
|
||||
data += sizeof(uint16_t);
|
||||
|
||||
// If there is enough space for at least another payload size,
|
||||
// set it to zero.
|
||||
if (chunkOffset < OneBeforeN)
|
||||
unaligned_zero16(data + n);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
m_chunkOffset = n + sizeof(uint16_t);
|
||||
m_chunks.emplace_back();
|
||||
|
||||
char* data = m_chunks.last->data;
|
||||
unaligned_store16(data, n);
|
||||
data += sizeof(uint16_t);
|
||||
|
||||
// We assume here that it takes more than one element to fill a chunk.
|
||||
unaligned_zero16(data + n);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/** Check if current storage is not enough to store additional n bytes.
|
||||
*/
|
||||
bool need_expand(uint16_t n) const
|
||||
{
|
||||
return (m_chunkOffset + n + sizeof(uint16_t)) > N;
|
||||
}
|
||||
|
||||
uint32_t size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
uint32_t markedSize() const
|
||||
{
|
||||
return m_markedSize;
|
||||
}
|
||||
|
||||
bool markedEmpty() const
|
||||
{
|
||||
return m_markedSize == 0;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_size = 0;
|
||||
m_markedSize = 0;
|
||||
m_chunkOffset = 0;
|
||||
m_markedChunk = nullptr;
|
||||
m_chunks.clear_all_except_last(); // There is always at least one chunk
|
||||
}
|
||||
|
||||
/** Serialize data to stream.
|
||||
|
||||
\warning Data will be cleared after serialization.
|
||||
*/
|
||||
void serialize(std::ostream& _outputStream)
|
||||
{
|
||||
// Chunks are stored in reversed order (stack).
|
||||
// To be able to iterate them in direct order we have to invert the chunks list.
|
||||
m_chunks.invert();
|
||||
|
||||
// Each chunk is an array of N bytes that can hold between
|
||||
// 1(if the list isn't empty) and however many elements can fit in a chunk,
|
||||
// where an element consists of a payload size + a payload as follows:
|
||||
// elementStart[0..1]: size as a uint16_t
|
||||
// elementStart[2..size-1]: payload.
|
||||
|
||||
// The maximum chunk offset is N-sizeof(uint16_t) b/c, if we hit that (or go past),
|
||||
// there is either no space left, 1 byte left, or 2 bytes left, all of which are
|
||||
// too small to cary more than a zero-sized element.
|
||||
|
||||
chunk* current = m_chunks.last;
|
||||
bool isMarked;
|
||||
do {
|
||||
|
||||
isMarked = (current == m_markedChunk);
|
||||
const char* data = current->data;
|
||||
|
||||
const int_fast32_t maxOffset = isMarked ? m_markedChunkOffset : MaxChunkOffset;
|
||||
int_fast32_t chunkOffset = 0; // signed int so overflow is not checked.
|
||||
auto payloadSize = unaligned_load16<uint16_t>(data);
|
||||
|
||||
while (chunkOffset < maxOffset && payloadSize != 0)
|
||||
{
|
||||
const uint16_t chunkSize = sizeof(uint16_t) + payloadSize;
|
||||
_outputStream.write(data, chunkSize);
|
||||
data += chunkSize;
|
||||
chunkOffset += chunkSize;
|
||||
unaligned_load16(data, &payloadSize);
|
||||
}
|
||||
|
||||
current = current->prev;
|
||||
|
||||
} while (current != nullptr && !isMarked);
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
void put_mark()
|
||||
{
|
||||
m_markedChunk = m_chunks.last;
|
||||
m_markedSize = m_size;
|
||||
m_markedChunkOffset = m_chunkOffset;
|
||||
}
|
||||
|
||||
void* marked_allocate(uint16_t n)
|
||||
{
|
||||
chunk* marked = m_markedChunk;
|
||||
if (marked == nullptr || (marked == m_chunks.last && m_markedSize == m_size))
|
||||
{
|
||||
auto data = allocate(n);
|
||||
put_mark();
|
||||
return data;
|
||||
}
|
||||
|
||||
++m_markedSize;
|
||||
|
||||
uint16_t chunkOffset = m_markedChunkOffset;
|
||||
if ((chunkOffset + n + sizeof(uint16_t)) <= N)
|
||||
{
|
||||
// Temp to avoid extra load due to this* aliasing.
|
||||
char* data = marked->data + chunkOffset;
|
||||
chunkOffset += n + sizeof(uint16_t);
|
||||
m_markedChunkOffset = chunkOffset;
|
||||
|
||||
unaligned_store16(data, n);
|
||||
data += sizeof(uint16_t);
|
||||
|
||||
// If there is enough space for at least another payload size,
|
||||
// set it to zero.
|
||||
if (chunkOffset < OneBeforeN)
|
||||
unaligned_zero16(data + n);
|
||||
|
||||
if (marked == m_chunks.last && chunkOffset > m_chunkOffset)
|
||||
m_chunkOffset = chunkOffset;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
chunkOffset = n + sizeof(uint16_t);
|
||||
m_markedChunkOffset = chunkOffset;
|
||||
|
||||
chunk* last = m_chunks.last;
|
||||
if (marked == last)
|
||||
{
|
||||
m_chunks.emplace_back();
|
||||
last = m_chunks.last;
|
||||
m_chunkOffset = chunkOffset;
|
||||
m_size = m_markedSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
do last = last->prev; while (last->prev != m_markedChunk);
|
||||
}
|
||||
|
||||
m_markedChunk = last;
|
||||
char* data = last->data;
|
||||
unaligned_store16(data, n);
|
||||
data += sizeof(uint16_t);
|
||||
|
||||
// We assume here that it takes more than one element to fill a chunk.
|
||||
unaligned_zero16(data + n);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}; // END of class chunk_allocator.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <const uint16_t N, bool, bool>
|
||||
struct aligned_size;
|
||||
|
||||
template <const uint16_t N, bool dummy>
|
||||
struct aligned_size<N, true, dummy> {
|
||||
EASY_STATIC_CONSTEXPR uint16_t Size = N;
|
||||
};
|
||||
|
||||
template <const uint16_t N>
|
||||
struct aligned_size<N, false, true> {
|
||||
EASY_STATIC_CONSTEXPR uint16_t Size = static_cast<uint16_t>(N - (N % EASY_ALIGN_SIZE));
|
||||
};
|
||||
|
||||
template <const uint16_t N>
|
||||
struct aligned_size<N, false, false> {
|
||||
EASY_STATIC_CONSTEXPR uint16_t Size = static_cast<uint16_t>(N + EASY_ALIGN_SIZE - (N % EASY_ALIGN_SIZE));
|
||||
};
|
||||
|
||||
template <const size_t N>
|
||||
struct get_aligned_size {
|
||||
EASY_STATIC_CONSTEXPR uint16_t Size =
|
||||
aligned_size<static_cast<uint16_t>(N), (N % EASY_ALIGN_SIZE) == 0, (N > (65536 - EASY_ALIGN_SIZE))>::Size;
|
||||
};
|
||||
|
||||
static_assert(get_aligned_size<EASY_ALIGN_SIZE - 3>::Size == EASY_ALIGN_SIZE, "wrong get_aligned_size");
|
||||
static_assert(get_aligned_size<2 * EASY_ALIGN_SIZE - 3>::Size == 2 * EASY_ALIGN_SIZE, "wrong get_aligned_size");
|
||||
static_assert(get_aligned_size<65530>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
|
||||
static_assert(get_aligned_size<65526>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
|
||||
static_assert(get_aligned_size<65536 - EASY_ALIGN_SIZE>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
|
||||
static_assert(get_aligned_size<65536 + 3 - EASY_ALIGN_SIZE * 2>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER_CHUNK_ALLOCATOR_H
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_CURRENT_THREAD_H
|
||||
#define EASY_PROFILER_CURRENT_THREAD_H
|
||||
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <Windows.h>
|
||||
#elif defined(__APPLE__)
|
||||
# include <pthread.h>
|
||||
# include <Availability.h>
|
||||
#elif defined(__QNX__)
|
||||
# include <sys/mman.h>
|
||||
# include <process.h>
|
||||
# define __NR_gettid SYS_gettid
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
inline profiler::thread_id_t getCurrentThreadId()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (profiler::thread_id_t)::GetCurrentThreadId();
|
||||
#elif defined(__APPLE__)
|
||||
# if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_6) || \
|
||||
(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
|
||||
static EASY_THREAD_LOCAL uint64_t _id = 0;
|
||||
if (!_id)
|
||||
pthread_threadid_np(NULL, &_id);
|
||||
return (profiler::thread_id_t)_id;
|
||||
# else
|
||||
return (profiler::thread_id_t)pthread_self();
|
||||
# endif
|
||||
#elif defined(__QNX__)
|
||||
EASY_THREAD_LOCAL static const profiler::thread_id_t _id = (profiler::thread_id_t)gettid();
|
||||
return _id;
|
||||
#else
|
||||
EASY_THREAD_LOCAL static const profiler::thread_id_t _id = (profiler::thread_id_t)syscall(__NR_gettid);
|
||||
return _id;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // EASY_PROFILER_CURRENT_THREAD_H
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_CURRENT_TIME_H
|
||||
#define EASY_PROFILER_CURRENT_TIME_H
|
||||
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
// std::chrono for MSVC2013 is broken - it has very low resolution of 16ms
|
||||
// restrict usage of std::chrono
|
||||
# if EASY_CHRONO_HIGHRES_CLOCK
|
||||
# undef EASY_CHRONO_HIGHRES_CLOCK
|
||||
# endif
|
||||
# if EASY_CHRONO_STEADY_CLOCK
|
||||
# undef EASY_CHRONO_STEADY_CLOCK
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if EASY_CHRONO_HIGHRES_CLOCK
|
||||
# include <chrono>
|
||||
# define EASY_CHRONO_CLOCK std::chrono::high_resolution_clock
|
||||
#elif EASY_CHRONO_STEADY_CLOCK
|
||||
# include <chrono>
|
||||
# define EASY_CHRONO_CLOCK std::chrono::steady_clock
|
||||
#elif defined(_WIN32)
|
||||
# include <Windows.h>
|
||||
#else
|
||||
# include <chrono>
|
||||
# include <time.h>
|
||||
# ifdef __ARM_ARCH
|
||||
# include <sys/time.h>
|
||||
# endif//__ARM_ARCH
|
||||
#endif
|
||||
# ifdef __mips__
|
||||
# include <sys/time.h>
|
||||
# endif//__mips__
|
||||
|
||||
namespace profiler { namespace clock {
|
||||
|
||||
static inline profiler::timestamp_t now()
|
||||
{
|
||||
#if EASY_CHRONO_HIGHRES_CLOCK || EASY_CHRONO_STEADY_CLOCK
|
||||
return (profiler::timestamp_t)EASY_CHRONO_CLOCK::now().time_since_epoch().count();
|
||||
#elif defined(_WIN32)
|
||||
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
|
||||
LARGE_INTEGER elapsedMicroseconds;
|
||||
if (!QueryPerformanceCounter(&elapsedMicroseconds))
|
||||
return 0;
|
||||
return (profiler::timestamp_t)elapsedMicroseconds.QuadPart;
|
||||
#else// not _WIN32
|
||||
|
||||
#if (defined(__GNUC__) || defined(__ICC))
|
||||
|
||||
// part of code from google/benchmark library (Licensed under the Apache License, Version 2.0)
|
||||
// see https://github.com/google/benchmark/blob/master/src/cycleclock.h#L111
|
||||
#if defined(__i386__)
|
||||
int64_t ret;
|
||||
__asm__ volatile("rdtsc" : "=A"(ret));
|
||||
return ret;
|
||||
#elif defined(__x86_64__) || defined(__amd64__)
|
||||
uint64_t low, high;
|
||||
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
|
||||
return (high << 32) | low;
|
||||
#elif defined(__powerpc__) || defined(__ppc__)
|
||||
// This returns a time-base, which is not always precisely a cycle-count.
|
||||
int64_t tbl, tbu0, tbu1;
|
||||
asm("mftbu %0" : "=r"(tbu0));
|
||||
asm("mftb %0" : "=r"(tbl));
|
||||
asm("mftbu %0" : "=r"(tbu1));
|
||||
tbl &= -static_cast<int64>(tbu0 == tbu1);
|
||||
// high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage)
|
||||
return (tbu1 << 32) | tbl;
|
||||
#elif defined(__sparc__)
|
||||
int64_t tick;
|
||||
asm(".byte 0x83, 0x41, 0x00, 0x00");
|
||||
asm("mov %%g1, %0" : "=r"(tick));
|
||||
return tick;
|
||||
#elif defined(__ia64__)
|
||||
int64_t itc;
|
||||
asm("mov %0 = ar.itc" : "=r"(itc));
|
||||
return itc;
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||
// Older MSVC compilers (like 7.x) don't seem to support the
|
||||
// __rdtsc intrinsic properly, so I prefer to use _asm instead
|
||||
// when I know it will work. Otherwise, I'll use __rdtsc and hope
|
||||
// the code is being compiled with a non-ancient compiler.
|
||||
_asm rdtsc
|
||||
#elif defined(_MSC_VER)
|
||||
return __rdtsc();
|
||||
#elif defined(__aarch64__)
|
||||
// System timer of ARMv8 runs at a different frequency than the CPU's.
|
||||
// The frequency is fixed, typically in the range 1-50MHz. It can be
|
||||
// read at CNTFRQ special register. We assume the OS has set up
|
||||
// the virtual timer properly.
|
||||
int64_t virtual_timer_value;
|
||||
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
|
||||
return virtual_timer_value;
|
||||
#elif defined(__ARM_ARCH)
|
||||
#if (__ARM_ARCH >= 6) // V6 is the earliest arch that has a standard cyclecount
|
||||
uint32_t pmccntr;
|
||||
uint32_t pmuseren;
|
||||
uint32_t pmcntenset;
|
||||
// Read the user mode perf monitor counter access permissions.
|
||||
asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
|
||||
if (pmuseren & 1) { // Allows reading perfmon counters for user mode code.
|
||||
asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
|
||||
if (pmcntenset & 0x80000000ul) { // Is it counting?
|
||||
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
|
||||
// The counter is set up to count every 64th cycle
|
||||
return static_cast<int64_t>(pmccntr) * 64; // Should optimize to << 6
|
||||
}
|
||||
}
|
||||
#endif
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
#elif defined(__mips__)
|
||||
// mips apparently only allows rdtsc for superusers, so we fall
|
||||
// back to gettimeofday. It's possible clock_gettime would be better.
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
#else
|
||||
#warning You need to define fast now() for your OS and CPU
|
||||
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
#define EASY_CHRONO_CLOCK std::chrono::high_resolution_clock
|
||||
#endif
|
||||
|
||||
#else // not _WIN32, __GNUC__, __ICC
|
||||
#warning You need to define fast now() for your OS and CPU
|
||||
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
#define EASY_CHRONO_CLOCK std::chrono::high_resolution_clock
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} } // end of namespace profiler::clock.
|
||||
|
||||
#endif // EASY_PROFILER_CURRENT_TIME_H
|
||||
+438
@@ -0,0 +1,438 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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.
|
||||
**/
|
||||
|
||||
#include <easy/easy_socket.h>
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <limits>
|
||||
#if defined(__QNX__)
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# pragma comment (lib, "Ws2_32.lib")
|
||||
# pragma comment (lib, "Mswsock.lib")
|
||||
# pragma comment (lib, "AdvApi32.lib")
|
||||
# ifdef max
|
||||
# undef max
|
||||
# endif
|
||||
#else
|
||||
# include <errno.h>
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(_WIN32)
|
||||
const int SOCK_ABORTED = WSAECONNABORTED;
|
||||
const int SOCK_RESET = WSAECONNRESET;
|
||||
const int SOCK_IN_PROGRESS = WSAEINPROGRESS;
|
||||
#else
|
||||
const int SOCK_ABORTED = ECONNABORTED;
|
||||
const int SOCK_RESET = ECONNRESET;
|
||||
const int SOCK_IN_PROGRESS = EINPROGRESS;
|
||||
const int SOCK_BROKEN_PIPE = EPIPE;
|
||||
const int SOCK_ENOENT = ENOENT;
|
||||
#endif
|
||||
|
||||
const int SEND_BUFFER_SIZE = 64 * 1024 * 1024;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
static int closeSocket(EasySocket::socket_t s)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return ::closesocket(s);
|
||||
#else
|
||||
return ::close(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
bool EasySocket::checkSocket(socket_t s) const
|
||||
{
|
||||
return s > 0;
|
||||
}
|
||||
|
||||
void EasySocket::setBlocking(EasySocket::socket_t s, bool blocking)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
u_long iMode = blocking ? 0 : 1;//0 - blocking, 1 - non blocking
|
||||
::ioctlsocket(s, FIONBIO, &iMode);
|
||||
#else
|
||||
int iMode = blocking ? 0 : 1;//0 - blocking, 1 - non blocking
|
||||
::ioctl(s, FIONBIO, (char*)&iMode);
|
||||
#endif
|
||||
}
|
||||
|
||||
int EasySocket::bind(uint16_t port)
|
||||
{
|
||||
if (!checkSocket(m_socket))
|
||||
return -1;
|
||||
|
||||
struct sockaddr_in server_address;
|
||||
memset(&server_address, 0, sizeof(server_address));
|
||||
server_address.sin_family = AF_INET;
|
||||
server_address.sin_addr.s_addr = INADDR_ANY;
|
||||
server_address.sin_port = htons(port);
|
||||
auto res = ::bind(m_socket, (struct sockaddr *)&server_address, sizeof(server_address));
|
||||
return res;
|
||||
}
|
||||
|
||||
void EasySocket::flush()
|
||||
{
|
||||
if (m_socket)
|
||||
closeSocket(m_socket);
|
||||
|
||||
if (m_replySocket != m_socket && m_replySocket != 0) {
|
||||
// we do not need to close uninitialized reply socket
|
||||
closeSocket(m_replySocket);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
m_socket = 0;
|
||||
m_replySocket = 0;
|
||||
#else
|
||||
m_wsaret = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EasySocket::checkResult(int result)
|
||||
{
|
||||
if (result >= 0)
|
||||
{
|
||||
m_state = ConnectionState::Connected;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == -1) // is this check necessary?
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
const int error_code = WSAGetLastError();
|
||||
#else
|
||||
const int error_code = errno;
|
||||
#endif
|
||||
|
||||
switch (error_code)
|
||||
{
|
||||
case SOCK_ABORTED:
|
||||
case SOCK_RESET:
|
||||
#if !defined(_WIN32)
|
||||
case SOCK_BROKEN_PIPE:
|
||||
case SOCK_ENOENT:
|
||||
#endif
|
||||
#if defined (__APPLE__)
|
||||
case ECONNREFUSED:
|
||||
#endif
|
||||
m_state = ConnectionState::Disconnected;
|
||||
break;
|
||||
|
||||
case SOCK_IN_PROGRESS:
|
||||
m_state = ConnectionState::Connecting;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EasySocket::init()
|
||||
{
|
||||
if (m_wsaret != 0)
|
||||
return;
|
||||
|
||||
#if !defined(_WIN32)
|
||||
const int protocol = 0;
|
||||
#else
|
||||
const int protocol = IPPROTO_TCP;
|
||||
#endif
|
||||
|
||||
m_socket = ::socket(AF_INET, SOCK_STREAM, protocol);
|
||||
if (!checkSocket(m_socket))
|
||||
return;
|
||||
|
||||
setBlocking(m_socket, true);
|
||||
|
||||
#if !defined(_WIN32)
|
||||
m_wsaret = 1;
|
||||
#endif
|
||||
|
||||
const int opt = 1;
|
||||
::setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(int));
|
||||
}
|
||||
|
||||
EasySocket::ConnectionState EasySocket::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
bool EasySocket::isDisconnected() const
|
||||
{
|
||||
return static_cast<int>(m_state) <= 0;
|
||||
}
|
||||
|
||||
bool EasySocket::isConnected() const
|
||||
{
|
||||
return m_state == ConnectionState::Connected;
|
||||
}
|
||||
|
||||
EasySocket::EasySocket()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
WSADATA wsaData;
|
||||
m_wsaret = WSAStartup(0x101, &wsaData);
|
||||
#else
|
||||
m_wsaret = 0;
|
||||
#endif
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
EasySocket::~EasySocket()
|
||||
{
|
||||
flush();
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (m_wsaret == 0)
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void EasySocket::setReceiveTimeout(int milliseconds)
|
||||
{
|
||||
if (!isConnected() || !checkSocket(m_replySocket))
|
||||
return;
|
||||
|
||||
if (milliseconds <= 0)
|
||||
milliseconds = std::numeric_limits<int>::max() / 1000;
|
||||
|
||||
#if defined(_WIN32)
|
||||
const DWORD timeout = static_cast<DWORD>(milliseconds);
|
||||
::setsockopt(m_replySocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
|
||||
#else
|
||||
struct timeval tv;
|
||||
if (milliseconds >= 1000)
|
||||
{
|
||||
const int s = milliseconds / 1000;
|
||||
const int us = (milliseconds - s * 1000) * 1000;
|
||||
tv.tv_sec = s;
|
||||
tv.tv_usec = us;
|
||||
}
|
||||
else
|
||||
{
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = milliseconds * 1000;
|
||||
}
|
||||
|
||||
::setsockopt(m_replySocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof (struct timeval));
|
||||
#endif
|
||||
}
|
||||
|
||||
int EasySocket::send(const void* buffer, size_t nbytes)
|
||||
{
|
||||
if (!checkSocket(m_replySocket))
|
||||
return -1;
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
const int res = ::send(m_replySocket, (const char*)buffer, (int)nbytes, 0);
|
||||
#else
|
||||
const int res = (int)::send(m_replySocket, buffer, nbytes, MSG_NOSIGNAL);
|
||||
#endif
|
||||
|
||||
checkResult(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int EasySocket::receive(void* buffer, size_t nbytes)
|
||||
{
|
||||
if (!checkSocket(m_replySocket))
|
||||
return -1;
|
||||
|
||||
#if defined(_WIN32)
|
||||
const int res = ::recv(m_replySocket, (char*)buffer, (int)nbytes, 0);
|
||||
#else
|
||||
const int res = (int)::read(m_replySocket, buffer, nbytes);
|
||||
#endif
|
||||
|
||||
checkResult(res);
|
||||
if (res == 0)
|
||||
m_state = ConnectionState::Disconnected;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int EasySocket::listen(int count)
|
||||
{
|
||||
if (!checkSocket(m_socket))
|
||||
return -1;
|
||||
|
||||
const int res = ::listen(m_socket, count);
|
||||
checkResult(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int EasySocket::accept()
|
||||
{
|
||||
if (!checkSocket(m_socket))
|
||||
return -1;
|
||||
|
||||
fd_set fdread;
|
||||
FD_ZERO (&fdread);
|
||||
FD_SET (m_socket, &fdread);
|
||||
|
||||
fd_set fdwrite = fdread;
|
||||
fd_set fdexcl = fdread;
|
||||
|
||||
struct timeval tv { 0, 500 };
|
||||
const int rc = ::select((int)m_socket + 1, &fdread, &fdwrite, &fdexcl, &tv);
|
||||
if (rc <= 0)
|
||||
return -1; // there is no connection for accept
|
||||
|
||||
m_replySocket = ::accept(m_socket, nullptr, nullptr);
|
||||
checkResult((int)m_replySocket);
|
||||
|
||||
if (checkSocket(m_replySocket))
|
||||
{
|
||||
::setsockopt(m_replySocket, SOL_SOCKET, SO_SNDBUF, (char*)&SEND_BUFFER_SIZE, sizeof(int));
|
||||
|
||||
//const int flag = 1;
|
||||
//const int result = setsockopt(m_replySocket,IPPROTO_TCP,TCP_NODELAY,(char *)&flag,sizeof(int));
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// Apple doesn't have MSG_NOSIGNAL, work around it
|
||||
const int value = 1;
|
||||
::setsockopt(m_replySocket, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
|
||||
#endif
|
||||
|
||||
//setBlocking(m_replySocket,true);
|
||||
}
|
||||
|
||||
return (int)m_replySocket;
|
||||
}
|
||||
|
||||
bool EasySocket::setAddress(const char* address, uint16_t port)
|
||||
{
|
||||
m_server = ::gethostbyname(address);
|
||||
if (m_server == nullptr)
|
||||
return false;
|
||||
|
||||
memset((char*)&m_serverAddress, 0, sizeof(m_serverAddress));
|
||||
m_serverAddress.sin_family = AF_INET;
|
||||
memcpy((char*)&m_serverAddress.sin_addr.s_addr, (char*)m_server->h_addr, (size_t)m_server->h_length);
|
||||
|
||||
m_serverAddress.sin_port = htons(port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int EasySocket::connect()
|
||||
{
|
||||
if (m_server == nullptr || m_socket <= 0)
|
||||
return -1;
|
||||
|
||||
int res = 0;
|
||||
//TODO: more intelligence
|
||||
#if !defined(_WIN32)
|
||||
setBlocking(m_socket, false);
|
||||
|
||||
const int sleepMs = 20;
|
||||
const int waitSec = 1;
|
||||
const int waitMs = waitSec * 1000 / sleepMs;
|
||||
|
||||
for (int counter = 0; counter++ < waitMs;)
|
||||
{
|
||||
res = ::connect(m_socket, (struct sockaddr*)&m_serverAddress, sizeof(m_serverAddress));
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// on Apple, treat EISCONN error as success
|
||||
if (res == -1 && errno == EISCONN)
|
||||
{
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
checkResult(res);
|
||||
if (res == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_state == ConnectionState::Connecting)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDisconnected())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setBlocking(m_socket, true);
|
||||
#else
|
||||
res = ::connect(m_socket, (struct sockaddr*)&m_serverAddress, sizeof(m_serverAddress));
|
||||
checkResult(res);
|
||||
#endif
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
::setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// Apple doesn't have MSG_NOSIGNAL, work around it
|
||||
const int value = 1;
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
|
||||
#endif
|
||||
|
||||
m_replySocket = m_socket;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
|
||||
#ifndef EASY_PROFILER__EVENT_TRACE_STATUS__H_
|
||||
#define EASY_PROFILER__EVENT_TRACE_STATUS__H_
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class EventTracingEnableStatus : unsigned char
|
||||
{
|
||||
LaunchedSuccessfully = 0,
|
||||
PermissionDenied,
|
||||
AlreadyLaunched,
|
||||
BadPropertiesSize,
|
||||
OpenTraceFailed,
|
||||
UnknownError,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER__EVENT_TRACE_STATUS__H_
|
||||
@@ -0,0 +1,587 @@
|
||||
/************************************************************************
|
||||
* file name : event_trace_win.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/09/04
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of EasyEventTracer class used for tracing
|
||||
* : Windows system events to get context switches.
|
||||
* ----------------- :
|
||||
* change log : * 2016/09/04 Victor Zarubkin: initial commit.
|
||||
* :
|
||||
* : * 2016/09/13 Victor Zarubkin: get process id and process name
|
||||
* : of the owner of thread with id == CSwitch::NewThreadId.
|
||||
* :
|
||||
* : * 2016/09/17 Victor Zarubkin: added log messages printing.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2019 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.
|
||||
************************************************************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <memory.h>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
#include <easy/profiler.h>
|
||||
#include "profile_manager.h"
|
||||
#include "current_time.h"
|
||||
|
||||
#include "event_trace_win.h"
|
||||
#include <Psapi.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <processthreadsapi.h>
|
||||
#endif
|
||||
|
||||
//#include <Shellapi.h>
|
||||
|
||||
#if EASY_OPTION_LOG_ENABLED != 0
|
||||
# include <iostream>
|
||||
|
||||
# ifndef EASY_ERRORLOG
|
||||
# define EASY_ERRORLOG std::cerr
|
||||
# endif
|
||||
|
||||
# ifndef EASY_LOG
|
||||
# define EASY_LOG std::cerr
|
||||
# endif
|
||||
|
||||
# ifndef EASY_ERROR
|
||||
# define EASY_ERROR(LOG_MSG) EASY_ERRORLOG << "EasyProfiler ERROR: " << LOG_MSG
|
||||
# endif
|
||||
|
||||
# ifndef EASY_WARNING
|
||||
# define EASY_WARNING(LOG_MSG) EASY_ERRORLOG << "EasyProfiler WARNING: " << LOG_MSG
|
||||
# endif
|
||||
|
||||
# ifndef EASY_LOGMSG
|
||||
# define EASY_LOGMSG(LOG_MSG) EASY_LOG << "EasyProfiler INFO: " << LOG_MSG
|
||||
# endif
|
||||
|
||||
# ifndef EASY_LOG_ONLY
|
||||
# define EASY_LOG_ONLY(CODE) CODE
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# ifndef EASY_ERROR
|
||||
# define EASY_ERROR(LOG_MSG)
|
||||
# endif
|
||||
|
||||
# ifndef EASY_WARNING
|
||||
# define EASY_WARNING(LOG_MSG)
|
||||
# endif
|
||||
|
||||
# ifndef EASY_LOGMSG
|
||||
# define EASY_LOGMSG(LOG_MSG)
|
||||
# endif
|
||||
|
||||
# ifndef EASY_LOG_ONLY
|
||||
# define EASY_LOG_ONLY(CODE)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern const profiler::color_t EASY_COLOR_INTERNAL_EVENT;
|
||||
|
||||
#ifdef __MINGW32__
|
||||
static std::atomic<uint64_t> TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
|
||||
static char KERNEL_LOGGER[] = KERNEL_LOGGER_NAME;
|
||||
#else
|
||||
static std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Retrieve the process name of the given process.
|
||||
*
|
||||
* This method is NOT thread-safe: the returned string has to be copied somewhere before this
|
||||
* method can be used by another thread or call.
|
||||
*
|
||||
* getProcessName() owns the returned string.
|
||||
*
|
||||
* \param len the process name string length [output].
|
||||
*
|
||||
* \return the process name string.
|
||||
*/
|
||||
static const char* getProcessName(HANDLE hProcess, std::size_t& len)
|
||||
{
|
||||
static TCHAR buf[MAX_PATH] = {};
|
||||
len = static_cast<std::size_t>(GetModuleBaseName(hProcess, 0, buf, MAX_PATH));
|
||||
if (len == 0)
|
||||
return nullptr;
|
||||
|
||||
#if UNICODE
|
||||
static char charbuf[MAX_PATH] = {};
|
||||
len = std::wcstombs(charbuf, buf, len);
|
||||
return charbuf;
|
||||
#else
|
||||
return buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
EASY_CONSTEXPR decltype(EVENT_DESCRIPTOR::Opcode) SWITCH_CONTEXT_OPCODE = 36;
|
||||
EASY_CONSTEXPR int RAW_TIMESTAMP_TIME_TYPE = 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct ProcessInfo {
|
||||
std::string name;
|
||||
processid_t id = 0;
|
||||
int8_t valid = 0;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// CSwitch class
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa964744(v=vs.85).aspx
|
||||
// EventType = 36
|
||||
struct CSwitch
|
||||
{
|
||||
uint32_t NewThreadId;
|
||||
uint32_t OldThreadId;
|
||||
int8_t NewThreadPriority;
|
||||
int8_t OldThreadPriority;
|
||||
uint8_t PreviousCState;
|
||||
int8_t SpareByte;
|
||||
int8_t OldThreadWaitReason;
|
||||
int8_t OldThreadWaitMode;
|
||||
int8_t OldThreadState;
|
||||
int8_t OldThreadWaitIdealProcessor;
|
||||
uint32_t NewThreadWaitTime;
|
||||
uint32_t Reserved;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct do_not_calc_hash {
|
||||
template <class T> inline size_t operator()(T _value) const {
|
||||
return static_cast<size_t>(_value);
|
||||
}
|
||||
};
|
||||
|
||||
using thread_process_info_map = std::unordered_map<decltype(CSwitch::NewThreadId), ProcessInfo*, do_not_calc_hash>;
|
||||
using process_info_map = std::unordered_map<processid_t, ProcessInfo, do_not_calc_hash>;
|
||||
|
||||
// Using static is safe because easyProcessTraceEvent() is called from one thread
|
||||
static process_info_map PROCESS_INFO_TABLE;
|
||||
static thread_process_info_map THREAD_PROCESS_INFO_TABLE;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void WINAPI easyProcessTraceEvent(PEVENT_RECORD _traceEvent)
|
||||
{
|
||||
if (_traceEvent->EventHeader.EventDescriptor.Opcode != SWITCH_CONTEXT_OPCODE)
|
||||
return;
|
||||
|
||||
if (sizeof(CSwitch) != _traceEvent->UserDataLength)
|
||||
return;
|
||||
|
||||
EASY_FUNCTION(EASY_COLOR_INTERNAL_EVENT, profiler::OFF);
|
||||
|
||||
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_traceEvent->UserData);
|
||||
const auto time = static_cast<profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
|
||||
if (time > TRACING_END_TIME.load(std::memory_order_acquire))
|
||||
return;
|
||||
|
||||
DWORD pid = 0;
|
||||
const char* process_name = "";
|
||||
|
||||
// Trying to get target process name and id
|
||||
auto it = THREAD_PROCESS_INFO_TABLE.find(_contextSwitchEvent->NewThreadId);
|
||||
if (it == THREAD_PROCESS_INFO_TABLE.end())
|
||||
{
|
||||
auto hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, _contextSwitchEvent->NewThreadId);
|
||||
if (hThread != nullptr)
|
||||
{
|
||||
pid = GetProcessIdOfThread(hThread);
|
||||
auto pinfo = &PROCESS_INFO_TABLE[pid];
|
||||
|
||||
if (pinfo->valid == 0)
|
||||
{
|
||||
if (pinfo->name.empty())
|
||||
{
|
||||
static char numbuf[128] = {};
|
||||
sprintf(numbuf, "%u", pid);
|
||||
pinfo->name = numbuf;
|
||||
pinfo->id = pid;
|
||||
}
|
||||
|
||||
/*
|
||||
According to documentation, using GetModuleBaseName() requires
|
||||
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ access rights.
|
||||
But it works fine with PROCESS_QUERY_LIMITED_INFORMATION instead of PROCESS_QUERY_INFORMATION.
|
||||
|
||||
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683196(v=vs.85).aspx
|
||||
*/
|
||||
|
||||
//auto hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
|
||||
//if (hProc == nullptr)
|
||||
auto hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, FALSE, pid);
|
||||
if (hProc != nullptr)
|
||||
{
|
||||
std::size_t len = 0;
|
||||
auto processName = getProcessName(hProc, len); // Using thread-unsafe method is safe because processTraceEvent() is called from one thread
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
pinfo->name.reserve(pinfo->name.size() + 2 + len);
|
||||
pinfo->name.append(" ", 1);
|
||||
pinfo->name.append(processName, len);
|
||||
pinfo->valid = 1;
|
||||
}
|
||||
|
||||
CloseHandle(hProc);
|
||||
}
|
||||
else
|
||||
{
|
||||
//auto err = GetLastError();
|
||||
//printf("OpenProcess(%u) fail: GetLastError() == %u\n", pid, err);
|
||||
pinfo->valid = -1;
|
||||
|
||||
if (pid == 4) {
|
||||
pinfo->name.reserve(pinfo->name.size() + 8);
|
||||
pinfo->name.append(" System", 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process_name = pinfo->name.c_str();
|
||||
THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = pinfo;
|
||||
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Can not OpenThread(%u);\n", _contextSwitchEvent->NewThreadId);
|
||||
THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pinfo = it->second;
|
||||
if (pinfo != nullptr)
|
||||
process_name = pinfo->name.c_str();
|
||||
else if (it->first == 0)
|
||||
process_name = "System Idle";
|
||||
else if (it->first == 4)
|
||||
process_name = "System";
|
||||
}
|
||||
|
||||
ProfileManager::instance().beginContextSwitch(_contextSwitchEvent->OldThreadId, time, _contextSwitchEvent->NewThreadId, process_name);
|
||||
ProfileManager::instance().endContextSwitch(_contextSwitchEvent->NewThreadId, pid, time);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EasyEventTracer::Properties::Properties()
|
||||
{
|
||||
#if UNICODE
|
||||
std::wcstombs(sessionName, KERNEL_LOGGER_NAME, sizeof(sessionName));
|
||||
#else
|
||||
std::strncpy(sessionName, KERNEL_LOGGER_NAME, sizeof(sessionName));
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASY_MAGIC_STATIC_AVAILABLE
|
||||
class EasyEventTracerInstance {
|
||||
friend EasyEventTracer;
|
||||
EasyEventTracer instance;
|
||||
} EASY_EVENT_TRACER;
|
||||
#endif
|
||||
|
||||
EasyEventTracer& EasyEventTracer::instance()
|
||||
{
|
||||
#ifndef EASY_MAGIC_STATIC_AVAILABLE
|
||||
return EASY_EVENT_TRACER.instance;
|
||||
#else
|
||||
static EasyEventTracer tracer;
|
||||
return tracer;
|
||||
#endif
|
||||
}
|
||||
|
||||
EasyEventTracer::EasyEventTracer()
|
||||
{
|
||||
m_lowPriority = ATOMIC_VAR_INIT(EASY_OPTION_LOW_PRIORITY_EVENT_TRACING);
|
||||
THREAD_PROCESS_INFO_TABLE[0U] = nullptr;
|
||||
}
|
||||
|
||||
EasyEventTracer::~EasyEventTracer()
|
||||
{
|
||||
disable();
|
||||
}
|
||||
|
||||
bool EasyEventTracer::isLowPriority() const
|
||||
{
|
||||
return m_lowPriority.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void EasyEventTracer::setLowPriority(bool _value)
|
||||
{
|
||||
m_lowPriority.store(_value, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool setPrivilege(HANDLE hToken, PTCHAR _privelegeName)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if (hToken)
|
||||
{
|
||||
LUID privilegyId;
|
||||
if (LookupPrivilegeValue(NULL, _privelegeName, &privilegyId))
|
||||
{
|
||||
TOKEN_PRIVILEGES tokenPrivilege;
|
||||
tokenPrivilege.PrivilegeCount = 1;
|
||||
tokenPrivilege.Privileges[0].Luid = privilegyId;
|
||||
tokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
success = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivilege, sizeof(TOKEN_PRIVILEGES), NULL, NULL) != FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
EASY_LOG_ONLY(
|
||||
if (!success)
|
||||
EASY_WARNING("Failed to set " << _privelegeName << " privilege for the application.\n");
|
||||
)
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void EasyEventTracer::setProcessPrivileges()
|
||||
{
|
||||
static bool alreadySet = false;
|
||||
if (alreadySet)
|
||||
return;
|
||||
|
||||
alreadySet = true;
|
||||
|
||||
HANDLE hToken = nullptr;
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
{
|
||||
#if EASY_OPTION_LOG_ENABLED != 0
|
||||
const bool success = setPrivilege(hToken, SE_DEBUG_NAME);
|
||||
if (!success)
|
||||
EASY_WARNING("Some context switch events could not get process name.\n");
|
||||
#else
|
||||
setPrivilege(hToken, SE_DEBUG_NAME);
|
||||
#endif
|
||||
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
EASY_LOG_ONLY(
|
||||
else {
|
||||
EASY_WARNING("Failed to open process to adjust privileges.\n");
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
EventTracingEnableStatus EasyEventTracer::startTrace(bool _force, int _step)
|
||||
{
|
||||
using Status = EventTracingEnableStatus;
|
||||
|
||||
auto startTraceResult = StartTrace(&m_sessionHandle, KERNEL_LOGGER_NAME, props());
|
||||
switch (startTraceResult)
|
||||
{
|
||||
case ERROR_SUCCESS:
|
||||
return Status::LaunchedSuccessfully;
|
||||
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
{
|
||||
if (_force)
|
||||
{
|
||||
// Try to stop another event tracing session to force launch self session.
|
||||
|
||||
if (_step == 0)
|
||||
{
|
||||
/*
|
||||
According to https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696(v=vs.85).aspx
|
||||
SessionHandle is ignored (and could be NULL) if SessionName is not NULL,
|
||||
and you only need to set the Wnode.BufferSize, Wnode.Guid, LoggerNameOffset, and LogFileNameOffset
|
||||
in EVENT_TRACE_PROPERTIES structure if ControlCode is EVENT_TRACE_CONTROL_STOP.
|
||||
All data is already set for m_properties to the moment. Simply copy m_properties and use the copy.
|
||||
|
||||
This method supposed to be faster than launching console window and executing shell command,
|
||||
but if that would not work, return to using shell command "logman stop".
|
||||
*/
|
||||
|
||||
// static is safe because we are guarded by spin-lock m_spin
|
||||
static Properties p;
|
||||
p.base = m_properties.base; // Use copy of m_properties to make sure m_properties will not be changed
|
||||
|
||||
// Stop another session
|
||||
ControlTrace((TRACEHANDLE)NULL, KERNEL_LOGGER_NAME, reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&p), EVENT_TRACE_CONTROL_STOP);
|
||||
|
||||
// Console window variant:
|
||||
//if (32 >= (int)ShellExecute(NULL, NULL, "logman", "stop \"" KERNEL_LOGGER_NAME "\" -ets", NULL, SW_HIDE))
|
||||
// return Status::AlreadyLaunched;
|
||||
}
|
||||
|
||||
if (_step < 4)
|
||||
{
|
||||
// Command executed successfully. Wait for a few time until tracing session finish.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
return startTrace(true, ++_step);
|
||||
}
|
||||
}
|
||||
|
||||
EASY_ERROR("Event tracing not launched: ERROR_ALREADY_EXISTS. To stop another session execute cmd: logman stop \"" << KERNEL_LOGGER_NAME << "\" -ets\n");
|
||||
return Status::AlreadyLaunched;
|
||||
}
|
||||
|
||||
case ERROR_ACCESS_DENIED:
|
||||
EASY_ERROR("Event tracing not launched: ERROR_ACCESS_DENIED. Try to launch your application as Administrator.\n");
|
||||
return Status::PermissionDenied;
|
||||
|
||||
case ERROR_BAD_LENGTH:
|
||||
EASY_ERROR("Event tracing not launched: ERROR_BAD_LENGTH. It seems that your KERNEL_LOGGER_NAME differs from \"" << m_properties.sessionName << "\". Try to re-compile easy_profiler or contact EasyProfiler developers.\n");
|
||||
return Status::BadPropertiesSize;
|
||||
}
|
||||
|
||||
EASY_ERROR("Event tracing not launched: StartTrace() returned " << startTraceResult << std::endl);
|
||||
|
||||
return Status::UnknownError;
|
||||
}
|
||||
|
||||
EventTracingEnableStatus EasyEventTracer::enable(bool _force)
|
||||
{
|
||||
using Status = EventTracingEnableStatus;
|
||||
|
||||
profiler::guard_lock<profiler::spin_lock> lock(m_spin);
|
||||
if (m_bEnabled)
|
||||
return Status::LaunchedSuccessfully;
|
||||
|
||||
/*
|
||||
Trying to set debug privilege for current process
|
||||
to be able to get other process information (process name).
|
||||
*/
|
||||
EasyEventTracer::setProcessPrivileges();
|
||||
|
||||
// Clear properties
|
||||
memset(&m_properties, 0, sizeof(m_properties));
|
||||
m_properties.base.Wnode.BufferSize = sizeof(m_properties);
|
||||
m_properties.base.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
||||
m_properties.base.Wnode.ClientContext = RAW_TIMESTAMP_TIME_TYPE;
|
||||
m_properties.base.Wnode.Guid = SystemTraceControlGuid;
|
||||
m_properties.base.LoggerNameOffset = sizeof(m_properties.base);
|
||||
m_properties.base.EnableFlags = EVENT_TRACE_FLAG_CSWITCH;
|
||||
m_properties.base.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
||||
|
||||
// Start event tracing
|
||||
const auto res = startTrace(_force);
|
||||
if (res != Status::LaunchedSuccessfully)
|
||||
return res;
|
||||
|
||||
memset(&m_trace, 0, sizeof(m_trace));
|
||||
#ifdef __MINGW32__
|
||||
m_trace.LoggerName = KERNEL_LOGGER;
|
||||
#else
|
||||
m_trace.LoggerName = KERNEL_LOGGER_NAME;
|
||||
#endif
|
||||
m_trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
|
||||
m_trace.EventRecordCallback = easyProcessTraceEvent;
|
||||
|
||||
m_openedHandle = OpenTrace(&m_trace);
|
||||
if (m_openedHandle == INVALID_PROCESSTRACE_HANDLE)
|
||||
{
|
||||
EASY_ERROR("Event tracing not launched: OpenTrace() returned invalid handle.\n");
|
||||
return Status::OpenTraceFailed;
|
||||
}
|
||||
|
||||
/*
|
||||
Have to launch a thread to process events because according to MSDN documentation:
|
||||
|
||||
The ProcessTrace function blocks the thread until it delivers all events, the BufferCallback function returns FALSE,
|
||||
or you call CloseTrace. If the consumer is consuming events in real time, the ProcessTrace function returns after
|
||||
the controller stops the trace session. (Note that there may be a several-second delay before the function returns.)
|
||||
|
||||
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364093(v=vs.85).aspx
|
||||
*/
|
||||
m_processThread = std::thread([this](bool _lowPriority)
|
||||
{
|
||||
if (_lowPriority) // Set low priority for event tracing thread
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
|
||||
EASY_THREAD_SCOPE("EasyProfiler.ETW");
|
||||
ProcessTrace(&m_openedHandle, 1, 0, 0);
|
||||
|
||||
}, m_lowPriority.load(std::memory_order_acquire));
|
||||
|
||||
m_bEnabled = true;
|
||||
|
||||
EASY_LOGMSG("Event tracing launched\n");
|
||||
return Status::LaunchedSuccessfully;
|
||||
}
|
||||
|
||||
void EasyEventTracer::disable()
|
||||
{
|
||||
profiler::guard_lock<profiler::spin_lock> lock(m_spin);
|
||||
if (!m_bEnabled)
|
||||
return;
|
||||
|
||||
EASY_LOGMSG("Event tracing is stopping...\n");
|
||||
|
||||
TRACING_END_TIME.store(profiler::clock::now(), std::memory_order_release);
|
||||
|
||||
ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP);
|
||||
CloseTrace(m_openedHandle);
|
||||
|
||||
// Wait for ProcessTrace to finish to make sure no processTraceEvent() will be called later.
|
||||
if (m_processThread.joinable())
|
||||
m_processThread.join();
|
||||
|
||||
m_bEnabled = false;
|
||||
|
||||
// processTraceEvent() is not called anymore. Clean static maps is safe.
|
||||
PROCESS_INFO_TABLE.clear();
|
||||
THREAD_PROCESS_INFO_TABLE.clear();
|
||||
THREAD_PROCESS_INFO_TABLE[0U] = nullptr;
|
||||
|
||||
TRACING_END_TIME.store(~0ULL, std::memory_order_release);
|
||||
|
||||
EASY_LOGMSG("Event tracing stopped\n");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // _WIN32
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/************************************************************************
|
||||
* file name : event_trace_win.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/09/04
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains declaration of EasyEventTracer class used for tracing
|
||||
* : Windows system events to get context switches.
|
||||
* ----------------- :
|
||||
* change log : * 2016/09/04 Victor Zarubkin: initial commit.
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2019 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_EVENT_TRACE_WINDOWS_H
|
||||
#define EASY_PROFILER_EVENT_TRACE_WINDOWS_H
|
||||
#ifdef _WIN32
|
||||
|
||||
#define INITGUID // This is to enable using SystemTraceControlGuid in evntrace.h.
|
||||
#include <Windows.h>
|
||||
#include <Strsafe.h>
|
||||
#include <wmistr.h>
|
||||
#include <evntrace.h>
|
||||
#include <evntcons.h>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include "event_trace_status.h"
|
||||
#include "spin_lock.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EasyEventTracer EASY_FINAL
|
||||
{
|
||||
#ifndef EASY_MAGIC_STATIC_AVAILABLE
|
||||
friend class EasyEventTracerInstance;
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Properties {
|
||||
Properties();
|
||||
|
||||
EVENT_TRACE_PROPERTIES base;
|
||||
char sessionName[sizeof(KERNEL_LOGGER_NAME)];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::thread m_processThread;
|
||||
Properties m_properties;
|
||||
EVENT_TRACE_LOGFILE m_trace;
|
||||
profiler::spin_lock m_spin;
|
||||
std::atomic_bool m_lowPriority;
|
||||
TRACEHANDLE m_sessionHandle = INVALID_PROCESSTRACE_HANDLE;
|
||||
TRACEHANDLE m_openedHandle = INVALID_PROCESSTRACE_HANDLE;
|
||||
bool m_bEnabled = false;
|
||||
|
||||
public:
|
||||
|
||||
static EasyEventTracer& instance();
|
||||
~EasyEventTracer();
|
||||
|
||||
bool isLowPriority() const;
|
||||
|
||||
EventTracingEnableStatus enable(bool _force = false);
|
||||
void disable();
|
||||
void setLowPriority(bool _value);
|
||||
static void setProcessPrivileges();
|
||||
|
||||
private:
|
||||
|
||||
EasyEventTracer();
|
||||
|
||||
inline EVENT_TRACE_PROPERTIES* props()
|
||||
{
|
||||
return reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&m_properties);
|
||||
}
|
||||
|
||||
EventTracingEnableStatus startTrace(bool _force, int _step = 0);
|
||||
|
||||
}; // END of class EasyEventTracer.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // EASY_PROFILER_EVENT_TRACE_WINDOWS_H
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
/************************************************************************
|
||||
* file name : hashed_str.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/09/11
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains definition of C-strings with calculated hash-code.
|
||||
* : These strings may be used as optimized keys for std::unordered_map.
|
||||
* ----------------- :
|
||||
* change log : * 2016/09/11 Victor Zarubkin: Initial commit. Moved sources from reader.cpp
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2019 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__HASHED_CSTR__H_
|
||||
#define EASY_PROFILER__HASHED_CSTR__H_
|
||||
|
||||
#include <functional>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace profiler {
|
||||
|
||||
class hashed_stdstring
|
||||
{
|
||||
::std::string m_str;
|
||||
size_t m_hash;
|
||||
|
||||
public:
|
||||
|
||||
hashed_stdstring(const char* _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
|
||||
{
|
||||
}
|
||||
|
||||
hashed_stdstring(const ::std::string& _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
|
||||
{
|
||||
}
|
||||
|
||||
hashed_stdstring(::std::string&& _str) : m_str(::std::forward<::std::string&&>(_str)), m_hash(::std::hash<::std::string>()(m_str))
|
||||
{
|
||||
}
|
||||
|
||||
hashed_stdstring(hashed_stdstring&& _other) : m_str(::std::move(_other.m_str)), m_hash(_other.m_hash)
|
||||
{
|
||||
}
|
||||
|
||||
hashed_stdstring(const char* _str, size_t _hash_code) : m_str(_str), m_hash(_hash_code)
|
||||
{
|
||||
}
|
||||
|
||||
hashed_stdstring(const ::std::string& _str, size_t _hash_code) : m_str(_str), m_hash(_hash_code)
|
||||
{
|
||||
}
|
||||
|
||||
hashed_stdstring(::std::string&& _str, size_t _hash_code) : m_str(::std::forward<::std::string&&>(_str)), m_hash(_hash_code)
|
||||
{
|
||||
}
|
||||
|
||||
hashed_stdstring(const hashed_stdstring&) = default;
|
||||
hashed_stdstring& operator = (const hashed_stdstring&) = default;
|
||||
|
||||
hashed_stdstring& operator = (hashed_stdstring&& _other)
|
||||
{
|
||||
m_str = ::std::move(_other.m_str);
|
||||
m_hash = _other.m_hash;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator == (const hashed_stdstring& _other) const
|
||||
{
|
||||
return m_hash == _other.m_hash && m_str == _other.m_str;
|
||||
}
|
||||
|
||||
inline bool operator != (const hashed_stdstring& _other) const
|
||||
{
|
||||
return !operator == (_other);
|
||||
}
|
||||
|
||||
inline size_t hcode() const
|
||||
{
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
inline const char* c_str() const
|
||||
{
|
||||
return m_str.c_str();
|
||||
}
|
||||
|
||||
inline size_t size() const
|
||||
{
|
||||
return m_str.size();
|
||||
}
|
||||
|
||||
}; // END of class hashed_stdstring.
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
namespace std {
|
||||
|
||||
/** \brief Simply returns precalculated hash of a std::string. */
|
||||
template <> struct hash<::profiler::hashed_stdstring> {
|
||||
typedef ::profiler::hashed_stdstring argument_type;
|
||||
typedef size_t result_type;
|
||||
inline size_t operator () (const ::profiler::hashed_stdstring& _str) const {
|
||||
return _str.hcode();
|
||||
}
|
||||
};
|
||||
|
||||
} // END of namespace std.
|
||||
|
||||
#if 0 == 1 //defined(_MSC_VER)// && _MSC_VER >= 1800
|
||||
# define EASY_PROFILER_HASHED_CSTR_DEFINED
|
||||
|
||||
namespace profiler {
|
||||
|
||||
/** \brief Simple C-string pointer with length.
|
||||
|
||||
It is used as base class for a key in std::unordered_map.
|
||||
It is used to get better performance than std::string.
|
||||
It simply stores a pointer and a length, there is no
|
||||
any memory allocation and copy.
|
||||
|
||||
\warning Make sure you know what you are doing. You have to be sure that
|
||||
pointed C-string will exist until you finish using this cstring.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
class cstring
|
||||
{
|
||||
protected:
|
||||
|
||||
const char* m_str;
|
||||
size_t m_len;
|
||||
|
||||
public:
|
||||
|
||||
cstring(const char* _str) : m_str(_str), m_len(strlen(_str))
|
||||
{
|
||||
}
|
||||
|
||||
cstring(const char* _str, size_t _len) : m_str(_str), m_len(_len)
|
||||
{
|
||||
}
|
||||
|
||||
cstring(const cstring&) = default;
|
||||
cstring& operator = (const cstring&) = default;
|
||||
|
||||
inline bool operator == (const cstring& _other) const
|
||||
{
|
||||
return m_len == _other.m_len && !strncmp(m_str, _other.m_str, m_len);
|
||||
}
|
||||
|
||||
inline bool operator != (const cstring& _other) const
|
||||
{
|
||||
return !operator == (_other);
|
||||
}
|
||||
|
||||
inline bool operator < (const cstring& _other) const
|
||||
{
|
||||
if (m_len == _other.m_len)
|
||||
{
|
||||
return strncmp(m_str, _other.m_str, m_len) < 0;
|
||||
}
|
||||
|
||||
return m_len < _other.m_len;
|
||||
}
|
||||
|
||||
inline const char* c_str() const
|
||||
{
|
||||
return m_str;
|
||||
}
|
||||
|
||||
inline size_t size() const
|
||||
{
|
||||
return m_len;
|
||||
}
|
||||
|
||||
}; // END of class cstring.
|
||||
|
||||
/** \brief cstring with precalculated hash.
|
||||
|
||||
This is used to calculate hash for C-string and to cache it
|
||||
to be used in the future without recurring hash calculatoin.
|
||||
|
||||
\note This class is used as a key in std::unordered_map.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
class hashed_cstr : public cstring
|
||||
{
|
||||
using Parent = cstring;
|
||||
|
||||
size_t m_hash;
|
||||
|
||||
public:
|
||||
|
||||
hashed_cstr(const char* _str) : Parent(_str), m_hash(0)
|
||||
{
|
||||
m_hash = ::std::_Hash_seq((const unsigned char *)m_str, m_len);
|
||||
}
|
||||
|
||||
hashed_cstr(const char* _str, size_t _hash_code) : Parent(_str), m_hash(_hash_code)
|
||||
{
|
||||
}
|
||||
|
||||
hashed_cstr(const char* _str, size_t _len, size_t _hash_code) : Parent(_str, _len), m_hash(_hash_code)
|
||||
{
|
||||
}
|
||||
|
||||
hashed_cstr(const hashed_cstr&) = default;
|
||||
hashed_cstr& operator = (const hashed_cstr&) = default;
|
||||
|
||||
inline bool operator == (const hashed_cstr& _other) const
|
||||
{
|
||||
return m_hash == _other.m_hash && Parent::operator == (_other);
|
||||
}
|
||||
|
||||
inline bool operator != (const hashed_cstr& _other) const
|
||||
{
|
||||
return !operator == (_other);
|
||||
}
|
||||
|
||||
inline size_t hcode() const
|
||||
{
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
}; // END of class hashed_cstr.
|
||||
|
||||
using string_with_hash = hashed_cstr;
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
namespace std {
|
||||
|
||||
/** \brief Simply returns precalculated hash of a C-string. */
|
||||
template <> struct hash<::profiler::hashed_cstr>
|
||||
{
|
||||
using argument_type = ::profiler::hashed_cstr;
|
||||
using result_type = size_t;
|
||||
|
||||
inline size_t operator () (const ::profiler::hashed_cstr& _str) const
|
||||
{
|
||||
return _str.hcode();
|
||||
}
|
||||
};
|
||||
|
||||
} // END of namespace std.
|
||||
|
||||
#else ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO: Create hashed_cstr for Linux (need to use Linux version of std::_Hash_seq)
|
||||
|
||||
namespace profiler {
|
||||
using string_with_hash = hashed_stdstring;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER__HASHED_CSTR__H_
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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.
|
||||
|
||||
**/
|
||||
|
||||
#include "nonscoped_block.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
NonscopedBlock::NonscopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, bool)
|
||||
: profiler::Block(_desc, _runtimeName, false), m_runtimeName(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NonscopedBlock::~NonscopedBlock()
|
||||
{
|
||||
// Actually destructor should not be invoked because StackBuffer do manual memory management
|
||||
|
||||
m_end = m_begin; // to restrict profiler::Block to invoke profiler::endBlock() on destructor.
|
||||
free(m_runtimeName);
|
||||
}
|
||||
|
||||
void NonscopedBlock::copyname()
|
||||
{
|
||||
// Here we need to copy m_name to m_runtimeName to ensure that
|
||||
// it would be alive to the moment we will serialize the block
|
||||
|
||||
if ((m_status & profiler::ON) == 0)
|
||||
return;
|
||||
|
||||
if (*m_name != 0)
|
||||
{
|
||||
auto len = strlen(m_name);
|
||||
m_runtimeName = static_cast<char*>(malloc(len + 1));
|
||||
|
||||
// memcpy should be faster than strncpy because we know
|
||||
// actual bytes number and both strings have the same size
|
||||
memcpy(m_runtimeName, m_name, len);
|
||||
|
||||
m_runtimeName[len] = 0;
|
||||
m_name = m_runtimeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_name = "";
|
||||
}
|
||||
}
|
||||
|
||||
void NonscopedBlock::destroy()
|
||||
{
|
||||
// free memory used by m_runtimeName
|
||||
free(m_runtimeName);
|
||||
m_name = "";
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_NONSCOPED_BLOCK_H
|
||||
#define EASY_PROFILER_NONSCOPED_BLOCK_H
|
||||
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
|
||||
class NonscopedBlock : public profiler::Block
|
||||
{
|
||||
char* m_runtimeName; ///< A copy of _runtimeName to make it safe to begin block in one function and end it in another
|
||||
|
||||
public:
|
||||
|
||||
NonscopedBlock() = delete;
|
||||
NonscopedBlock(const NonscopedBlock&) = delete;
|
||||
NonscopedBlock(NonscopedBlock&&) = delete;
|
||||
NonscopedBlock& operator = (const NonscopedBlock&) = delete;
|
||||
NonscopedBlock& operator = (NonscopedBlock&&) = delete;
|
||||
|
||||
NonscopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, bool = false);
|
||||
~NonscopedBlock();
|
||||
|
||||
/** Copy string from m_name to m_runtimeName to make it safe to end block in another function.
|
||||
|
||||
Performs any work if block is ON and m_name != ""
|
||||
*/
|
||||
void copyname();
|
||||
|
||||
void destroy();
|
||||
|
||||
}; // END of class NonscopedBlock.
|
||||
|
||||
#endif // EASY_PROFILER_NONSCOPED_BLOCK_H
|
||||
+1698
File diff suppressed because it is too large
Load Diff
+226
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_MANAGER_H
|
||||
#define EASY_PROFILER_MANAGER_H
|
||||
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
// Do not move this include to other place!
|
||||
// It should be included before Windows.h which is included in spin_lock.h
|
||||
# include <easy/easy_socket.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include "spin_lock.h"
|
||||
#include "hashed_cstr.h"
|
||||
#include "thread_storage.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <unordered_map>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using processid_t = uint64_t;
|
||||
|
||||
class BlockDescriptor;
|
||||
|
||||
namespace profiler {
|
||||
class ValueId;
|
||||
}
|
||||
|
||||
class ProfileManager
|
||||
{
|
||||
#ifndef EASY_MAGIC_STATIC_AVAILABLE
|
||||
friend class ProfileManagerInstance;
|
||||
#endif
|
||||
|
||||
ProfileManager();
|
||||
|
||||
using atomic_timestamp_t = std::atomic<profiler::timestamp_t>;
|
||||
using guard_lock_t = profiler::guard_lock<profiler::spin_lock>;
|
||||
using map_of_threads_stacks = std::map<profiler::thread_id_t, ThreadStorage>;
|
||||
using block_descriptors_t = std::vector<BlockDescriptor*>;
|
||||
using descriptors_map_t = std::unordered_map<profiler::string_with_hash, profiler::block_id_t>;
|
||||
|
||||
const processid_t m_processId;
|
||||
|
||||
#if defined(EASY_CHRONO_CLOCK) || defined(_WIN32)
|
||||
const int64_t m_cpuFrequency;
|
||||
#endif
|
||||
|
||||
map_of_threads_stacks m_threads;
|
||||
block_descriptors_t m_descriptors;
|
||||
descriptors_map_t m_descriptorsMap;
|
||||
uint64_t m_descriptorsMemorySize;
|
||||
|
||||
#if !defined(EASY_CHRONO_CLOCK) && !defined(_WIN32)
|
||||
std::atomic<int64_t> m_cpuFrequency;
|
||||
#endif
|
||||
|
||||
profiler::timestamp_t m_beginTime;
|
||||
profiler::timestamp_t m_endTime;
|
||||
atomic_timestamp_t m_frameMax;
|
||||
atomic_timestamp_t m_frameAvg;
|
||||
atomic_timestamp_t m_frameCur;
|
||||
profiler::spin_lock m_spin;
|
||||
profiler::spin_lock m_storedSpin;
|
||||
profiler::spin_lock m_dumpSpin;
|
||||
std::atomic<profiler::thread_id_t> m_mainThreadId;
|
||||
std::atomic_bool m_profilerStatus;
|
||||
std::atomic_bool m_isEventTracingEnabled;
|
||||
std::atomic_bool m_isAlreadyListening;
|
||||
std::atomic_bool m_frameMaxReset;
|
||||
std::atomic_bool m_frameAvgReset;
|
||||
std::atomic_bool m_stopDumping;
|
||||
|
||||
std::string m_csInfoFilename = "/tmp/cs_profiling_info.log";
|
||||
|
||||
std::thread m_listenThread;
|
||||
std::atomic_bool m_stopListen;
|
||||
|
||||
public:
|
||||
|
||||
ProfileManager(const ProfileManager&) = delete;
|
||||
ProfileManager(ProfileManager&&) = delete;
|
||||
ProfileManager& operator = (const ProfileManager&) = delete;
|
||||
ProfileManager& operator = (ProfileManager&&) = delete;
|
||||
|
||||
static ProfileManager& instance();
|
||||
~ProfileManager();
|
||||
|
||||
const profiler::BaseBlockDescriptor* addBlockDescriptor(profiler::EasyBlockStatus _defaultStatus,
|
||||
const char* _autogenUniqueId,
|
||||
const char* _name,
|
||||
const char* _filename,
|
||||
int _line,
|
||||
profiler::block_type_t _block_type,
|
||||
profiler::color_t _color,
|
||||
bool _copyName = false);
|
||||
|
||||
void storeValue(const profiler::BaseBlockDescriptor* _desc, profiler::DataType _type, const void* _data, uint16_t _size, bool _isArray, profiler::ValueId _vin);
|
||||
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
|
||||
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime);
|
||||
void beginBlock(profiler::Block& _block);
|
||||
void beginNonScopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
|
||||
void endBlock();
|
||||
|
||||
profiler::timestamp_t maxFrameDuration();
|
||||
profiler::timestamp_t avgFrameDuration();
|
||||
profiler::timestamp_t curFrameDuration() const;
|
||||
|
||||
void setEnabled(bool isEnable);
|
||||
EASY_FORCE_INLINE bool isEnabled() const {
|
||||
return m_profilerStatus.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void setEventTracingEnabled(bool _isEnable);
|
||||
bool isEventTracingEnabled() const;
|
||||
uint32_t dumpBlocksToFile(const char* filename);
|
||||
const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard);
|
||||
const char* registerThread(const char* name);
|
||||
|
||||
void setContextSwitchLogFilename(const char* name);
|
||||
const char* getContextSwitchLogFilename() const;
|
||||
|
||||
void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, const char* _target_process, bool _lockSpin = true);
|
||||
void endContextSwitch(profiler::thread_id_t _thread_id, processid_t _process_id, profiler::timestamp_t _endtime, bool _lockSpin = true);
|
||||
void startListen(uint16_t _port);
|
||||
void stopListen();
|
||||
bool isListening() const;
|
||||
|
||||
profiler::timestamp_t ticks2ns(profiler::timestamp_t ticks) const;
|
||||
profiler::timestamp_t ticks2us(profiler::timestamp_t ticks) const;
|
||||
|
||||
static bool isMainThread();
|
||||
static profiler::timestamp_t this_thread_frameTime(profiler::Duration _durationCast);
|
||||
static profiler::timestamp_t this_thread_frameTimeLocalMax(profiler::Duration _durationCast);
|
||||
static profiler::timestamp_t this_thread_frameTimeLocalAvg(profiler::Duration _durationCast);
|
||||
static profiler::timestamp_t main_thread_frameTime(profiler::Duration _durationCast);
|
||||
static profiler::timestamp_t main_thread_frameTimeLocalMax(profiler::Duration _durationCast);
|
||||
static profiler::timestamp_t main_thread_frameTimeLocalAvg(profiler::Duration _durationCast);
|
||||
|
||||
private:
|
||||
|
||||
void listen(uint16_t _port);
|
||||
|
||||
uint32_t dumpBlocksToStream(std::ostream& _outputStream, bool _lockSpin, bool _async);
|
||||
void setBlockStatus(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
|
||||
|
||||
void registerThread();
|
||||
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
|
||||
void enableEventTracer();
|
||||
void disableEventTracer();
|
||||
|
||||
static char checkThreadExpired(ThreadStorage& _registeredThread);
|
||||
|
||||
void storeBlockForce(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t& _timestamp);
|
||||
void storeBlockForce2(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
|
||||
|
||||
ThreadStorage& _threadStorage(profiler::thread_id_t _thread_id);
|
||||
ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id);
|
||||
|
||||
ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
|
||||
{
|
||||
guard_lock_t lock(m_spin);
|
||||
return _threadStorage(_thread_id);
|
||||
}
|
||||
|
||||
ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
|
||||
{
|
||||
guard_lock_t lock(m_spin);
|
||||
return _findThreadStorage(_thread_id);
|
||||
}
|
||||
|
||||
}; // END of class ProfileManager.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER_MANAGER_H
|
||||
+349
@@ -0,0 +1,349 @@
|
||||
/************************************************************************
|
||||
* file name : profiler.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2018/05/06
|
||||
* authors : Sergey Yagovtsev, Victor Zarubkin
|
||||
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of Profile manager and implement access c-function
|
||||
* :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2019 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.
|
||||
************************************************************************/
|
||||
|
||||
#include <easy/profiler.h>
|
||||
#include <easy/arbitrary_value.h>
|
||||
#include "profile_manager.h"
|
||||
#include "event_trace_win.h"
|
||||
#include "current_time.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BUILD_WITH_EASY_PROFILER
|
||||
# ifndef EASY_PROFILER_API_DISABLED
|
||||
# define EASY_PROFILER_API_DISABLED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(EASY_PROFILER_VERSION_MAJOR) || !defined(EASY_PROFILER_VERSION_MINOR) || !defined(EASY_PROFILER_VERSION_PATCH)
|
||||
# ifdef _WIN32
|
||||
# error EASY_PROFILER_VERSION_MAJOR and EASY_PROFILER_VERSION_MINOR and EASY_PROFILER_VERSION_PATCH macros must be defined
|
||||
# else
|
||||
# error "EASY_PROFILER_VERSION_MAJOR and EASY_PROFILER_VERSION_MINOR and EASY_PROFILER_VERSION_PATCH macros must be defined"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define EASY_PROFILER_PRODUCT_VERSION "v" EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MAJOR) "." \
|
||||
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MINOR) "." \
|
||||
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_PATCH)
|
||||
|
||||
extern const uint32_t EASY_PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8) | 'y';
|
||||
extern const uint32_t EASY_PROFILER_VERSION = (static_cast<uint32_t>(EASY_PROFILER_VERSION_MAJOR) << 24) |
|
||||
(static_cast<uint32_t>(EASY_PROFILER_VERSION_MINOR) << 16) |
|
||||
static_cast<uint32_t>(EASY_PROFILER_VERSION_PATCH);
|
||||
|
||||
#undef EASY_VERSION_INT
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" {
|
||||
|
||||
PROFILER_API uint8_t versionMajor()
|
||||
{
|
||||
static_assert(0 <= EASY_PROFILER_VERSION_MAJOR && EASY_PROFILER_VERSION_MAJOR <= 255,
|
||||
"EASY_PROFILER_VERSION_MAJOR must be defined in range [0, 255]");
|
||||
|
||||
return EASY_PROFILER_VERSION_MAJOR;
|
||||
}
|
||||
|
||||
PROFILER_API uint8_t versionMinor()
|
||||
{
|
||||
static_assert(0 <= EASY_PROFILER_VERSION_MINOR && EASY_PROFILER_VERSION_MINOR <= 255,
|
||||
"EASY_PROFILER_VERSION_MINOR must be defined in range [0, 255]");
|
||||
|
||||
return EASY_PROFILER_VERSION_MINOR;
|
||||
}
|
||||
|
||||
PROFILER_API uint16_t versionPatch()
|
||||
{
|
||||
static_assert(0 <= EASY_PROFILER_VERSION_PATCH && EASY_PROFILER_VERSION_PATCH <= 65535,
|
||||
"EASY_PROFILER_VERSION_PATCH must be defined in range [0, 65535]");
|
||||
|
||||
return EASY_PROFILER_VERSION_PATCH;
|
||||
}
|
||||
|
||||
PROFILER_API uint32_t version()
|
||||
{
|
||||
return EASY_PROFILER_VERSION;
|
||||
}
|
||||
|
||||
PROFILER_API const char* versionName()
|
||||
{
|
||||
#ifdef EASY_PROFILER_API_DISABLED
|
||||
return EASY_PROFILER_PRODUCT_VERSION "_disabled";
|
||||
#else
|
||||
return EASY_PROFILER_PRODUCT_VERSION;
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(EASY_PROFILER_API_DISABLED)
|
||||
|
||||
PROFILER_API profiler::timestamp_t now()
|
||||
{
|
||||
return profiler::clock::now();
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t toNanoseconds(profiler::timestamp_t _ticks)
|
||||
{
|
||||
return ProfileManager::instance().ticks2ns(_ticks);
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t toMicroseconds(profiler::timestamp_t _ticks)
|
||||
{
|
||||
return ProfileManager::instance().ticks2us(_ticks);
|
||||
}
|
||||
|
||||
PROFILER_API const profiler::BaseBlockDescriptor*
|
||||
registerDescription(profiler::EasyBlockStatus _status, const char* _autogenUniqueId, const char* _name,
|
||||
const char* _filename, int _line, profiler::block_type_t _block_type, profiler::color_t _color,
|
||||
bool _copyName)
|
||||
{
|
||||
return ProfileManager::instance().addBlockDescriptor(_status, _autogenUniqueId, _name, _filename, _line,
|
||||
_block_type, _color, _copyName);
|
||||
}
|
||||
|
||||
PROFILER_API void endBlock()
|
||||
{
|
||||
ProfileManager::instance().endBlock();
|
||||
}
|
||||
|
||||
PROFILER_API void setEnabled(bool isEnable)
|
||||
{
|
||||
ProfileManager::instance().setEnabled(isEnable);
|
||||
}
|
||||
|
||||
PROFILER_API bool isEnabled()
|
||||
{
|
||||
return ProfileManager::instance().isEnabled();
|
||||
}
|
||||
|
||||
PROFILER_API void storeValue(const profiler::BaseBlockDescriptor* _desc, profiler::DataType _type, const void* _data,
|
||||
uint16_t _size, bool _isArray, profiler::ValueId _vin)
|
||||
{
|
||||
ProfileManager::instance().storeValue(_desc, _type, _data, _size, _isArray, _vin);
|
||||
}
|
||||
|
||||
PROFILER_API void storeEvent(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
|
||||
{
|
||||
ProfileManager::instance().storeBlock(_desc, _runtimeName);
|
||||
}
|
||||
|
||||
PROFILER_API void storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName,
|
||||
profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime)
|
||||
{
|
||||
ProfileManager::instance().storeBlock(_desc, _runtimeName, _beginTime, _endTime);
|
||||
}
|
||||
|
||||
PROFILER_API void beginBlock(profiler::Block& _block)
|
||||
{
|
||||
ProfileManager::instance().beginBlock(_block);
|
||||
}
|
||||
|
||||
PROFILER_API void beginNonScopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
|
||||
{
|
||||
ProfileManager::instance().beginNonScopedBlock(_desc, _runtimeName);
|
||||
}
|
||||
|
||||
PROFILER_API uint32_t dumpBlocksToFile(const char* filename)
|
||||
{
|
||||
return ProfileManager::instance().dumpBlocksToFile(filename);
|
||||
}
|
||||
|
||||
PROFILER_API const char* registerThreadScoped(const char* name, profiler::ThreadGuard& threadGuard)
|
||||
{
|
||||
return ProfileManager::instance().registerThread(name, threadGuard);
|
||||
}
|
||||
|
||||
PROFILER_API const char* registerThread(const char* name)
|
||||
{
|
||||
return ProfileManager::instance().registerThread(name);
|
||||
}
|
||||
|
||||
PROFILER_API void setEventTracingEnabled(bool _isEnable)
|
||||
{
|
||||
ProfileManager::instance().setEventTracingEnabled(_isEnable);
|
||||
}
|
||||
|
||||
PROFILER_API bool isEventTracingEnabled()
|
||||
{
|
||||
return ProfileManager::instance().isEventTracingEnabled();
|
||||
}
|
||||
|
||||
# ifdef _WIN32
|
||||
PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority)
|
||||
{
|
||||
EasyEventTracer::instance().setLowPriority(_isLowPriority);
|
||||
}
|
||||
|
||||
PROFILER_API bool isLowPriorityEventTracing()
|
||||
{
|
||||
return EasyEventTracer::instance().isLowPriority();
|
||||
}
|
||||
# else
|
||||
PROFILER_API void setLowPriorityEventTracing(bool) { }
|
||||
PROFILER_API bool isLowPriorityEventTracing() { return false; }
|
||||
# endif
|
||||
|
||||
PROFILER_API void setContextSwitchLogFilename(const char* name)
|
||||
{
|
||||
return ProfileManager::instance().setContextSwitchLogFilename(name);
|
||||
}
|
||||
|
||||
PROFILER_API const char* getContextSwitchLogFilename()
|
||||
{
|
||||
return ProfileManager::instance().getContextSwitchLogFilename();
|
||||
}
|
||||
|
||||
PROFILER_API void startListen(uint16_t _port)
|
||||
{
|
||||
return ProfileManager::instance().startListen(_port);
|
||||
}
|
||||
|
||||
PROFILER_API void stopListen()
|
||||
{
|
||||
return ProfileManager::instance().stopListen();
|
||||
}
|
||||
|
||||
PROFILER_API bool isListening()
|
||||
{
|
||||
return ProfileManager::instance().isListening();
|
||||
}
|
||||
|
||||
PROFILER_API bool isMainThread()
|
||||
{
|
||||
return ProfileManager::isMainThread();
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t this_thread_frameTime(profiler::Duration _durationCast)
|
||||
{
|
||||
return ProfileManager::this_thread_frameTime(_durationCast);
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalMax(profiler::Duration _durationCast)
|
||||
{
|
||||
return ProfileManager::this_thread_frameTimeLocalMax(_durationCast);
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalAvg(profiler::Duration _durationCast)
|
||||
{
|
||||
return ProfileManager::this_thread_frameTimeLocalAvg(_durationCast);
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t main_thread_frameTime(profiler::Duration _durationCast)
|
||||
{
|
||||
return ProfileManager::main_thread_frameTime(_durationCast);
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalMax(profiler::Duration _durationCast)
|
||||
{
|
||||
return ProfileManager::main_thread_frameTimeLocalMax(_durationCast);
|
||||
}
|
||||
|
||||
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalAvg(profiler::Duration _durationCast)
|
||||
{
|
||||
return ProfileManager::main_thread_frameTimeLocalAvg(_durationCast);
|
||||
}
|
||||
|
||||
#else // EASY_PROFILER_API_DISABLED
|
||||
|
||||
PROFILER_API profiler::timestamp_t now() { return 0; }
|
||||
PROFILER_API profiler::timestamp_t toNanoseconds(profiler::timestamp_t) { return 0; }
|
||||
PROFILER_API profiler::timestamp_t toMicroseconds(profiler::timestamp_t) { return 0; }
|
||||
|
||||
PROFILER_API const profiler::BaseBlockDescriptor* registerDescription(profiler::EasyBlockStatus, const char*,
|
||||
const char*, const char*, int,
|
||||
profiler::block_type_t, profiler::color_t, bool)
|
||||
{
|
||||
return reinterpret_cast<const profiler::BaseBlockDescriptor*>(0xbad);
|
||||
}
|
||||
|
||||
PROFILER_API void endBlock() { }
|
||||
PROFILER_API void setEnabled(bool) { }
|
||||
PROFILER_API bool isEnabled() { return false; }
|
||||
|
||||
PROFILER_API void storeValue(const profiler::BaseBlockDescriptor*, profiler::DataType, const void*, uint16_t, bool,
|
||||
profiler::ValueId)
|
||||
{
|
||||
}
|
||||
|
||||
PROFILER_API void storeEvent(const profiler::BaseBlockDescriptor*, const char*) { }
|
||||
PROFILER_API void storeBlock(const profiler::BaseBlockDescriptor*, const char*, profiler::timestamp_t,
|
||||
profiler::timestamp_t)
|
||||
{
|
||||
}
|
||||
|
||||
PROFILER_API void beginBlock(profiler::Block&) { }
|
||||
PROFILER_API void beginNonScopedBlock(const profiler::BaseBlockDescriptor*, const char*) { }
|
||||
PROFILER_API uint32_t dumpBlocksToFile(const char*) { return 0; }
|
||||
PROFILER_API const char* registerThreadScoped(const char*, profiler::ThreadGuard&) { return ""; }
|
||||
PROFILER_API const char* registerThread(const char*) { return ""; }
|
||||
PROFILER_API void setEventTracingEnabled(bool) { }
|
||||
PROFILER_API bool isEventTracingEnabled() { return false; }
|
||||
PROFILER_API void setLowPriorityEventTracing(bool) { }
|
||||
PROFILER_API bool isLowPriorityEventTracing(bool) { return false; }
|
||||
PROFILER_API void setContextSwitchLogFilename(const char*) { }
|
||||
PROFILER_API const char* getContextSwitchLogFilename() { return ""; }
|
||||
PROFILER_API void startListen(uint16_t) { }
|
||||
PROFILER_API void stopListen() { }
|
||||
PROFILER_API bool isListening() { return false; }
|
||||
|
||||
PROFILER_API bool isMainThread() { return false; }
|
||||
PROFILER_API profiler::timestamp_t this_thread_frameTime(profiler::Duration) { return 0; }
|
||||
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalMax(profiler::Duration) { return 0; }
|
||||
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalAvg(profiler::Duration) { return 0; }
|
||||
PROFILER_API profiler::timestamp_t main_thread_frameTime(profiler::Duration) { return 0; }
|
||||
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalMax(profiler::Duration) { return 0; }
|
||||
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalAvg(profiler::Duration) { return 0; }
|
||||
|
||||
#endif // EASY_PROFILER_API_DISABLED
|
||||
|
||||
} // end extern "C".
|
||||
+1561
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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.
|
||||
|
||||
**/
|
||||
|
||||
#include <string.h>
|
||||
#include <easy/serialized_block.h>
|
||||
#include "thread_storage.h"
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
|
||||
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
|
||||
: BaseBlockData(block)
|
||||
{
|
||||
char* pName = const_cast<char*>(name());
|
||||
if (name_length != 0)
|
||||
strncpy(pName, block.name(), name_length);
|
||||
pName[name_length] = 0;
|
||||
}
|
||||
|
||||
SerializedCSwitch::SerializedCSwitch(const CSwitchBlock& block, uint16_t name_length)
|
||||
: CSwitchEvent(block)
|
||||
{
|
||||
char* pName = const_cast<char*>(name());
|
||||
if (name_length != 0)
|
||||
strncpy(pName, block.name(), name_length);
|
||||
pName[name_length] = 0;
|
||||
}
|
||||
|
||||
} // end of namespace profiler.
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_SPIN_LOCK_H
|
||||
#define EASY_PROFILER_SPIN_LOCK_H
|
||||
|
||||
#define EASY_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag
|
||||
|
||||
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
namespace profiler {
|
||||
|
||||
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
|
||||
// std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag...
|
||||
// By the way, Windows critical sections are slower than std::atomic_flag on Unix.
|
||||
class spin_lock { CRITICAL_SECTION m_lock; public:
|
||||
|
||||
void lock() {
|
||||
EnterCriticalSection(&m_lock);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
LeaveCriticalSection(&m_lock);
|
||||
}
|
||||
|
||||
spin_lock() {
|
||||
InitializeCriticalSection(&m_lock);
|
||||
}
|
||||
|
||||
~spin_lock() {
|
||||
DeleteCriticalSection(&m_lock);
|
||||
}
|
||||
};
|
||||
#else
|
||||
// std::atomic_flag on Unix works fine and very fast (almost instant!)
|
||||
class spin_lock { ::std::atomic_flag m_lock; public:
|
||||
|
||||
void lock() {
|
||||
while (m_lock.test_and_set(::std::memory_order_acquire));
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
m_lock.clear(::std::memory_order_release);
|
||||
}
|
||||
|
||||
spin_lock() {
|
||||
m_lock.clear();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
class guard_lock
|
||||
{
|
||||
T& m_lock;
|
||||
bool m_isLocked = false;
|
||||
|
||||
public:
|
||||
|
||||
explicit guard_lock(T& m) : m_lock(m) {
|
||||
m_lock.lock();
|
||||
m_isLocked = true;
|
||||
}
|
||||
|
||||
~guard_lock() {
|
||||
unlock();
|
||||
}
|
||||
|
||||
inline void unlock() {
|
||||
if (m_isLocked) {
|
||||
m_lock.unlock();
|
||||
m_isLocked = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
#ifdef EASY_USE_CRITICAL_SECTION
|
||||
# undef EASY_USE_CRITICAL_SECTION
|
||||
#endif
|
||||
|
||||
#endif // EASY_PROFILER_SPIN_LOCK_H
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_STACK_BUFFER_H
|
||||
#define EASY_PROFILER_STACK_BUFFER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
|
||||
#include "nonscoped_block.h"
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline void destroy_elem(T*)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline void destroy_elem(NonscopedBlock* _elem)
|
||||
{
|
||||
_elem->destroy();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class StackBuffer
|
||||
{
|
||||
struct chunk { int8_t data[sizeof(T)]; };
|
||||
|
||||
std::list<chunk> m_overflow; ///< List of additional stack elements if current capacity of buffer is not enough
|
||||
T* m_buffer; ///< Contiguous buffer used for stack
|
||||
uint32_t m_size; ///< Current size of stack
|
||||
uint32_t m_capacity; ///< Current capacity of m_buffer
|
||||
uint32_t m_maxcapacity; ///< Maximum used capacity including m_buffer and m_overflow
|
||||
|
||||
public:
|
||||
|
||||
StackBuffer() = delete;
|
||||
StackBuffer(const StackBuffer&) = delete;
|
||||
StackBuffer(StackBuffer&&) = delete;
|
||||
|
||||
explicit StackBuffer(uint32_t N)
|
||||
: m_buffer(static_cast<T*>(malloc(N * sizeof(T))))
|
||||
, m_size(0)
|
||||
, m_capacity(N)
|
||||
, m_maxcapacity(N)
|
||||
{
|
||||
}
|
||||
|
||||
~StackBuffer()
|
||||
{
|
||||
for (uint32_t i = 0; i < m_size; ++i)
|
||||
destroy_elem(m_buffer + i);
|
||||
|
||||
free(m_buffer);
|
||||
|
||||
for (auto& elem : m_overflow)
|
||||
destroy_elem(reinterpret_cast<T*>(elem.data + 0));
|
||||
}
|
||||
|
||||
template <class ... TArgs>
|
||||
T& push(TArgs ... _args)
|
||||
{
|
||||
if (m_size < m_capacity)
|
||||
return *(::new (m_buffer + m_size++) T(_args...));
|
||||
|
||||
m_overflow.emplace_back();
|
||||
const uint32_t cap = m_capacity + static_cast<uint32_t>(m_overflow.size());
|
||||
if (m_maxcapacity < cap)
|
||||
m_maxcapacity = cap;
|
||||
|
||||
return *(::new (m_overflow.back().data + 0) T(_args...));
|
||||
}
|
||||
|
||||
void pop()
|
||||
{
|
||||
if (m_overflow.empty())
|
||||
{
|
||||
// m_size should not be equal to 0 here because ProfileManager behavior does not allow such situation
|
||||
destroy_elem(m_buffer + --m_size);
|
||||
|
||||
if (m_size == 0 && m_maxcapacity > m_capacity)
|
||||
{
|
||||
// When stack gone empty we can resize buffer to use enough space in the future
|
||||
free(m_buffer);
|
||||
m_maxcapacity = m_capacity = std::max(m_maxcapacity, m_capacity << 1);
|
||||
m_buffer = static_cast<T*>(malloc(m_capacity * sizeof(T)));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
destroy_elem(reinterpret_cast<T*>(m_overflow.back().data + 0));
|
||||
m_overflow.pop_back();
|
||||
}
|
||||
|
||||
}; // END of class StackBuffer.
|
||||
|
||||
#endif // EASY_PROFILER_STACK_BUFFER_H
|
||||
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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.
|
||||
|
||||
**/
|
||||
|
||||
#include <algorithm>
|
||||
#include "thread_storage.h"
|
||||
#include "current_thread.h"
|
||||
#include "current_time.h"
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
EASY_CONSTEXPR uint16_t BASE_SIZE = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + 1U);
|
||||
|
||||
#if EASY_OPTION_TRUNCATE_LONG_RUNTIME_NAMES != 0
|
||||
EASY_CONSTEXPR uint16_t MAX_BLOCK_NAME_LENGTH = BLOCK_CHUNK_SIZE - BASE_SIZE;
|
||||
#endif
|
||||
|
||||
#if EASY_OPTION_CHECK_MAX_VALUE_DATA_SIZE != 0
|
||||
EASY_CONSTEXPR uint16_t MAX_VALUE_DATA_SIZE = BLOCK_CHUNK_SIZE - static_cast<uint16_t>(sizeof(profiler::ArbitraryValue));
|
||||
#endif
|
||||
|
||||
profiler::vin_t ptr2vin(const void* ptr)
|
||||
{
|
||||
static_assert(sizeof(uintptr_t) == sizeof(void*),
|
||||
"Can not cast void* to uintptr_t. Different sizes.");
|
||||
|
||||
static_assert(sizeof(profiler::vin_t) >= sizeof(uintptr_t),
|
||||
"Can not cast uintptr_t to vin_t. Possible truncation.");
|
||||
|
||||
return static_cast<profiler::vin_t>(reinterpret_cast<uintptr_t>(ptr));
|
||||
}
|
||||
|
||||
} // end of namespace <noname>.
|
||||
|
||||
ThreadStorage::ThreadStorage()
|
||||
: nonscopedBlocks(16)
|
||||
, frameStartTime(0)
|
||||
, id(getCurrentThreadId())
|
||||
, stackSize(0)
|
||||
, allowChildren(true)
|
||||
, named(false)
|
||||
, guarded(false)
|
||||
, frameOpened(false)
|
||||
{
|
||||
expired = ATOMIC_VAR_INIT(0);
|
||||
}
|
||||
|
||||
void ThreadStorage::storeValue(
|
||||
profiler::timestamp_t _timestamp,
|
||||
profiler::block_id_t _id,
|
||||
profiler::DataType _type,
|
||||
const void* _data,
|
||||
uint16_t _size,
|
||||
bool _isArray,
|
||||
profiler::ValueId _vin
|
||||
) {
|
||||
#if EASY_OPTION_CHECK_MAX_VALUE_DATA_SIZE != 0
|
||||
if (_size > MAX_VALUE_DATA_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
const uint16_t serializedDataSize = _size + static_cast<uint16_t>(sizeof(profiler::ArbitraryValue));
|
||||
|
||||
void* data = blocks.closedList.allocate(serializedDataSize);
|
||||
|
||||
::new (data) profiler::ArbitraryValue(_timestamp, ptr2vin(_vin.m_id), _id, _size, _type, _isArray);
|
||||
|
||||
char* cdata = reinterpret_cast<char*>(data);
|
||||
memcpy(cdata + sizeof(profiler::ArbitraryValue), _data, _size);
|
||||
|
||||
blocks.frameMemorySize += serializedDataSize;
|
||||
|
||||
putMarkIfEmpty();
|
||||
}
|
||||
|
||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
{
|
||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
|
||||
EASY_LOCAL_STATIC_PTR(const BaseBlockDescriptor*, desc, \
|
||||
MANAGER.addBlockDescriptor(EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON ? profiler::ON : profiler::OFF, EASY_UNIQUE_LINE_ID, "EasyProfiler.ExpandStorage", \
|
||||
__FILE__, __LINE__, profiler::BlockType::Block, EASY_COLOR_INTERNAL_EVENT));
|
||||
|
||||
EASY_THREAD_LOCAL static profiler::timestamp_t beginTime = 0ULL;
|
||||
EASY_THREAD_LOCAL static profiler::timestamp_t endTime = 0ULL;
|
||||
#endif
|
||||
|
||||
#if EASY_OPTION_TRUNCATE_LONG_RUNTIME_NAMES != 0
|
||||
const uint16_t nameLength = std::min(static_cast<uint16_t>(strlen(block.name())), MAX_BLOCK_NAME_LENGTH);
|
||||
#else
|
||||
const uint16_t nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
#endif
|
||||
|
||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND == 0
|
||||
const
|
||||
#endif
|
||||
auto serializedDataSize = static_cast<uint16_t>(BASE_SIZE + nameLength);
|
||||
|
||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
|
||||
const bool expanded = (desc->m_status & profiler::ON) && blocks.closedList.need_expand(serializedDataSize);
|
||||
if (expanded) beginTime = profiler::clock::now();
|
||||
#endif
|
||||
|
||||
void* data = blocks.closedList.allocate(serializedDataSize);
|
||||
|
||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
|
||||
if (expanded) endTime = profiler::clock::now();
|
||||
#endif
|
||||
|
||||
::new (data) profiler::SerializedBlock(block, nameLength);
|
||||
blocks.frameMemorySize += serializedDataSize;
|
||||
|
||||
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
|
||||
if (expanded)
|
||||
{
|
||||
profiler::Block b(beginTime, desc->id(), "");
|
||||
b.finish(endTime);
|
||||
|
||||
serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + 1);
|
||||
data = blocks.closedList.allocate(serializedDataSize);
|
||||
::new (data) profiler::SerializedBlock(b, 0);
|
||||
blocks.frameMemorySize += serializedDataSize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThreadStorage::storeBlockForce(const profiler::Block& block)
|
||||
{
|
||||
const auto nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
const auto serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + nameLength + 1);
|
||||
|
||||
void* data = blocks.closedList.marked_allocate(serializedDataSize);
|
||||
::new (data) profiler::SerializedBlock(block, nameLength);
|
||||
blocks.usedMemorySize += serializedDataSize;
|
||||
}
|
||||
|
||||
void ThreadStorage::storeCSwitch(const CSwitchBlock& block)
|
||||
{
|
||||
const auto nameLength = static_cast<uint16_t>(strlen(block.name()));
|
||||
const auto serializedDataSize = static_cast<uint16_t>(sizeof(profiler::CSwitchEvent) + nameLength + 1);
|
||||
|
||||
void* data = sync.closedList.allocate(serializedDataSize);
|
||||
::new (data) profiler::SerializedCSwitch(block, nameLength);
|
||||
sync.usedMemorySize += serializedDataSize;
|
||||
}
|
||||
|
||||
void ThreadStorage::clearClosed()
|
||||
{
|
||||
blocks.clearClosed();
|
||||
sync.clearClosed();
|
||||
}
|
||||
|
||||
void ThreadStorage::popSilent()
|
||||
{
|
||||
if (!blocks.openedList.empty())
|
||||
{
|
||||
profiler::Block& top = blocks.openedList.back();
|
||||
top.m_end = top.m_begin;
|
||||
if (!top.m_isScoped)
|
||||
nonscopedBlocks.pop();
|
||||
blocks.openedList.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadStorage::beginFrame()
|
||||
{
|
||||
if (!frameOpened)
|
||||
{
|
||||
frameStartTime = profiler::clock::now();
|
||||
frameOpened = true;
|
||||
}
|
||||
}
|
||||
|
||||
profiler::timestamp_t ThreadStorage::endFrame()
|
||||
{
|
||||
frameOpened = false;
|
||||
return profiler::clock::now() - frameStartTime;
|
||||
}
|
||||
|
||||
void ThreadStorage::putMark()
|
||||
{
|
||||
blocks.closedList.put_mark();
|
||||
blocks.usedMemorySize += blocks.frameMemorySize;
|
||||
blocks.frameMemorySize = 0;
|
||||
}
|
||||
|
||||
void ThreadStorage::putMarkIfEmpty()
|
||||
{
|
||||
if (!frameOpened)
|
||||
putMark();
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
Lightweight profiler library for c++
|
||||
Copyright(C) 2016-2019 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_THREAD_STORAGE_H
|
||||
#define EASY_PROFILER_THREAD_STORAGE_H
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <easy/details/profiler_public_types.h>
|
||||
#include <easy/details/arbitrary_value_public_types.h>
|
||||
#include <easy/serialized_block.h>
|
||||
|
||||
#include "chunk_allocator.h"
|
||||
#include "stack_buffer.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T, const uint16_t N>
|
||||
struct BlocksList
|
||||
{
|
||||
BlocksList(const BlocksList&) = delete;
|
||||
BlocksList(BlocksList&&) = delete;
|
||||
|
||||
BlocksList() = default;
|
||||
|
||||
std::vector<T> openedList;
|
||||
chunk_allocator<N> closedList;
|
||||
uint64_t usedMemorySize = 0;
|
||||
uint64_t frameMemorySize = 0;
|
||||
|
||||
void clearClosed()
|
||||
{
|
||||
//closedList.clear();
|
||||
usedMemorySize = 0;
|
||||
frameMemorySize = 0;
|
||||
}
|
||||
|
||||
}; // END of struct BlocksList.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CSwitchBlock : public profiler::CSwitchEvent
|
||||
{
|
||||
const char* m_name;
|
||||
|
||||
public:
|
||||
|
||||
CSwitchBlock(profiler::timestamp_t _begin_time, profiler::thread_id_t _tid, const char* _runtimeName) EASY_NOEXCEPT;
|
||||
inline const char* name() const EASY_NOEXCEPT { return m_name; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EASY_CONSTEXPR uint16_t BLOCKS_IN_CHUNK = 128U;
|
||||
EASY_CONSTEXPR uint16_t SIZEOF_BLOCK = sizeof(profiler::BaseBlockData) + 1U + sizeof(uint16_t); // SerializedBlock stores BaseBlockData + at least 1 character for name ('\0') + 2 bytes for size of serialized data
|
||||
EASY_CONSTEXPR uint16_t SIZEOF_CSWITCH = sizeof(profiler::CSwitchEvent) + 1U + sizeof(uint16_t); // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id
|
||||
|
||||
static_assert(((int)SIZEOF_BLOCK * (int)BLOCKS_IN_CHUNK) < 65536, "Chunk size for profiler::Block must be less than 65536");
|
||||
static_assert(((int)SIZEOF_CSWITCH * (int)BLOCKS_IN_CHUNK) < 65536, "Chunk size for CSwitchBlock must be less than 65536");
|
||||
|
||||
EASY_CONSTEXPR uint16_t BLOCK_CHUNK_SIZE = get_aligned_size<SIZEOF_BLOCK * BLOCKS_IN_CHUNK>::Size;
|
||||
EASY_CONSTEXPR uint16_t CSWITCH_CHUNK_SIZE = get_aligned_size<SIZEOF_BLOCK * BLOCKS_IN_CHUNK>::Size;
|
||||
|
||||
static_assert((BLOCK_CHUNK_SIZE % EASY_ALIGN_SIZE) == 0, "BLOCK_CHUNK_SIZE not aligned");
|
||||
static_assert((CSWITCH_CHUNK_SIZE % EASY_ALIGN_SIZE) == 0, "CSWITCH_CHUNK_SIZE not aligned");
|
||||
static_assert(BLOCK_CHUNK_SIZE > 2048, "wrong BLOCK_CHUNK_SIZE");
|
||||
static_assert(CSWITCH_CHUNK_SIZE > 2048, "wrong CSWITCH_CHUNK_SIZE");
|
||||
|
||||
struct ThreadStorage EASY_FINAL
|
||||
{
|
||||
using BlocksStorage = BlocksList<std::reference_wrapper<profiler::Block>, BLOCK_CHUNK_SIZE>;
|
||||
using ContextSwitchStorage = BlocksList<CSwitchBlock, CSWITCH_CHUNK_SIZE>;
|
||||
|
||||
StackBuffer<NonscopedBlock> nonscopedBlocks;
|
||||
BlocksStorage blocks;
|
||||
ContextSwitchStorage sync;
|
||||
|
||||
std::string name; ///< Thread name
|
||||
profiler::timestamp_t frameStartTime; ///< Current frame start time. Used to calculate FPS.
|
||||
const profiler::thread_id_t id; ///< Thread ID
|
||||
std::atomic<char> expired; ///< Is thread expired
|
||||
int32_t stackSize; ///< Current thread stack depth. Used when switching profiler state to begin collecting blocks only when new frame would be opened.
|
||||
bool allowChildren; ///< False if one of previously opened blocks has OFF_RECURSIVE or ON_WITHOUT_CHILDREN status
|
||||
bool named; ///< True if thread name was set
|
||||
bool guarded; ///< True if thread has been registered using ThreadGuard
|
||||
bool frameOpened; ///< Is new frame opened (this does not depend on profiling status) \sa profiledFrameOpened
|
||||
|
||||
void storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, uint16_t _size, bool _isArray, profiler::ValueId _vin);
|
||||
void storeBlock(const profiler::Block& _block);
|
||||
void storeBlockForce(const profiler::Block& _block);
|
||||
void storeCSwitch(const CSwitchBlock& _block);
|
||||
void clearClosed();
|
||||
void popSilent();
|
||||
|
||||
void beginFrame();
|
||||
profiler::timestamp_t endFrame();
|
||||
void putMark();
|
||||
void putMarkIfEmpty();
|
||||
|
||||
ThreadStorage();
|
||||
ThreadStorage(const ThreadStorage&) = delete;
|
||||
ThreadStorage(ThreadStorage&&) = delete;
|
||||
|
||||
}; // END of struct ThreadStorage.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // EASY_PROFILER_THREAD_STORAGE_H
|
||||
+564
@@ -0,0 +1,564 @@
|
||||
/************************************************************************
|
||||
* file name : writer.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2018/05/08
|
||||
* authors : Sergey Yagovtsev, Victor Zarubkin
|
||||
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of fillTreesFromFile function
|
||||
* : which reads profiler file and fill profiler blocks tree.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2019 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.
|
||||
************************************************************************/
|
||||
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
#include <easy/writer.h>
|
||||
#include <easy/profiler.h>
|
||||
|
||||
#include "alignment_helpers.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern const uint32_t EASY_PROFILER_SIGNATURE;
|
||||
extern const uint32_t EASY_PROFILER_VERSION;
|
||||
|
||||
EASY_CONSTEXPR auto BaseCSwitchSize = sizeof(profiler::SerializedCSwitch) + 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct BlocksRange
|
||||
{
|
||||
profiler::block_index_t begin;
|
||||
profiler::block_index_t end;
|
||||
|
||||
BlocksRange(profiler::block_index_t size = 0)
|
||||
: begin(0), end(size)
|
||||
{
|
||||
}
|
||||
|
||||
BlocksRange(profiler::block_index_t beginIndex, profiler::block_index_t endIndex)
|
||||
: begin(beginIndex), end(endIndex)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct BlocksMemoryAndCount
|
||||
{
|
||||
uint64_t usedMemorySize = 0; // memory size used by profiler blocks
|
||||
profiler::block_index_t blocksCount = 0;
|
||||
|
||||
BlocksMemoryAndCount() = default;
|
||||
|
||||
BlocksMemoryAndCount& operator += (const BlocksMemoryAndCount& another)
|
||||
{
|
||||
usedMemorySize += another.usedMemorySize;
|
||||
blocksCount += another.blocksCount;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct BlocksAndCSwitchesRange
|
||||
{
|
||||
BlocksMemoryAndCount blocksMemoryAndCount;
|
||||
BlocksMemoryAndCount cswitchesMemoryAndCount;
|
||||
BlocksRange blocks;
|
||||
BlocksRange cswitches;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T>
|
||||
static void write(std::ostream& _stream, const char* _data, T _size)
|
||||
{
|
||||
_stream.write(_data, _size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void write(std::ostream& _stream, const T& _data)
|
||||
{
|
||||
_stream.write((const char*)&_data, sizeof(T));
|
||||
}
|
||||
|
||||
static bool update_progress_write(std::atomic<int>& progress, int new_value, std::ostream& _log)
|
||||
{
|
||||
auto oldprogress = progress.exchange(new_value, std::memory_order_release);
|
||||
if (oldprogress < 0)
|
||||
{
|
||||
_log << "Writing was interrupted";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler::timestamp_t beginTime,
|
||||
profiler::timestamp_t endTime, const profiler::block_getter_fn& getter)
|
||||
{
|
||||
const auto size = static_cast<profiler::block_index_t>(children.size());
|
||||
BlocksRange range(size);
|
||||
|
||||
if (size == 0)
|
||||
return range;
|
||||
|
||||
if (beginTime <= getter(children.front()).node->begin() && getter(children.back()).node->end() <= endTime)
|
||||
return range; // All blocks inside range
|
||||
|
||||
auto first_it = std::lower_bound(children.begin(), children.end(), beginTime,
|
||||
[&](profiler::block_index_t element, profiler::timestamp_t value)
|
||||
{
|
||||
return getter(element).node->end() < value;
|
||||
});
|
||||
|
||||
for (; first_it != children.end(); ++first_it)
|
||||
{
|
||||
const auto& child = getter(*first_it);
|
||||
if (child.node->begin() >= beginTime || child.node->end() > beginTime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (first_it != children.end() && getter(*first_it).node->begin() <= endTime)
|
||||
{
|
||||
auto last_it = std::lower_bound(children.begin(), children.end(), endTime,
|
||||
[&](profiler::block_index_t element, profiler::timestamp_t value)
|
||||
{
|
||||
return getter(element).node->begin() <= value;
|
||||
});
|
||||
|
||||
if (last_it != children.end() && getter(*last_it).node->end() >= beginTime)
|
||||
{
|
||||
const auto begin = static_cast<profiler::block_index_t>(std::distance(children.begin(), first_it));
|
||||
const auto end = static_cast<profiler::block_index_t>(std::distance(children.begin(), last_it));
|
||||
|
||||
if (begin <= end)
|
||||
{
|
||||
range.begin = begin;
|
||||
range.end = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static BlocksRange findRange(const profiler::bookmarks_t& bookmarks, profiler::timestamp_t beginTime, profiler::timestamp_t endTime)
|
||||
{
|
||||
const auto size = static_cast<profiler::block_index_t>(bookmarks.size());
|
||||
BlocksRange range(size);
|
||||
|
||||
if (size == 0)
|
||||
return range;
|
||||
|
||||
if (beginTime <= bookmarks.front().pos && bookmarks.back().pos <= endTime)
|
||||
return range; // All blocks inside range
|
||||
|
||||
auto first_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), beginTime,
|
||||
[](const profiler::Bookmark& element, profiler::timestamp_t value)
|
||||
{
|
||||
return element.pos < value;
|
||||
});
|
||||
|
||||
for (; first_it != bookmarks.end(); ++first_it)
|
||||
{
|
||||
const auto& bookmark = *first_it;
|
||||
if (bookmark.pos >= beginTime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (first_it != bookmarks.end() && first_it->pos <= endTime)
|
||||
{
|
||||
auto last_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), endTime,
|
||||
[](const profiler::Bookmark& element, profiler::timestamp_t value)
|
||||
{
|
||||
return element.pos <= value;
|
||||
});
|
||||
|
||||
if (last_it != bookmarks.end() && last_it->pos >= beginTime)
|
||||
{
|
||||
const auto begin = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), first_it));
|
||||
const auto end = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), last_it));
|
||||
|
||||
if (begin <= end)
|
||||
{
|
||||
range.begin = begin;
|
||||
range.end = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children,
|
||||
const BlocksRange& range,
|
||||
const profiler::block_getter_fn& getter,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
bool contextSwitches)
|
||||
{
|
||||
BlocksMemoryAndCount memoryAndCount;
|
||||
|
||||
if (!contextSwitches)
|
||||
{
|
||||
for (auto i = range.begin; i < range.end; ++i)
|
||||
{
|
||||
const auto& child = getter(children[i]);
|
||||
|
||||
// Calculate self memory consumption
|
||||
const auto& desc = *descriptors[child.node->id()];
|
||||
uint64_t usedMemorySize = 0;
|
||||
|
||||
if (desc.type() == profiler::BlockType::Value)
|
||||
usedMemorySize = sizeof(profiler::ArbitraryValue) + child.value->data_size();
|
||||
else
|
||||
usedMemorySize = sizeof(profiler::SerializedBlock) + strlen(child.node->name()) + 1;
|
||||
|
||||
// Calculate children memory consumption
|
||||
const BlocksRange childRange(0, static_cast<profiler::block_index_t>(child.children.size()));
|
||||
const auto childrenMemoryAndCount = calculateUsedMemoryAndBlocksCount(child.children, childRange,
|
||||
getter, descriptors,
|
||||
false);
|
||||
|
||||
// Accumulate memory and count
|
||||
memoryAndCount += childrenMemoryAndCount;
|
||||
memoryAndCount.usedMemorySize += usedMemorySize;
|
||||
++memoryAndCount.blocksCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i = range.begin; i < range.end; ++i)
|
||||
{
|
||||
const auto& child = getter(children[i]);
|
||||
const uint64_t usedMemorySize = BaseCSwitchSize + strlen(child.cs->name());
|
||||
memoryAndCount.usedMemorySize += usedMemorySize;
|
||||
++memoryAndCount.blocksCount;
|
||||
}
|
||||
}
|
||||
|
||||
return memoryAndCount;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void serializeBlocks(std::ostream& output, std::vector<char>& buffer,
|
||||
const profiler::BlocksTree::children_t& children, const BlocksRange& range,
|
||||
const profiler::block_getter_fn& getter, const profiler::descriptors_list_t& descriptors)
|
||||
{
|
||||
for (auto i = range.begin; i < range.end; ++i)
|
||||
{
|
||||
const auto& child = getter(children[i]);
|
||||
|
||||
// Serialize children
|
||||
const BlocksRange childRange(0, static_cast<profiler::block_index_t>(child.children.size()));
|
||||
serializeBlocks(output, buffer, child.children, childRange, getter, descriptors);
|
||||
|
||||
// Serialize self
|
||||
const auto& desc = *descriptors[child.node->id()];
|
||||
uint16_t usedMemorySize = 0;
|
||||
|
||||
if (desc.type() == profiler::BlockType::Value)
|
||||
{
|
||||
usedMemorySize = static_cast<uint16_t>(sizeof(profiler::ArbitraryValue)) + child.value->data_size();
|
||||
buffer.resize(usedMemorySize + sizeof(uint16_t));
|
||||
unaligned_store16(buffer.data(), usedMemorySize);
|
||||
memcpy(buffer.data() + sizeof(uint16_t), child.value, static_cast<size_t>(usedMemorySize));
|
||||
}
|
||||
else
|
||||
{
|
||||
usedMemorySize = static_cast<uint16_t>(sizeof(profiler::SerializedBlock)
|
||||
+ strlen(child.node->name()) + 1);
|
||||
|
||||
buffer.resize(usedMemorySize + sizeof(uint16_t));
|
||||
unaligned_store16(buffer.data(), usedMemorySize);
|
||||
memcpy(buffer.data() + sizeof(uint16_t), child.node, static_cast<size_t>(usedMemorySize));
|
||||
|
||||
if (child.node->id() != desc.id())
|
||||
{
|
||||
// This block id is dynamic. Restore it's value like it was before in the input .prof file
|
||||
auto block = reinterpret_cast<profiler::SerializedBlock*>(buffer.data() + sizeof(uint16_t));
|
||||
block->setId(desc.id());
|
||||
}
|
||||
}
|
||||
|
||||
write(output, buffer.data(), buffer.size());
|
||||
}
|
||||
}
|
||||
|
||||
static void serializeContextSwitches(std::ostream& output, std::vector<char>& buffer,
|
||||
const profiler::BlocksTree::children_t& children, const BlocksRange& range,
|
||||
const profiler::block_getter_fn& getter)
|
||||
{
|
||||
for (auto i = range.begin; i < range.end; ++i)
|
||||
{
|
||||
const auto& child = getter(children[i]);
|
||||
|
||||
const auto usedMemorySize = static_cast<uint16_t>(BaseCSwitchSize + strlen(child.cs->name()));
|
||||
|
||||
buffer.resize(usedMemorySize + sizeof(uint16_t));
|
||||
unaligned_store16(buffer.data(), usedMemorySize);
|
||||
memcpy(buffer.data() + sizeof(uint16_t), child.cs, static_cast<size_t>(usedMemorySize));
|
||||
|
||||
write(output, buffer.data(), buffer.size());
|
||||
}
|
||||
}
|
||||
|
||||
static void serializeDescriptors(std::ostream& output, std::vector<char>& buffer,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count)
|
||||
{
|
||||
const size_t size = std::min(descriptors.size(), static_cast<size_t>(descriptors_count));
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
const auto& desc = *descriptors[i];
|
||||
if (desc.id() != i)
|
||||
break;
|
||||
|
||||
const auto usedMemorySize = static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor)
|
||||
+ strlen(desc.name()) + strlen(desc.file()) + 2);
|
||||
|
||||
buffer.resize(usedMemorySize + sizeof(uint16_t));
|
||||
unaligned_store16(buffer.data(), usedMemorySize);
|
||||
memcpy(buffer.data() + sizeof(uint16_t), &desc, static_cast<size_t>(usedMemorySize));
|
||||
|
||||
write(output, buffer.data(), buffer.size());
|
||||
}
|
||||
}
|
||||
|
||||
static void serializeBookmarks(std::ostream& output, const profiler::bookmarks_t& bookmarks, const BlocksRange& range)
|
||||
{
|
||||
for (auto i = range.begin; i < range.end; ++i)
|
||||
{
|
||||
const auto& bookmark = bookmarks[i];
|
||||
|
||||
const auto usedMemorySize = static_cast<uint16_t>(profiler::Bookmark::BaseSize + bookmark.text.size());
|
||||
write(output, usedMemorySize);
|
||||
write(output, bookmark.pos);
|
||||
write(output, bookmark.color);
|
||||
write(output, bookmark.text.c_str(), bookmark.text.size() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
|
||||
const profiler::SerializedData& serialized_descriptors,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
profiler::processid_t pid,
|
||||
std::ostream& log)
|
||||
{
|
||||
if (!update_progress_write(progress, 0, log))
|
||||
return 0;
|
||||
|
||||
std::ofstream outFile(filename, std::fstream::binary);
|
||||
if (!outFile.is_open())
|
||||
{
|
||||
log << "Can not open file " << filename;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write data to file
|
||||
auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors, descriptors_count, trees,
|
||||
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<int>& progress, std::ostream& str,
|
||||
const profiler::SerializedData& serialized_descriptors,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
profiler::processid_t pid,
|
||||
std::ostream& log)
|
||||
{
|
||||
if (trees.empty() || serialized_descriptors.empty() || descriptors_count == 0)
|
||||
{
|
||||
log << "Nothing to save";
|
||||
return 0;
|
||||
}
|
||||
|
||||
BlocksMemoryAndCount total;
|
||||
|
||||
using ranges_t = std::unordered_map<profiler::thread_id_t, BlocksAndCSwitchesRange, estd::hash<profiler::thread_id_t> >;
|
||||
ranges_t block_ranges;
|
||||
|
||||
// Calculate block ranges and used memory (for serialization)
|
||||
profiler::timestamp_t beginTime = begin_time, endTime = end_time;
|
||||
size_t i = 0;
|
||||
for (const auto& kv : trees)
|
||||
{
|
||||
const auto id = kv.first;
|
||||
const auto& tree = kv.second;
|
||||
|
||||
BlocksAndCSwitchesRange range;
|
||||
|
||||
range.blocks = findRange(tree.children, begin_time, end_time, block_getter);
|
||||
range.cswitches = findRange(tree.sync, begin_time, end_time, block_getter);
|
||||
|
||||
range.blocksMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.children, range.blocks, block_getter,
|
||||
descriptors, false);
|
||||
total += range.blocksMemoryAndCount;
|
||||
|
||||
if (range.blocksMemoryAndCount.blocksCount != 0)
|
||||
{
|
||||
beginTime = std::min(beginTime, block_getter(tree.children[range.blocks.begin]).node->begin());
|
||||
endTime = std::max(endTime, block_getter(tree.children[range.blocks.end - 1]).node->end());
|
||||
}
|
||||
|
||||
range.cswitchesMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.sync, range.cswitches, block_getter,
|
||||
descriptors, true);
|
||||
total += range.cswitchesMemoryAndCount;
|
||||
|
||||
if (range.cswitchesMemoryAndCount.blocksCount != 0)
|
||||
{
|
||||
beginTime = std::min(beginTime, block_getter(tree.children[range.cswitches.begin]).cs->begin());
|
||||
endTime = std::max(endTime, block_getter(tree.children[range.cswitches.end - 1]).cs->end());
|
||||
}
|
||||
|
||||
block_ranges[id] = range;
|
||||
|
||||
if (!update_progress_write(progress, 15 / static_cast<int>(trees.size() - i), log))
|
||||
return 0;
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
BlocksRange bookmarksRange;
|
||||
uint16_t bookmarksCount = 0;
|
||||
if (!bookmarks.empty())
|
||||
{
|
||||
bookmarksRange = findRange(bookmarks, begin_time, end_time);
|
||||
bookmarksCount = static_cast<uint16_t>(bookmarksRange.end - bookmarksRange.begin);
|
||||
if (bookmarksCount != 0)
|
||||
{
|
||||
beginTime = std::min(beginTime, bookmarks[bookmarksRange.begin].pos);
|
||||
endTime = std::max(endTime, bookmarks[bookmarksRange.end - 1].pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (total.blocksCount == 0)
|
||||
{
|
||||
log << "Nothing to save";
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint64_t usedMemorySizeDescriptors = serialized_descriptors.size() + descriptors_count * sizeof(uint16_t);
|
||||
|
||||
// Write data to stream
|
||||
write(str, EASY_PROFILER_SIGNATURE);
|
||||
write(str, EASY_PROFILER_VERSION);
|
||||
write(str, pid);
|
||||
|
||||
// write 0 because we do not need to convert time from ticks to nanoseconds (it's already converted)
|
||||
write<int64_t>(str, 0LL); // CPU frequency
|
||||
|
||||
write(str, beginTime);
|
||||
write(str, endTime);
|
||||
|
||||
write(str, total.usedMemorySize);
|
||||
write(str, usedMemorySizeDescriptors);
|
||||
write(str, total.blocksCount);
|
||||
write(str, descriptors_count);
|
||||
write(str, static_cast<uint32_t>(trees.size()));
|
||||
write(str, bookmarksCount);
|
||||
write(str, static_cast<uint16_t>(0)); // padding
|
||||
|
||||
std::vector<char> buffer;
|
||||
|
||||
// Serialize all descriptors
|
||||
serializeDescriptors(str, buffer, descriptors, descriptors_count);
|
||||
|
||||
// Serialize all blocks
|
||||
i = 0;
|
||||
for (const auto& kv : trees)
|
||||
{
|
||||
const auto id = kv.first;
|
||||
const auto& tree = kv.second;
|
||||
const auto& range = block_ranges.at(id);
|
||||
|
||||
const auto nameSize = static_cast<uint16_t>(tree.thread_name.size() + 1);
|
||||
write(str, id);
|
||||
write(str, nameSize);
|
||||
write(str, tree.name(), nameSize);
|
||||
|
||||
// Serialize context switches
|
||||
write(str, range.cswitchesMemoryAndCount.blocksCount);
|
||||
if (range.cswitchesMemoryAndCount.blocksCount != 0)
|
||||
serializeContextSwitches(str, buffer, tree.sync, range.cswitches, block_getter);
|
||||
|
||||
// Serialize blocks
|
||||
write(str, range.blocksMemoryAndCount.blocksCount);
|
||||
if (range.blocksMemoryAndCount.blocksCount != 0)
|
||||
serializeBlocks(str, buffer, tree.children, range.blocks, block_getter, descriptors);
|
||||
|
||||
if (!update_progress_write(progress, 40 + 57 / static_cast<int>(trees.size() - i), log))
|
||||
return 0;
|
||||
}
|
||||
|
||||
write(str, EASY_PROFILER_SIGNATURE);
|
||||
|
||||
// Serialize bookmarks
|
||||
if (bookmarksCount != 0)
|
||||
{
|
||||
serializeBookmarks(str, bookmarks, bookmarksRange);
|
||||
write(str, EASY_PROFILER_SIGNATURE);
|
||||
}
|
||||
|
||||
return total.blocksCount;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
Reference in New Issue
Block a user