0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 16:51:22 +08:00

#0 [Core] Refactoring: moved all types from profiler.h to separate file

This commit is contained in:
Victor Zarubkin 2017-10-05 20:53:41 +03:00
parent 1f8cc6346c
commit 65bfb94276
3 changed files with 289 additions and 171 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
bin bin
*build* *build*
.idea .*
*.user *.user

View File

@ -43,7 +43,7 @@ The Apache License, Version 2.0 (the "License");
#ifndef EASY_PROFILER_H #ifndef EASY_PROFILER_H
#define EASY_PROFILER_H #define EASY_PROFILER_H
#include <easy/profiler_aux.h> #include <easy/profiler_public_types.h>
#if defined ( __clang__ ) #if defined ( __clang__ )
# pragma clang diagnostic push # pragma clang diagnostic push
@ -453,180 +453,14 @@ Added for clarification.
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class NonscopedBlock;
class ProfileManager;
struct ThreadStorage;
namespace profiler { namespace profiler {
//////////////////////////////////////////////////////////////////////
// Core types
const uint16_t DEFAULT_PORT = EASY_DEFAULT_PORT; 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 // 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 #ifdef BUILD_WITH_EASY_PROFILER
extern "C" { extern "C" {
@ -635,18 +469,24 @@ namespace profiler {
You can use it if you want to store block explicitly. You can use it if you want to store block explicitly.
\retval Current CPU time in ticks.
\ingroup profiler \ingroup profiler
*/ */
PROFILER_API timestamp_t currentTime(); PROFILER_API timestamp_t currentTime();
/** Convert ticks to nanoseconds. /** Convert ticks to nanoseconds.
\retval _ticks converted to nanoseconds.
\ingroup profiler \ingroup profiler
*/ */
PROFILER_API timestamp_t toNanoseconds(timestamp_t _ticks); PROFILER_API timestamp_t toNanoseconds(timestamp_t _ticks);
/** Convert ticks to microseconds. /** Convert ticks to microseconds.
\retval _ticks converted to microseconds.
\ingroup profiler \ingroup profiler
*/ */
PROFILER_API timestamp_t toMicroseconds(timestamp_t _ticks); 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. \note This API function is used by EASY_EVENT, EASY_BLOCK, EASY_FUNCTION macros.
There is no need to invoke this function explicitly. There is no need to invoke this function explicitly.
\retval Pointer to registered block description.
\ingroup profiler \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); 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. /** Enable or disable profiler.
AKA start or stop profiling (capturing blocks).
\ingroup profiler \ingroup profiler
*/ */
PROFILER_API void setEnabled(bool _isEnable); PROFILER_API void setEnabled(bool _isEnable);
@ -736,14 +580,26 @@ namespace profiler {
\note This also disables profiler. \note This also disables profiler.
\retval Number of saved blocks. If 0 then nothing was profiled or an error occured.
\ingroup profiler \ingroup profiler
*/ */
PROFILER_API uint32_t dumpBlocksToFile(const char* _filename); PROFILER_API uint32_t dumpBlocksToFile(const char* _filename);
/** Register current thread and give it a name. /** 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 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 \ingroup profiler
*/ */
PROFILER_API const char* registerThreadScoped(const char* _name, ThreadGuard&); 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. \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 \ingroup profiler
*/ */
PROFILER_API const char* registerThread(const char* _name); PROFILER_API const char* registerThread(const char* _name);
@ -792,8 +650,29 @@ namespace profiler {
*/ */
PROFILER_API const char* getContextSwitchLogFilename(); 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); 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(); PROFILER_API void stopListen();
/** Check if listening thread launched.
\ingroup profiler
*/
PROFILER_API bool isListening(); PROFILER_API bool isListening();
/** Returns current major version. /** Returns current major version.
@ -816,11 +695,16 @@ namespace profiler {
/** Returns current version in 32-bit integer format. /** 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 \ingroup profiler
*/ */
PROFILER_API uint32_t version(); PROFILER_API uint32_t version();
/** Returns current version in 32-bit integer format. /** Returns current version string.
Example: "v1.3.0"
\ingroup profiler \ingroup profiler
*/ */
@ -828,12 +712,16 @@ namespace profiler {
/** Returns true if current thread has been marked as Main. /** Returns true if current thread has been marked as Main.
Otherwise, returns false. Otherwise, returns false.
\ingroup profiler
*/ */
PROFILER_API bool isMainThread(); PROFILER_API bool isMainThread();
/** Returns last frame duration for current thread. /** Returns last frame duration for current thread.
\param _durationCast desired duration units (could be cpu-ticks or microseconds) \param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/ */
PROFILER_API timestamp_t this_thread_frameTime(Duration _durationCast = ::profiler::MICROSECONDS); 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. Local max is maximum frame duration since last frameTimeLocalMax() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds) \param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/ */
PROFILER_API timestamp_t this_thread_frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS); 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. Local average is average frame duration since last frameTimeLocalAvg() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds) \param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/ */
PROFILER_API timestamp_t this_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS); PROFILER_API timestamp_t this_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS);
/** Returns last frame duration for main thread. /** Returns last frame duration for main thread.
\param _durationCast desired duration units (could be cpu-ticks or microseconds) \param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/ */
PROFILER_API timestamp_t main_thread_frameTime(Duration _durationCast = ::profiler::MICROSECONDS); 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. Local max is maximum frame duration since last frameTimeLocalMax() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds) \param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/ */
PROFILER_API timestamp_t main_thread_frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS); 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. Local average is average frame duration since last frameTimeLocalAvg() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds) \param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/ */
PROFILER_API timestamp_t main_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS); PROFILER_API timestamp_t main_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS);

View File

@ -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 <easy/profiler_aux.h>
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