mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 08:41:02 +08:00
#91 [UI] .prof serializator (intermediate commit)
This commit is contained in:
parent
0b9ee4e6d0
commit
21bcefcb75
@ -62,11 +62,12 @@ profiler::block_index_t FileReader::readFile(const std::string& filename)
|
|||||||
profiler::blocks_t blocks;
|
profiler::blocks_t blocks;
|
||||||
profiler::thread_blocks_tree_t threaded_trees;
|
profiler::thread_blocks_tree_t threaded_trees;
|
||||||
|
|
||||||
|
profiler::processid_t pid = 0;
|
||||||
uint32_t total_descriptors_number = 0;
|
uint32_t total_descriptors_number = 0;
|
||||||
|
|
||||||
EASY_CONSTEXPR bool DoNotGatherStats = false;
|
EASY_CONSTEXPR bool DoNotGatherStats = false;
|
||||||
const auto blocks_number = ::fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors,
|
const auto blocks_number = ::fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors,
|
||||||
descriptors, blocks, threaded_trees, total_descriptors_number, m_version, DoNotGatherStats, m_errorMessage);
|
descriptors, blocks, threaded_trees, total_descriptors_number, m_version, pid, DoNotGatherStats, m_errorMessage);
|
||||||
|
|
||||||
if (blocks_number == 0)
|
if (blocks_number == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
274
easy_profiler_core/alignment_helpers.h
Normal file
274
easy_profiler_core/alignment_helpers.h
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
/************************************************
|
||||||
|
* creation time : 2017/08/20
|
||||||
|
* author : Blake Martin
|
||||||
|
* email : rationalcoder@gmail.com
|
||||||
|
************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
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_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
|
@ -45,9 +45,8 @@ 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 <cstddef>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "outstream.h"
|
#include "outstream.h"
|
||||||
|
#include "alignment_helpers.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -83,226 +82,6 @@ The Apache License, Version 2.0 (the "License");
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//! 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
template <const uint16_t N>
|
template <const uint16_t N>
|
||||||
class chunk_allocator
|
class chunk_allocator
|
||||||
{
|
{
|
||||||
|
@ -66,17 +66,18 @@
|
|||||||
* : limitations under the License.
|
* : limitations under the License.
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
#include <easy/reader.h>
|
|
||||||
#include <easy/profiler.h>
|
|
||||||
|
|
||||||
#include "hashed_cstr.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <easy/reader.h>
|
||||||
|
#include <easy/profiler.h>
|
||||||
|
|
||||||
|
#include "hashed_cstr.h"
|
||||||
|
#include "alignment_helpers.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
extern const uint32_t PROFILER_SIGNATURE;
|
extern const uint32_t PROFILER_SIGNATURE;
|
||||||
@ -1055,18 +1056,39 @@ struct BlocksRange
|
|||||||
{
|
{
|
||||||
profiler::block_index_t begin;
|
profiler::block_index_t begin;
|
||||||
profiler::block_index_t end;
|
profiler::block_index_t end;
|
||||||
};
|
|
||||||
|
|
||||||
struct BlocksAndCSwitchesRange
|
BlocksRange(profiler::block_index_t size = 0)
|
||||||
|
: begin(size), end(size)
|
||||||
{
|
{
|
||||||
BlocksRange blocks;
|
}
|
||||||
BlocksRange cswitches;
|
|
||||||
|
BlocksRange(profiler::block_index_t beginIndex, profiler::block_index_t endIndex)
|
||||||
|
: begin(beginIndex), end(endIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlocksMemoryAndCount
|
struct BlocksMemoryAndCount
|
||||||
{
|
{
|
||||||
uint64_t usedMemorySize = 0; // memory size used by profiler blocks
|
uint64_t usedMemorySize = 0; // memory size used by profiler blocks
|
||||||
profiler::block_index_t blocksCount = 0;
|
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>
|
template <typename T>
|
||||||
@ -1085,7 +1107,7 @@ BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler
|
|||||||
const profiler::block_getter_fn& getter)
|
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, size};
|
BlocksRange range(size);
|
||||||
|
|
||||||
auto first_it = std::lower_bound(children.begin(), children.end(), beginTime, [&](profiler::block_index_t element, profiler::timestamp_t value)
|
auto first_it = std::lower_bound(children.begin(), children.end(), beginTime, [&](profiler::block_index_t element, profiler::timestamp_t value)
|
||||||
{
|
{
|
||||||
@ -1122,6 +1144,92 @@ BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler
|
|||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children,
|
||||||
|
const BlocksRange& range,
|
||||||
|
const profiler::block_getter_fn& getter, 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 uint64_t 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,
|
||||||
|
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 = sizeof(profiler::SerializedCSwitch) + strlen(child.cs->name()) + 1;
|
||||||
|
memoryAndCount.usedMemorySize += usedMemorySize;
|
||||||
|
++memoryAndCount.blocksCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memoryAndCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize(profiler::SerializedData& output, uint64_t& position, const profiler::BlocksTree::children_t& children,
|
||||||
|
const BlocksRange& range, const profiler::block_getter_fn& getter, bool contextSwitches)
|
||||||
|
{
|
||||||
|
if (!contextSwitches)
|
||||||
|
{
|
||||||
|
// Serialize blocks
|
||||||
|
|
||||||
|
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()));
|
||||||
|
serialize(output, position, child.children, childRange, getter, false);
|
||||||
|
|
||||||
|
// Serialize self
|
||||||
|
const auto usedMemorySize = static_cast<uint16_t>(
|
||||||
|
sizeof(profiler::SerializedBlock) + strlen(child.node->name()) + 1);
|
||||||
|
|
||||||
|
unaligned_store16(output.data() + position, usedMemorySize);
|
||||||
|
memcpy(output.data() + position + sizeof(uint16_t), child.node, static_cast<size_t>(usedMemorySize));
|
||||||
|
|
||||||
|
// TODO: write valid block id (it can be dynamic)
|
||||||
|
|
||||||
|
position += usedMemorySize + sizeof(uint16_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize context switches
|
||||||
|
for (auto i = range.begin; i < range.end; ++i)
|
||||||
|
{
|
||||||
|
const auto& child = getter(children[i]);
|
||||||
|
|
||||||
|
const auto usedMemorySize = static_cast<uint16_t>(
|
||||||
|
sizeof(profiler::SerializedCSwitch) + strlen(child.cs->name()) + 1);
|
||||||
|
|
||||||
|
unaligned_store16(output.data() + position, usedMemorySize);
|
||||||
|
memcpy(output.data() + position + sizeof(uint16_t), child.cs, static_cast<size_t>(usedMemorySize));
|
||||||
|
|
||||||
|
position += usedMemorySize + sizeof(uint16_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
|
extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
|
||||||
const profiler::SerializedData& serialized_descriptors,
|
const profiler::SerializedData& serialized_descriptors,
|
||||||
profiler::block_id_t descriptors_count,
|
profiler::block_id_t descriptors_count,
|
||||||
@ -1172,17 +1280,25 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
|
|||||||
using ranges_t = std::unordered_map<profiler::thread_id_t, BlocksAndCSwitchesRange, estd::hash<profiler::thread_id_t> >;
|
using ranges_t = std::unordered_map<profiler::thread_id_t, BlocksAndCSwitchesRange, estd::hash<profiler::thread_id_t> >;
|
||||||
ranges_t block_ranges;
|
ranges_t block_ranges;
|
||||||
|
|
||||||
size_t counter = 0, i = 0;
|
// Calculate block ranges and used memory (for serialization)
|
||||||
|
size_t i = 0;
|
||||||
for (const auto& kv : trees)
|
for (const auto& kv : trees)
|
||||||
{
|
{
|
||||||
const auto id = kv.first;
|
const auto id = kv.first;
|
||||||
const auto& tree = kv.second;
|
const auto& tree = kv.second;
|
||||||
const auto childrenRange = findRange(tree.children, begin_time, end_time, block_getter);
|
|
||||||
const auto cswitcesRange = findRange(tree.sync, begin_time, end_time, block_getter);
|
|
||||||
|
|
||||||
counter += childrenRange.end - childrenRange.begin;
|
BlocksAndCSwitchesRange range;
|
||||||
counter += cswitcesRange.end - cswitcesRange.begin;
|
|
||||||
block_ranges[id] = BlocksAndCSwitchesRange {childrenRange, cswitcesRange};
|
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, false);
|
||||||
|
total += range.blocksMemoryAndCount;
|
||||||
|
|
||||||
|
range.cswitchesMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.sync, range.cswitches, block_getter, true);
|
||||||
|
total += range.cswitchesMemoryAndCount;
|
||||||
|
|
||||||
|
block_ranges[id] = range;
|
||||||
|
|
||||||
if (!update_progress_write(progress, 15 / static_cast<int>(trees.size() - i), log))
|
if (!update_progress_write(progress, 15 / static_cast<int>(trees.size() - i), log))
|
||||||
return 0;
|
return 0;
|
||||||
@ -1190,29 +1306,73 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counter == 0)
|
if (total.blocksCount == 0)
|
||||||
{
|
{
|
||||||
log << "Nothing to save";
|
log << "Nothing to save";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint64_t usedMemorySizeDescriptors = serialized_descriptors.size() + descriptors_count * sizeof(uint16_t);
|
||||||
|
|
||||||
|
// Write data to stream
|
||||||
write(str, PROFILER_SIGNATURE);
|
write(str, PROFILER_SIGNATURE);
|
||||||
write(str, EASY_CURRENT_VERSION);
|
write(str, EASY_CURRENT_VERSION);
|
||||||
write(str, pid);
|
write(str, pid);
|
||||||
|
|
||||||
// write 0 because we do not need to oncvert time from ticks to nanoseconds (it's already converted here)
|
// 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<int64_t>(str, 0LL); // CPU frequency
|
||||||
|
|
||||||
write(str, begin_time);
|
write(str, begin_time);
|
||||||
write(str, end_time);
|
write(str, end_time);
|
||||||
|
|
||||||
write(str, total.usedMemorySize);
|
write(str, total.usedMemorySize);
|
||||||
write(str, serialized_descriptors.size());
|
write(str, usedMemorySizeDescriptors);
|
||||||
write(str, total.blocksCount);
|
write(str, total.blocksCount);
|
||||||
write(str, descriptors_count);
|
write(str, descriptors_count);
|
||||||
|
|
||||||
log << "Not implemented";
|
// Serialize all descriptors
|
||||||
progress.store(100, std::memory_order_release);
|
// TODO
|
||||||
|
|
||||||
|
// Serialize all blocks
|
||||||
|
profiler::SerializedData serializedBlocks;
|
||||||
|
serializedBlocks.set(total.usedMemorySize + sizeof(uint16_t) * total.blocksCount);
|
||||||
|
uint64_t position = 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
write(str, range.cswitchesMemoryAndCount.blocksCount);
|
||||||
|
|
||||||
|
// Serialize context switches
|
||||||
|
write(str, range.cswitchesMemoryAndCount.blocksCount);
|
||||||
|
if (range.cswitchesMemoryAndCount.blocksCount != 0)
|
||||||
|
{
|
||||||
|
const auto previousPosition = position;
|
||||||
|
serialize(serializedBlocks, position, tree.sync, range.cswitches, block_getter, true);
|
||||||
|
write(str, serializedBlocks.data() + previousPosition, position - previousPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize blocks
|
||||||
|
write(str, range.blocksMemoryAndCount.blocksCount);
|
||||||
|
if (range.blocksMemoryAndCount.blocksCount != 0)
|
||||||
|
{
|
||||||
|
const auto previousPosition = position;
|
||||||
|
serialize(serializedBlocks, position, tree.children, range.blocks, block_getter, false);
|
||||||
|
write(str, serializedBlocks.data() + previousPosition, position - previousPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!update_progress_write(progress, 40 + 60 / static_cast<int>(trees.size() - i), log))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return total.blocksCount;
|
return total.blocksCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user