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

#0 [Core] refactoring

This commit is contained in:
Victor Zarubkin 2018-05-07 21:42:17 +03:00
parent 745609f1a4
commit 8c90ee7ef5
12 changed files with 1190 additions and 866 deletions

View File

@ -112,16 +112,21 @@ message(STATUS "")
################################################# #################################################
# Add source files: # Add source files:
set(CPP_FILES set(CPP_FILES
base_block_descriptor.cpp
block.cpp block.cpp
block_descriptor.cpp
easy_socket.cpp easy_socket.cpp
event_trace_win.cpp event_trace_win.cpp
nonscoped_block.cpp nonscoped_block.cpp
profile_manager.cpp profile_manager.cpp
profiler.cpp
reader.cpp reader.cpp
serialized_block.cpp
thread_storage.cpp thread_storage.cpp
) )
set(H_FILES set(H_FILES
block_descriptor.h
chunk_allocator.h chunk_allocator.h
current_time.h current_time.h
current_thread.h current_thread.h

View File

@ -0,0 +1,59 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2018 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.

View File

@ -0,0 +1,92 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2018 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
}

View File

@ -0,0 +1,86 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2018 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

View File

@ -45,7 +45,7 @@ The Apache License, Version 2.0 (the "License");
#include <easy/details/easy_compiler_support.h> #include <easy/details/easy_compiler_support.h>
#include <cstring> #include <cstring>
#include "outstream.h" #include <ostream>
#include "alignment_helpers.h" #include "alignment_helpers.h"
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -261,7 +261,7 @@ public:
\warning Data will be cleared after serialization. \warning Data will be cleared after serialization.
*/ */
void serialize(profiler::OStream& _outputStream) void serialize(std::ostream& _outputStream)
{ {
// Chunks are stored in reversed order (stack). // Chunks are stored in reversed order (stack).
// To be able to iterate them in direct order we have to invert the chunks list. // To be able to iterate them in direct order we have to invert the chunks list.

View File

@ -63,146 +63,6 @@
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#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
{
typedef cstring Parent;
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.
} // END of namespace profiler.
namespace std {
/** \brief Simply returns precalculated hash of a C-string. */
template <> struct hash<::profiler::hashed_cstr> {
typedef ::profiler::hashed_cstr argument_type;
typedef size_t result_type;
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)
#endif
namespace profiler { namespace profiler {
class hashed_stdstring class hashed_stdstring
@ -292,6 +152,155 @@ namespace std {
} // END of namespace std. } // 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
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -1,115 +0,0 @@
/************************************************************************
* file name : outstream.h
* ----------------- :
* creation time : 2016/09/11
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains definition of output stream helpers.
* ----------------- :
* change log : * 2016/09/11 Victor Zarubkin: Initial commit. Moved sources from profiler_manager.h/.cpp
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 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__OUTPUT_STREAM__H_
#define EASY_PROFILER__OUTPUT_STREAM__H_
#include <sstream>
#include <string.h>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
class OStream
{
::std::stringstream m_stream;
public:
explicit OStream() : m_stream(std::ios_base::out | std::ios_base::binary)
{
}
template <typename T> void write(const char* _data, T _size)
{
m_stream.write(_data, _size);
}
template <class T> void write(const T& _data)
{
m_stream.write((const char*)&_data, sizeof(T));
}
::std::stringstream& stream()
{
return m_stream;
}
const ::std::stringstream& stream() const
{
return m_stream;
}
void clear()
{
#if defined(__GNUC__) && __GNUC__ < 5
// gcc 4 has a known bug which has been solved in gcc 5:
// std::stringstream has no swap() method :(
m_stream.str(::std::string());
#else
::std::stringstream().swap(m_stream);
#endif
}
}; // END of class OStream.
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__OUTPUT_STREAM__H_

File diff suppressed because it is too large Load Diff

View File

@ -52,16 +52,17 @@ The Apache License, Version 2.0 (the "License");
#endif // _WIN32 #endif // _WIN32
#include "spin_lock.h" #include "spin_lock.h"
#include "outstream.h"
#include "hashed_cstr.h" #include "hashed_cstr.h"
#include "thread_storage.h" #include "thread_storage.h"
#include "current_time.h"
#include <atomic>
#include <map> #include <map>
#include <vector> #include <ostream>
#include <unordered_map> #include <unordered_map>
#include <thread> #include <thread>
#include <atomic>
#include <type_traits> #include <type_traits>
#include <vector>
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -69,7 +70,9 @@ using processid_t = uint64_t;
class BlockDescriptor; class BlockDescriptor;
namespace profiler { class ValueId; } namespace profiler {
class ValueId;
}
class ProfileManager class ProfileManager
{ {
@ -79,23 +82,27 @@ class ProfileManager
ProfileManager(); ProfileManager();
using atomic_timestamp_t = std::atomic<profiler::timestamp_t>; using atomic_timestamp_t = std::atomic<profiler::timestamp_t>;
using guard_lock_t = profiler::guard_lock<profiler::spin_lock>; using guard_lock_t = profiler::guard_lock<profiler::spin_lock>;
using map_of_threads_stacks = std::map<profiler::thread_id_t, ThreadStorage>; using map_of_threads_stacks = std::map<profiler::thread_id_t, ThreadStorage>;
using block_descriptors_t = std::vector<BlockDescriptor*>; using block_descriptors_t = std::vector<BlockDescriptor*>;
using descriptors_map_t = std::unordered_map<profiler::string_with_hash, profiler::block_id_t>;
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
using descriptors_map_t = std::unordered_map<profiler::hashed_cstr, profiler::block_id_t>;
#else
using descriptors_map_t = std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t>;
#endif
const processid_t m_processId; const processid_t m_processId;
#if defined(EASY_CHRONO_CLOCK) || defined(_WIN32)
const int64_t m_cpuFrequency;
#endif
map_of_threads_stacks m_threads; map_of_threads_stacks m_threads;
block_descriptors_t m_descriptors; block_descriptors_t m_descriptors;
descriptors_map_t m_descriptorsMap; descriptors_map_t m_descriptorsMap;
uint64_t m_descriptorsMemorySize; 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_beginTime;
profiler::timestamp_t m_endTime; profiler::timestamp_t m_endTime;
atomic_timestamp_t m_frameMax; atomic_timestamp_t m_frameMax;
@ -114,13 +121,8 @@ class ProfileManager
std::string m_csInfoFilename = "/tmp/cs_profiling_info.log"; std::string m_csInfoFilename = "/tmp/cs_profiling_info.log";
uint32_t dumpBlocksToStream(profiler::OStream& _outputStream, bool _lockSpin, bool _async); std::thread m_listenThread;
void setBlockStatus(profiler::block_id_t _id, profiler::EasyBlockStatus _status); std::atomic_bool m_stopListen;
std::thread m_listenThread;
void listen(uint16_t _port);
std::atomic_bool m_stopListen;
public: public:
@ -147,6 +149,7 @@ public:
void beginBlock(profiler::Block& _block); void beginBlock(profiler::Block& _block);
void beginNonScopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName); void beginNonScopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
void endBlock(); void endBlock();
profiler::timestamp_t maxFrameDuration(); profiler::timestamp_t maxFrameDuration();
profiler::timestamp_t avgFrameDuration(); profiler::timestamp_t avgFrameDuration();
profiler::timestamp_t curFrameDuration() const; profiler::timestamp_t curFrameDuration() const;
@ -162,15 +165,8 @@ public:
const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard); const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard);
const char* registerThread(const char* name); const char* registerThread(const char* name);
void setContextSwitchLogFilename(const char* name) void setContextSwitchLogFilename(const char* name);
{ const char* getContextSwitchLogFilename() const;
m_csInfoFilename = name;
}
const char* getContextSwitchLogFilename() const
{
return m_csInfoFilename.c_str();
}
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 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 endContextSwitch(profiler::thread_id_t _thread_id, processid_t _process_id, profiler::timestamp_t _endtime, bool _lockSpin = true);
@ -178,8 +174,24 @@ public:
void stopListen(); void stopListen();
bool isListening() const; 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: 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 registerThread();
void beginFrame(); void beginFrame();
@ -196,13 +208,13 @@ private:
ThreadStorage& _threadStorage(profiler::thread_id_t _thread_id); ThreadStorage& _threadStorage(profiler::thread_id_t _thread_id);
ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id); ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id);
inline ThreadStorage& threadStorage(profiler::thread_id_t _thread_id) ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
{ {
guard_lock_t lock(m_spin); guard_lock_t lock(m_spin);
return _threadStorage(_thread_id); return _threadStorage(_thread_id);
} }
inline ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id) ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
{ {
guard_lock_t lock(m_spin); guard_lock_t lock(m_spin);
return _findThreadStorage(_thread_id); return _findThreadStorage(_thread_id);

View File

@ -0,0 +1,348 @@
/************************************************************************
* 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-2018 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 "current_time.h"
#include "profile_manager.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 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".

View File

@ -80,14 +80,18 @@
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
extern const uint32_t PROFILER_SIGNATURE; extern const uint32_t EASY_PROFILER_SIGNATURE;
extern const uint32_t EASY_CURRENT_VERSION; extern const uint32_t EASY_PROFILER_VERSION;
# define EASY_VERSION_INT(v_major, v_minor, v_patch) ((static_cast<uint32_t>(v_major) << 24) | \
(static_cast<uint32_t>(v_minor) << 16) | \
static_cast<uint32_t>(v_patch))
EASY_CONSTEXPR uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///< minimal compatible version (.prof file format was not changed seriously since this version)
EASY_CONSTEXPR uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file
EASY_CONSTEXPR uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t
EASY_CONSTEXPR uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged
# define EASY_VERSION_INT(v_major, v_minor, v_patch) ((static_cast<uint32_t>(v_major) << 24) | (static_cast<uint32_t>(v_minor) << 16) | static_cast<uint32_t>(v_patch))
const uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///< minimal compatible version (.prof file format was not changed seriously since this version)
const uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file
const uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t
const uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged
# undef EASY_VERSION_INT # undef EASY_VERSION_INT
const uint64_t TIME_FACTOR = 1000000000ULL; const uint64_t TIME_FACTOR = 1000000000ULL;
@ -120,7 +124,7 @@ const uint64_t TIME_FACTOR = 1000000000ULL;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
inline bool isCompatibleVersion(uint32_t _version) static bool isCompatibleVersion(uint32_t _version)
{ {
return _version >= MIN_COMPATIBLE_VERSION; return _version >= MIN_COMPATIBLE_VERSION;
} }
@ -243,24 +247,9 @@ namespace profiler {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
using StatsMap = std::unordered_map<profiler::block_id_t, profiler::BlockStatistics*, estd::hash<profiler::block_id_t> >;
/** \note It is absolutely safe to use hashed_cstr (which simply stores pointer) because std::unordered_map,
which uses it as a key, exists only inside fillTreesFromFile function. */
using IdMap = std::unordered_map<profiler::hashed_cstr, profiler::block_id_t>;
using CsStatsMap = std::unordered_map<profiler::hashed_cstr, profiler::BlockStatistics*>;
#else
// TODO: Create optimized version of profiler::hashed_cstr for Linux too.
using StatsMap = std::unordered_map<profiler::block_id_t, profiler::BlockStatistics*, estd::hash<profiler::block_id_t> >; using StatsMap = std::unordered_map<profiler::block_id_t, profiler::BlockStatistics*, estd::hash<profiler::block_id_t> >;
using IdMap = std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t>; using IdMap = std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t>;
using CsStatsMap = std::unordered_map<profiler::hashed_stdstring, profiler::BlockStatistics*>; using CsStatsMap = std::unordered_map<profiler::string_with_hash, profiler::BlockStatistics*>;
#endif
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -438,7 +427,7 @@ struct EasyFileHeader
uint32_t total_descriptors_number = 0; uint32_t total_descriptors_number = 0;
}; };
bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log) static bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log)
{ {
// File header before v2.0.0 // File header before v2.0.0
@ -491,7 +480,7 @@ bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::ostream&
return true; return true;
} }
bool readHeader_v2(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log) static bool readHeader_v2(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log)
{ {
// File header after v2.0.0 // File header after v2.0.0
@ -587,7 +576,7 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
uint32_t signature = 0; uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t)); inFile.read((char*)&signature, sizeof(uint32_t));
if (signature != PROFILER_SIGNATURE) if (signature != EASY_PROFILER_SIGNATURE)
{ {
_log << "Wrong signature " << signature << "\nThis is not EasyProfiler file/stream."; _log << "Wrong signature " << signature << "\nThis is not EasyProfiler file/stream.";
return 0; return 0;
@ -1064,7 +1053,7 @@ extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progre
uint32_t signature = 0; uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t)); inFile.read((char*)&signature, sizeof(uint32_t));
if (signature != PROFILER_SIGNATURE) if (signature != EASY_PROFILER_SIGNATURE)
{ {
_log << "Wrong file signature.\nThis is not EasyProfiler file/stream."; _log << "Wrong file signature.\nThis is not EasyProfiler file/stream.";
return false; return false;
@ -1174,19 +1163,19 @@ struct BlocksAndCSwitchesRange
}; };
template <typename T> template <typename T>
inline void write(std::ostream& _stream, const char* _data, T _size) static void write(std::ostream& _stream, const char* _data, T _size)
{ {
_stream.write(_data, _size); _stream.write(_data, _size);
} }
template <class T> template <class T>
inline void write(std::ostream& _stream, const T& _data) static void write(std::ostream& _stream, const T& _data)
{ {
_stream.write((const char*)&_data, sizeof(T)); _stream.write((const char*)&_data, sizeof(T));
} }
BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler::timestamp_t beginTime, profiler::timestamp_t endTime, static BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler::timestamp_t beginTime,
const profiler::block_getter_fn& getter) profiler::timestamp_t endTime, const profiler::block_getter_fn& getter)
{ {
const auto size = static_cast<profiler::block_index_t>(children.size()); const auto size = static_cast<profiler::block_index_t>(children.size());
BlocksRange range(size); BlocksRange range(size);
@ -1226,11 +1215,11 @@ BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler
return range; return range;
} }
BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children, static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children,
const BlocksRange& range, const BlocksRange& range,
const profiler::block_getter_fn& getter, const profiler::block_getter_fn& getter,
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
bool contextSwitches) bool contextSwitches)
{ {
BlocksMemoryAndCount memoryAndCount; BlocksMemoryAndCount memoryAndCount;
@ -1275,9 +1264,9 @@ BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTre
return memoryAndCount; return memoryAndCount;
} }
void serializeBlocks(std::ostream& output, std::vector<char>& buffer, const profiler::BlocksTree::children_t& children, static void serializeBlocks(std::ostream& output, std::vector<char>& buffer,
const BlocksRange& range, const profiler::block_getter_fn& getter, const profiler::BlocksTree::children_t& children, const BlocksRange& range,
const profiler::descriptors_list_t& descriptors) const profiler::block_getter_fn& getter, const profiler::descriptors_list_t& descriptors)
{ {
for (auto i = range.begin; i < range.end; ++i) for (auto i = range.begin; i < range.end; ++i)
{ {
@ -1319,8 +1308,9 @@ void serializeBlocks(std::ostream& output, std::vector<char>& buffer, const prof
} }
} }
void serializeContextSwitches(std::ostream& output, std::vector<char>& buffer, const profiler::BlocksTree::children_t& children, static void serializeContextSwitches(std::ostream& output, std::vector<char>& buffer,
const BlocksRange& range, const profiler::block_getter_fn& getter) const profiler::BlocksTree::children_t& children, const BlocksRange& range,
const profiler::block_getter_fn& getter)
{ {
for (auto i = range.begin; i < range.end; ++i) for (auto i = range.begin; i < range.end; ++i)
{ {
@ -1337,9 +1327,9 @@ void serializeContextSwitches(std::ostream& output, std::vector<char>& buffer, c
} }
} }
void serializeDescriptors(std::ostream& output, std::vector<char>& buffer, static void serializeDescriptors(std::ostream& output, std::vector<char>& buffer,
const profiler::descriptors_list_t& descriptors, const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count) profiler::block_id_t descriptors_count)
{ {
const size_t size = std::min(descriptors.size(), static_cast<size_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) for (size_t i = 0; i < size; ++i)
@ -1461,8 +1451,8 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
const uint64_t usedMemorySizeDescriptors = serialized_descriptors.size() + descriptors_count * sizeof(uint16_t); const uint64_t usedMemorySizeDescriptors = serialized_descriptors.size() + descriptors_count * sizeof(uint16_t);
// Write data to stream // Write data to stream
write(str, PROFILER_SIGNATURE); write(str, EASY_PROFILER_SIGNATURE);
write(str, EASY_CURRENT_VERSION); write(str, EASY_PROFILER_VERSION);
write(str, pid); write(str, pid);
// write 0 because we do not need to convert time from ticks to nanoseconds (it's already converted) // write 0 because we do not need to convert time from ticks to nanoseconds (it's already converted)

View File

@ -0,0 +1,68 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2018 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.