From 65bfb94276d0533338ee3d073cb28e8fc86ba8e1 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Thu, 5 Oct 2017 20:53:41 +0300 Subject: [PATCH] #0 [Core] Refactoring: moved all types from profiler.h to separate file --- .gitignore | 2 +- easy_profiler_core/include/easy/profiler.h | 238 +++++------------- .../include/easy/profiler_public_types.h | 220 ++++++++++++++++ 3 files changed, 289 insertions(+), 171 deletions(-) create mode 100644 easy_profiler_core/include/easy/profiler_public_types.h diff --git a/.gitignore b/.gitignore index e4373d3..7b6c709 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ bin *build* -.idea +.* *.user diff --git a/easy_profiler_core/include/easy/profiler.h b/easy_profiler_core/include/easy/profiler.h index 27c36b8..3ca6b12 100644 --- a/easy_profiler_core/include/easy/profiler.h +++ b/easy_profiler_core/include/easy/profiler.h @@ -43,7 +43,7 @@ The Apache License, Version 2.0 (the "License"); #ifndef EASY_PROFILER_H #define EASY_PROFILER_H -#include +#include #if defined ( __clang__ ) # pragma clang diagnostic push @@ -453,180 +453,14 @@ Added for clarification. ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -class NonscopedBlock; -class ProfileManager; -struct ThreadStorage; - namespace profiler { - ////////////////////////////////////////////////////////////////////// - // Core types - const uint16_t DEFAULT_PORT = EASY_DEFAULT_PORT; - typedef uint64_t timestamp_t; - typedef uint64_t thread_id_t; - typedef uint32_t block_id_t; - - enum BlockType : uint8_t - { - BLOCK_TYPE_EVENT = 0, - BLOCK_TYPE_BLOCK, - - BLOCK_TYPES_NUMBER - }; - typedef BlockType block_type_t; - - enum Duration : uint8_t - { - TICKS = 0, ///< CPU ticks - MICROSECONDS ///< Microseconds - }; - - //*********************************************** - -#pragma pack(push,1) - class PROFILER_API BaseBlockDescriptor - { - friend ::ProfileManager; - friend ::ThreadStorage; - - protected: - - block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors) - int m_line; ///< Line number in the source file - color_t m_color; ///< Color of the block packed into 1-byte structure - block_type_t m_type; ///< Type of the block (See BlockType) - EasyBlockStatus m_status; ///< If false then blocks with such id() will not be stored by profiler during profile session - - BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color); - - public: - - inline block_id_t id() const { return m_id; } - inline int line() const { return m_line; } - inline color_t color() const { return m_color; } - inline block_type_t type() const { return m_type; } - inline EasyBlockStatus status() const { return m_status; } - - }; // END of class BaseBlockDescriptor. - - //*********************************************** - - class PROFILER_API Event - { - friend ::ProfileManager; - - protected: - - timestamp_t m_begin; - timestamp_t m_end; - - public: - - Event(const Event&) = default; - Event(timestamp_t _begin_time); - Event(timestamp_t _begin_time, timestamp_t _end_time); - - inline timestamp_t begin() const { return m_begin; } - inline timestamp_t end() const { return m_end; } - inline timestamp_t duration() const { return m_end - m_begin; } - - private: - - Event() = delete; - - }; // END class Event. - - class PROFILER_API BaseBlockData : public Event - { - friend ::ProfileManager; - - protected: - - block_id_t m_id; - - public: - - BaseBlockData(const BaseBlockData&) = default; - BaseBlockData(timestamp_t _begin_time, block_id_t _id); - BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id); - - inline block_id_t id() const { return m_id; } - inline void setId(block_id_t _id) { m_id = _id; } - - private: - - BaseBlockData() = delete; - - }; // END of class BaseBlockData. - - class PROFILER_API CSwitchEvent : public Event - { - thread_id_t m_thread_id; - - public: - - CSwitchEvent() = default; - CSwitchEvent(const CSwitchEvent&) = default; - CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid); - - inline thread_id_t tid() const { return m_thread_id; } - - }; // END of class CSwitchEvent. -#pragma pack(pop) - - //*********************************************** - - class PROFILER_API Block : public BaseBlockData - { - friend ::ProfileManager; - friend ::ThreadStorage; - friend ::NonscopedBlock; - - const char* m_name; - EasyBlockStatus m_status; - bool m_isScoped; - - private: - - void start(); - void start(timestamp_t _time); - void finish(); - void finish(timestamp_t _time); - inline bool finished() const { return m_end >= m_begin; } - inline EasyBlockStatus status() const { return m_status; } - inline void setStatus(EasyBlockStatus _status) { m_status = _status; } - - public: - - Block(Block&& that); - Block(const BaseBlockDescriptor* _desc, const char* _runtimeName, bool _scoped = true); - Block(timestamp_t _begin_time, block_id_t _id, const char* _runtimeName); - Block(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id, const char* _runtimeName); - ~Block(); - - inline const char* name() const { return m_name; } - - private: - - Block(const Block&) = delete; - Block& operator = (const Block&) = delete; - - }; // END of class Block. - - //*********************************************** - - class PROFILER_API ThreadGuard EASY_FINAL { - friend ::ProfileManager; - thread_id_t m_id = 0; - public: - ~ThreadGuard(); - }; // END of class ThreadGuard. - ////////////////////////////////////////////////////////////////////// // Core API - // Note: it is better to use macros defined above than a direct calls to API. + // 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 BUILD_WITH_EASY_PROFILER extern "C" { @@ -635,18 +469,24 @@ namespace profiler { You can use it if you want to store block explicitly. + \retval Current CPU time in ticks. + \ingroup profiler */ PROFILER_API timestamp_t currentTime(); /** 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); @@ -659,6 +499,8 @@ namespace profiler { \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); @@ -727,6 +569,8 @@ namespace profiler { /** Enable or disable profiler. + AKA start or stop profiling (capturing blocks). + \ingroup profiler */ PROFILER_API void setEnabled(bool _isEnable); @@ -736,14 +580,26 @@ namespace profiler { \note This also disables profiler. + \retval Number of saved blocks. If 0 then nothing was profiled or an error occured. + \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&); @@ -752,6 +608,8 @@ namespace profiler { \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); @@ -792,8 +650,29 @@ namespace 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. @@ -816,11 +695,16 @@ namespace profiler { /** 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 in 32-bit integer format. + /** Returns current version string. + + Example: "v1.3.0" \ingroup profiler */ @@ -828,12 +712,16 @@ namespace profiler { /** 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); @@ -842,6 +730,8 @@ namespace profiler { 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); @@ -850,12 +740,16 @@ namespace profiler { 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); @@ -864,6 +758,8 @@ namespace profiler { 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); @@ -872,6 +768,8 @@ namespace profiler { 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); diff --git a/easy_profiler_core/include/easy/profiler_public_types.h b/easy_profiler_core/include/easy/profiler_public_types.h new file mode 100644 index 0000000..7a31a53 --- /dev/null +++ b/easy_profiler_core/include/easy/profiler_public_types.h @@ -0,0 +1,220 @@ +/** +Lightweight profiler library for c++ +Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin + +Licensed under either of + * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0) +at your option. + +The MIT License + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. + + +The Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +**/ + +#ifndef EASY_PROFILER_PUBLIC_TYPES_H +#define EASY_PROFILER_PUBLIC_TYPES_H + +#include + +class NonscopedBlock; +class ProfileManager; +struct ThreadStorage; + +namespace profiler { + + typedef uint64_t timestamp_t; + typedef uint64_t thread_id_t; + typedef uint32_t block_id_t; + + enum BlockType : uint8_t + { + BLOCK_TYPE_EVENT = 0, + BLOCK_TYPE_BLOCK, + + BLOCK_TYPES_NUMBER + }; + typedef BlockType block_type_t; + + enum Duration : uint8_t + { + TICKS = 0, ///< CPU ticks + MICROSECONDS ///< Microseconds + }; + + //*********************************************** + +#pragma pack(push,1) + class PROFILER_API BaseBlockDescriptor + { + friend ::ProfileManager; + friend ::ThreadStorage; + + protected: + + block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors) + int m_line; ///< Line number in the source file + color_t m_color; ///< Color of the block packed into 1-byte structure + block_type_t m_type; ///< Type of the block (See BlockType) + EasyBlockStatus m_status; ///< If false then blocks with such id() will not be stored by profiler during profile session + + BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color); + + public: + + inline block_id_t id() const { return m_id; } + inline int line() const { return m_line; } + inline color_t color() const { return m_color; } + inline block_type_t type() const { return m_type; } + inline EasyBlockStatus status() const { return m_status; } + + }; // END of class BaseBlockDescriptor. + + //*********************************************** + + class PROFILER_API Event + { + friend ::ProfileManager; + + protected: + + timestamp_t m_begin; + timestamp_t m_end; + + public: + + Event(const Event&) = default; + Event(timestamp_t _begin_time); + Event(timestamp_t _begin_time, timestamp_t _end_time); + + inline timestamp_t begin() const { return m_begin; } + inline timestamp_t end() const { return m_end; } + inline timestamp_t duration() const { return m_end - m_begin; } + + private: + + Event() = delete; + + }; // END class Event. + + class PROFILER_API BaseBlockData : public Event + { + friend ::ProfileManager; + + protected: + + block_id_t m_id; + + public: + + BaseBlockData(const BaseBlockData&) = default; + BaseBlockData(timestamp_t _begin_time, block_id_t _id); + BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id); + + inline block_id_t id() const { return m_id; } + inline void setId(block_id_t _id) { m_id = _id; } + + private: + + BaseBlockData() = delete; + + }; // END of class BaseBlockData. + + class PROFILER_API CSwitchEvent : public Event + { + thread_id_t m_thread_id; + + public: + + CSwitchEvent() = default; + CSwitchEvent(const CSwitchEvent&) = default; + CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid); + + inline thread_id_t tid() const { return m_thread_id; } + + }; // END of class CSwitchEvent. +#pragma pack(pop) + + //*********************************************** + + class PROFILER_API Block : public BaseBlockData + { + friend ::ProfileManager; + friend ::ThreadStorage; + friend ::NonscopedBlock; + + const char* m_name; + EasyBlockStatus m_status; + bool m_isScoped; + + private: + + void start(); + void start(timestamp_t _time); + void finish(); + void finish(timestamp_t _time); + inline bool finished() const { return m_end >= m_begin; } + inline EasyBlockStatus status() const { return m_status; } + inline void setStatus(EasyBlockStatus _status) { m_status = _status; } + + public: + + Block(Block&& that); + Block(const BaseBlockDescriptor* _desc, const char* _runtimeName, bool _scoped = true); + Block(timestamp_t _begin_time, block_id_t _id, const char* _runtimeName); + Block(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id, const char* _runtimeName); + ~Block(); + + inline const char* name() const { return m_name; } + + private: + + Block(const Block&) = delete; + Block& operator = (const Block&) = delete; + + }; // END of class Block. + + //*********************************************** + + class PROFILER_API ThreadGuard EASY_FINAL + { + friend ::ProfileManager; + thread_id_t m_id = 0; + + public: + + ~ThreadGuard(); + + }; // END of class ThreadGuard. + +} // END of namespace profiler. + +#endif // EASY_PROFILER_PUBLIC_TYPES_H