Giter VIP home page Giter VIP logo

easy_profiler's Introduction

easy_profiler 2.1.0 2.x.x

Build Status Build Status

License: MIT License

  1. About
  2. Key features
  3. Usage
  4. Build
  5. Notes about major release (1.0 -> 2.0)
  6. License

About

Lightweight cross-platform profiler library for c++

You can profile any function in you code. Furthermore this library provide measuring time of any block of code. For example, information for 12 millions of blocks is using less than 300Mb of memory. Working profiler slows your application execution for only 1-2%.

Block time Average overhead per block is about 15ns/block (tested on Intel Core i7-5930K 3.5GHz, Win7)

Disabled profiler will not affect your application execution in any way. You can leave it in your Release build and enable it at run-time at any moment during application launch to see what is happening at the moment.

Also the library can capture system's context switch events between threads. Context switch information includes duration, target thread id, thread owner process id, thread owner process name.

You can see the results of measuring in simple GUI application which provides full statistics and renders beautiful time-line.

GUI screenshot Profiling CryEngine SDK example

New UI Style New UI style in version 2.0

Key features

  • Extremely low overhead
  • Low additional memory usage
  • Cross-platform
  • Profiling over network
  • Capture thread context-switch events
  • Store user variables (both single values and arrays)
  • GUI could be connected to an application which is already profiling (so you can profile initialization of your application)
  • Monitor main thread fps at real-time in GUI even if profiling is disabled or draw your own HUD/fps-plot directly in your application using data provided by profiler
  • Save a snapshot (selected area) of profiled data from file
  • Add bookmarks at any place on the timeline
  • Configurable timer type with CMakeLists or preprocessor macros

Usage

Integration

General

First of all you can specify path to include directory which contains include/profiler directory and define macro BUILD_WITH_EASY_PROFILER. For linking with easy_profiler you can specify path to library.

If using CMake

If you are using cmake set CMAKE_PREFIX_PATH to lib/cmake/easy_profiler directory (from release package) and use function find_package(easy_profiler) with target_link_libraries(... easy_profiler).

Example:

project(my_application)

set(SOURCES
    main.cpp
)

# CMAKE_PREFIX_PATH should be set to <easy_profiler-release_dir>/lib/cmake/easy_profiler
find_package(easy_profiler REQUIRED)  # STEP 1 #########################

add_executable(my_application ${SOURCES})

target_link_libraries(my_application easy_profiler)  # STEP 2 ##########

Inserting blocks

Example of usage.

#include <easy/profiler.h>

void foo() {
    EASY_FUNCTION(profiler::colors::Magenta); // Magenta block with name "foo"

    EASY_BLOCK("Calculating sum"); // Begin block with default color == Amber100
    int sum = 0;
    for (int i = 0; i < 10; ++i) {
        EASY_BLOCK("Addition", profiler::colors::Red); // Scoped red block (no EASY_END_BLOCK needed)
        sum += i;
    }
    EASY_END_BLOCK; // End of "Calculating sum" block

    EASY_BLOCK("Calculating multiplication", profiler::colors::Blue500); // Blue block
    int mul = 1;
    for (int i = 1; i < 11; ++i)
        mul *= i;
    //EASY_END_BLOCK; // This is not needed because all blocks are ended on destructor when closing braces met
}

void bar() {
    EASY_FUNCTION(0xfff080aa); // Function block with custom ARGB color
}

void baz() {
    EASY_FUNCTION(); // Function block with default color == Amber100
}

EasyProfiler is using Google Material-Design colors palette, but you can use custom colors in ARGB format (like shown in example above).
The default color is Amber100 (it is used when you do not specify color explicitly).

Storing variables

Example of storing variables:

#include <easy/profiler.h>
#include <easy/arbitrary_value.h> // EASY_VALUE, EASY_ARRAY are defined here

class Object {
    Vector3 m_position; // Let's suppose Vector3 is a struct { float x, y, z; };
    unsigned int  m_id;
public:
    void act() {
        EASY_FUNCTION(profiler::colors::Cyan);

        // Dump variables values
        constexpr auto Size = sizeof(Vector3) / sizeof(float);
        EASY_VALUE("id", m_id);
        EASY_ARRAY("position", &m_position.x, Size, profiler::color::Red);

        // Do something ...
    }

    void loop(uint32_t N) {
        EASY_FUNCTION();
        EASY_VALUE("N", N, EASY_VIN("N")); /* EASY_VIN is used here to ensure
                                            that this value id will always be
                                            the same, because the address of N
                                            can change */
        for (uint32_t i = 0; i < N; ++i) {
            // Do something
        }
    }
};

Collect profiling data

There are two ways to collect profiling data: streaming over network and dumping data to file.

Streaming over network

This is the most preferred and convenient method in many cases.

  1. (In profiled app) Invoke profiler::startListen(). This will start new thread to listen 28077 port for the start-capture-signal from profiler_gui.
  2. (In UI) Connect profiler_gui to your application using hostname or IP-address.
  3. (In UI) Press Start capture button in profiler_gui.
  4. (In UI) Press Stop capture button in profiler_gui to stop capturing and wait until profiled data will be passed over network.
  5. (Optional step)(In profiled app) Invoke profiler::stopListen() to stop listening.

Example:

void main() {
    profiler::startListen();
    /* do work */
}

Dump to file

  1. (Profiled application) Start capturing by putting EASY_PROFILER_ENABLE macro somewhere into the code.
  2. (Profiled application) Dump profiled data to file in any place you want by profiler::dumpBlocksToFile("test_profile.prof") function.

Example:

void main() {
    EASY_PROFILER_ENABLE;
    /* do work */
    profiler::dumpBlocksToFile("test_profile.prof");
}

Note about thread context-switch events

To capture a thread context-switch events you need:

  • On Windows: launch your application "as Administrator"
  • On Linux: you can launch special systemtap script with root privileges as follow (example on Fedora):
#stap -o /tmp/cs_profiling_info.log scripts/context_switch_logger.stp name APPLICATION_NAME

APPLICATION_NAME - name of your application

There are some known issues on a linux based systems (for more information see wiki)

Profiling application startup

To profile your application startup (when using network method) add EASY_PROFILER_ENABLE macro into the code together with profiler::startListen().

Example:

void main() {
    EASY_PROFILER_ENABLE;
    profiler::startListen();
    /* do work */
}

This will allow you to collect profiling data before profiler_gui connection. profiler_gui will automatically display capturing dialog window after successful connection to the profiled application.

Build

Prerequisites

  • CMake 3.0 or higher
  • Compiler with c++11 support
    • for Unix systems: compiler with thread_local support is highly recommended: GCC >=4.8, Clang >=3.3

Additional requirements for GUI:

  • Qt 5.3.0 or higher

Linux

$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE="Release" ..
$ make

MacOS

$ mkdir build
$ cd build
$ cmake -DCMAKE_CXX_COMPILER=g++-5 -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_BUILD_TYPE="Release" ..
$ make

Windows

If you are using QtCreator IDE you can just open CMakeLists.txt file in root directory. If you are using Visual Studio you can generate solution by cmake generator command. Examples shows how to generate Win64 solution for Visual Studio 2013. To generate for another version use proper cmake generator (-G "name of generator").

Way 1

Specify path to cmake scripts in Qt5 dir (usually in lib/cmake subdir) and execute cmake generator command, for example:

$ mkdir build
$ cd build
$ cmake -DCMAKE_PREFIX_PATH="C:\Qt\5.3\msvc2013_64\lib\cmake" .. -G "Visual Studio 12 2013 Win64"

Way 2

Create system variable "Qt5Widgets_DIR" and set it's value to "[path-to-Qt5-binaries]\lib\cmake\Qt5Widgets". For example, "C:\Qt\5.3\msvc2013_64\lib\cmake\Qt5Widgets". And then run cmake generator as follows:

$ mkdir build
$ cd build
$ cmake .. -G "Visual Studio 12 2013 Win64"

QNX

$ souce $QNX_ENVIRONMENT
$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/QNXToolchain.cmake ..

For more information and example for QNXToolchain.cmake see this PR

Android

You can build native library for android by using NDK and standalone toolchain. See comment for this PR to get a more detailed instruction.

Status

Branch develop contains all v2.0.0 features and new UI style.
Please, note that .prof file header has changed in v2.0.0:

struct EasyFileHeader {
    uint32_t signature = 0;
    uint32_t version = 0;
    profiler::processid_t pid = 0;
    int64_t cpu_frequency = 0;
    profiler::timestamp_t begin_time = 0;
    profiler::timestamp_t end_time = 0;
    
    // Changed order of memory_size and blocks_number relative to v1.3.0
    uint64_t memory_size = 0;
    uint64_t descriptors_memory_size = 0;
    uint32_t total_blocks_number = 0;
    uint32_t total_descriptors_number = 0;
};

License

Licensed under either of

at your option.

easy_profiler's People

Contributors

cas4ey avatar cdserg avatar corporateshark avatar derevnja avatar devnoname120 avatar joshengebretson avatar jrlanglois avatar karimnaaji avatar liareth avatar lordofbikes avatar mean-ui-thread avatar mrautio avatar rationalcoder avatar rokups avatar silveryard avatar sirver avatar tals avatar tkalbitz avatar uykusuz avatar valeriovarricchio avatar yse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easy_profiler's Issues

Design problem with StackBuffer

I am in the progress of integrating easy_profiler to AtomicGameEngine. In the process we bumped into several nasty issues which i think should be addressed. Profiler does not build on MacOS platform or on windows with MSVC compiler. We worked out some patches and will submit PR once code is in shape.

Now on to a real problem:

MacOS is having a hard time (meaning crash) due to manual string destructor invocation. This right there is a sign of very bad design and needs to be addressed.

I started digging deeper into the problem and discovered that this destructor call is a result of custom StackBuffer class. As i understand this class was created due to performance reasons, but i think it is completely not necessary. Did you try using std::vector? We can minimize memory reallocations by reserving space in a vector. I usually reserve double of vector size when capacity is reached. It wastes some memory, but progressively reduces memory reallocations and we can use RAII and not need ugly manual calls to destructors. To avoid copying on insertion we can just .push_back(std::move(NonscopedBlock(...))). This should perform much the same as StackBuffer except so much more safer and cleaner.

I started changing StackBuffer to std::vector and noticed that move constructor of Block modifies state of object it is stealing state from. Why? Move constructor is supposed to steal state from the other object and that leaves this object in undetermined state, basically destined for a trashcan. Here something else is happening which seems very wrong. I do not think i can fix this problem without understanding why it was written this way.

Code base mixes dos and unix line ending files.

For example, just looking at the cpp files, most are UNIX line terminators, but some have CRLF (dos) line terminators.

$ find . -name '*.cpp' -exec file {} \;
./sample/main.cpp: C source, ASCII text, with CRLF line terminators
./easy_profiler_core/event_trace_win.cpp: C source, ASCII text, with CRLF line terminators
./easy_profiler_core/easy_socket.cpp: C source, ASCII text
./easy_profiler_core/block.cpp: C source, ASCII text
./easy_profiler_core/profile_manager.cpp: C source, ASCII text
./easy_profiler_core/reader.cpp: C++ source, ASCII text
./profiler_gui/descriptors_tree_widget.cpp: C source, ASCII text, with CRLF, LF line terminators
./profiler_gui/easy_qtimer.cpp: C source, ASCII text
./profiler_gui/globals.cpp: C source, ASCII text
./profiler_gui/treeitem.cpp: C source, ASCII text
./profiler_gui/easy_graphics_item.cpp: C source, ASCII text, with very long lines
./profiler_gui/main.cpp: C source, ASCII text
./profiler_gui/treemodel.cpp: C source, ASCII text
./profiler_gui/blocks_graphics_view.cpp: C++ source, ASCII text, with CRLF, LF line terminators
./profiler_gui/tree_widget_item.cpp: C source, ASCII text
./profiler_gui/globals_qobjects.cpp: C source, ASCII text
./profiler_gui/blocks_tree_widget.cpp: C source, ASCII text, with CRLF, LF line terminators
./profiler_gui/easy_graphics_scrollbar.cpp: C source, ASCII text, with CRLF, LF line terminators
./profiler_gui/main_window.cpp: C source, ASCII text, with CRLF, LF line terminators
./profiler_gui/easy_chronometer_item.cpp: C source, ASCII text
./profiler_gui/tree_widget_loader.cpp: C source, ASCII text, with very long lines, with CRLF, LF line terminators
./reader/main.cpp: C++ source, ASCII text

First connect always fails

As title says - first attempt to connect to profiled application always fails. Second attempt works.

Edit:
I might add that this code loop keeps spinning endlessly when there is no connection. Judging from EASY_LOGMSG("GUI-client connected\n"); i do not think that is what you intended as it would be spamming that message when nothing connects. Maybe this is related?

Fix problems after changing thread_id_t

There are several problems because of changing thread_id_t from uint32_t to uint64_t referenced mainly to context-switch events on *nix systems with 64-bit pid_t

Document Stream Format

I'm having an issue with a serialized block size having a zero in it, despite there actually being a block there. I'm having a really hard time debugging it without fully understanding the contents of a stream.

CMakeLists.txt does not respect BUILD_SHARED_LIBS argument

The standard cmake argument for building a library as shared or static is BUILD_SHARED_LIBS. This would replace the EASY_OPTION_LIB_STATIC and EASY_OPTION_LIB_TYPE allowing more idiomatic usage of cmake. This is important for integration with package managers such as hunter which expect this argument to be honored. If you are happy with this change then I will create a pull request.

MinGW builds/binary compatibility

Hey, this library/program looks quite promising but sadly, I was not able to use it though using mingw w64, gcc-7 and release v1.2.0.
To use mingw i built the library from source but when trying to record blocks using the program (which i downloaded from the same release since i don't have qt installed and am not sure how to get it to work with mingw) i always received the error

Can not read profiled blocks
Reason:
Profiled blocks number == 0

When trying to dump the blocks to a file at the end of the program, the profiler::dumpBlocksToFile("file.prof"); call seems to get stuck (everytime i checked with gdb the thread was in a std::this_thread::sleep_for call triggered by this call).

Not sure how you serialize the blocks, but may it require binary compatibility between the viewer program and the library? If so, is it possible to package mingw releases with the next release? Would be really awesome!

Otherwise, do you have any ideas how to fix this?
Thanks for any help.

Empty Hierarchy

After loading *.prof file in the GUI. I can see the Diagram, but Hierarchy is empty.

Unscoped thread crashes when dumping blocks

Version:

Public v1.2.0, built locally with source and integrated into my project that way (rather than with the provided static libraries).

Callstack:

easy_profiler.dll!operator` delete(void * block) Line 21 C++ easy_profiler.dll!std::_Deallocate(void * _Ptr, unsigned __int64 _Count, unsigned __int64 _Sz) Line 133 C++ easy_profiler.dll!std::allocator<std::reference_wrapper<profiler::Block> >::deallocate(std::reference_wrapper<profiler::Block> * _Ptr, unsigned __int64 _Count) Line 721 C++ easy_profiler.dll!std::_Wrap_alloc<std::allocator<std::reference_wrapper<profiler::Block> > >::deallocate(std::reference_wrapper<profiler::Block> * _Ptr, unsigned __int64 _Count) Line 988 C++ easy_profiler.dll!std::vector<std::reference_wrapper<profiler::Block>,std::allocator<std::reference_wrapper<profiler::Block> > >::_Reallocate(unsigned __int64 _Count) Line 1619 C++ easy_profiler.dll!std::vector<std::reference_wrapper<profiler::Block>,std::allocator<std::reference_wrapper<profiler::Block> > >::_Reserve(unsigned __int64 _Count) Line 1633 C++ easy_profiler.dll!std::vector<std::reference_wrapper<profiler::Block>,std::allocator<std::reference_wrapper<profiler::Block> > >::emplace_back<profiler::Block & __ptr64>(profiler::Block & <_Val_0>) Line 928 C++ easy_profiler.dll!ProfileManager::beginBlock(profiler::Block & _block) Line 968 C++ easy_profiler.dll!beginBlock(profiler::Block & _block) Line 304 C++ TomatoGame.exe!Katgine::App::Win32AppWindow::Run(Katgine::App::IApp * app) Line 81 C++ ...

Steps to reproduce:

  1. Have two threads, Win32 and Game. Win32 is declared with EASY_THREAD("Win32"), and the game thread is declared with EASY_THREAD("Main"). Note that this bug only occurs when the Win32 thread is not guarded with a scoped thread.
  2. The Win32 thread is blocking in the Win32 message loop, e.g. sending no data, but it has sent data since starting, so the THIS_THREAD is correct.
  3. The main thread is sending data regularly, e.g. once every 16 ms but the interval really doesn't matter.
  4. Connect over the network and gather data.
  5. Observe that no data is captured on the Win32 thread because the thread is still blocking.
  6. End network capture of the data.
  7. Notice how ProfileManager::dumpBlocksToStream is called, and the Win32 thread is removed from m_threads at line 1429.
  8. Mouse over the window, which causes the Win32 message loop to leave its blocked state, and data is once again captured on that thread.
  9. Observe crash because THIS_THREAD is now pointing to freed memory, because the thread has been freed, but not reallocated because THIS_THREAD was never set to null.

Workaround:

  1. Use scoped thread macro instead, which marks the thread as guarded so it isn't freed when blocks are dumped by the network profiler.

Possible solutions:

  1. m_threads now stores pointers to pointers, which would allow the code which removes threads from the collection to also nullify the thread-local storage pointer. This may be an issue though because I bet thread-local storage is freed when a thread dies, so you can't nullify the pointer without a segfault.
  2. Do not free threads for unscoped threads when dumping blocks.
  3. Removed unguarded thread support. (Extreme!)

Не запускается profiler_gui под Linux

Вывод:
./profiler_gui: error while loading shared libraries: libeasy_profiler.so: cannot open shared object file: No such file or directory

вот что ldd показывает:
libeasy_profiler.so => not found
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f94f917e000)
libQt5Gui.so.5 => /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5 (0x00007f94f8c36000)
libQt5Core.so.5 => /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 (0x00007f94f8760000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f94f83dd000)
Библиотеки эти я вижу в папке с бинарником.
Возможно, использование в CMake команды link_directories(directory1 directory2 ...) решит проблему.

Starting and ending a block from two functions

Hi,

I'm wanting to start and end a block manually in two functions. I want to use the GCC API for start and end functions so I don't have to add the easy_profiler macros to every function call.

Something like:

void __cyg_profile_func_enter(void* this_fn, void* call_site){
	const char* symbol = "";
	Dl_info info;
	if(dladdr(this_fn, &info) && info.dli_sname){
		symbol = info.dli_sname;
	}

	int status = 0;

	char* demangled = __cxxabiv1::__cxa_demangle(symbol, 0, 0, &status);
	EASY_PROFILE_BLOCK_START(demangled != NULL && status == 0 ? demangled : symbol);
	infunc = false;
}

void __cyg_profile_func_exit(void* this_fn, void* call_site){
	EASY_PROFILE_BLOCK_END();
}

Is this possible?

QFont intialized before QApplication causes segfault with static Qt

Initialization of fonts before QApplication is not valid and causes a segfault when linking statically against Qt. This is caused by the initialization of non-local variables before main. eg.

const auto BG_FONT = ::profiler_gui::EFont("Helvetica", 10, QFont::Bold);

This can be fixed by replacing the above with

auto const & BG_FONT() { static const auto BG_FONT = ::profiler_gui::EFont("Helvetica", 10, QFont::Bold); return BG_FONT; }

API for extracting cached information from profiler

Since Urho3D maintainers are not interested in making use of easy_profiler i no longer maintain integration. There is however some interest from AtomicGameEngine community. However they want to maintain on-screen display of recent profiling data snapshot.

We already discussed ability to get data tree at runtime in Urho3D forum. But could we get API to receive cached profiling data anyway? Does not have to be anything fancy, just a dump of blocks profiler collected on last frame. Then i could use that to build a tree real-time for display on the screen.

Test std::chrono timers

Run tests using std::chrono timers for gcc 5, gcc 6 and msvc2015 builds to calculate block cost using c++11 standard timers on modern compilers.
For gcc 4 and msvc2013 it was very high cost: ~0.6-0.8 us per block.

Profiler freezes on reconnect

Reconnecting seems to be broken as profiler application freezes on reconnect. Closing game window does not terminate process as background music can still be heard even if window disappears. Terminating frozen profiler application makes game process exit completely.

Steps to reproduce:

  1. Start profiler and profiled application
  2. Hit Connect button in profiler - data is gathered properly
  3. Hit Stop button in profiler - data is displayed properly
  4. Hit Disconnect button in profiler - shouldnt profiler disconnect in previous step?
  5. Hit Connect button in profiler - profiler is frozen

I should also point out is that we added this fix to get profiler into working order. For some reason without this loop profiler freezes on very first attempt to connect to a running application. Killing profiled application shows message that profiler could not connect. This was tested on linux and macos. While i test things with our little bit modified version our mods should not have any impact as they are pretty much all for macos + this loop i just linked.

Create, begin, end, store blocks manually

Hi,

thanks for your awesome tool.
I love it so much that I am planning to (ab)using it in a slightly different way.
I would like to measure the execution of tasks and not just functions/methods.

Ideally I need to be able to manually do the following operations:

  1. Create a profile::Block
  2. Start() it manually.
  3. Call manually finish()

In other words, I don't want the ProfilerManager to take care of this for me, but, on the other hand, ProfilerManager is the one that provides the socket interface and dump to file.

I am positive that what I described can be done, but it would be nice if you can give any hint

Regards

Davide

why hierarchy is empty?

the thread timeline is correct, but the hierarchy is empty.
i use easy_function and easy_block.
need set something?
Thanks.

Подготовить к релизу запускаемый файл для win-платформы

В релизную сборку необходимо:

  • Инициализировать приложение как оконную подсистему. Для этого корректно расставить макросы вокруг строчки https://github.com/yse/easy_profiler/blob/develop/profiler_gui/main.cpp#L51

  • Создать rc-файл, куда прописать издателя и текущую версию

"INFO: GUI-client connected" spam

When lib is built with -DEASY_OPTION_LOG=ON profiled application spams this at high speed:

EasyProfiler INFO: GUI-client connected

Nothing is connecting to it.

Memory Leaking

I've just started to add some blocks into my code, and I currently have the following function which runs fine, no leaking memory.

void Renderer::RenderLines()
{
#ifdef _PROFILE
	EASY_FUNCTION(profiler::colors::Amber);
#endif

	m_API->SetBlendState(eBlendStates::NO_BLEND);
	m_API->SetRasterizer(eRasterizer::CULL_NONE);

	ID3D11RenderTargetView* backbuffer = m_API->GetBackbuffer();
	ID3D11DepthStencilView* depth = m_DeferredRenderer->GetDepthStencil()->GetDepthView();
	m_API->GetContext()->OMSetRenderTargets(1, &backbuffer, depth);

	const auto commands = mySynchronizer->GetRenderCommands(eBufferType::LINE_BUFFER);
#ifdef _PROFILE
	EASY_BLOCK("LineCommand", profiler::colors::Red);
#endif
	for (s32 i = 0; i < commands.Size(); i++)
	{
		auto command = reinterpret_cast<LineCommand*>(commands[i]);
		m_API->SetDepthStencilState(command->m_ZEnabled ? eDepthStencilState::Z_ENABLED : eDepthStencilState::Z_DISABLED, 1);
		m_Line->Update(command->m_Points[0], command->m_Points[1]);
		m_Line->Render(m_Camera->GetOrientation(), m_Camera->GetPerspective());
	}
#ifdef _PROFILE
	EASY_END_BLOCK;
#endif

	m_API->SetBlendState(eBlendStates::NO_BLEND);
	m_API->SetDepthStencilState(eDepthStencilState::Z_ENABLED, 1);
	m_API->SetRasterizer(eRasterizer::CULL_BACK);
}

But when I add another block inside the already existing block, it can be EASY_BLOCK( foo ); or EASY_FUNCTION( bar ); both of them creates a memory leak in my application.

#ifdef _PROFILE
	EASY_BLOCK("LineCommand", profiler::colors::Red);
#endif
	for (s32 i = 0; i < commands.Size(); i++)
	{
#ifdef _PROFILE
                EASY_BLOCK("InsideLoop", profiler::colors::Green);
#endif
		auto command = reinterpret_cast<LineCommand*>(commands[i]);
		m_API->SetDepthStencilState(command->m_ZEnabled ? eDepthStencilState::Z_ENABLED : eDepthStencilState::Z_DISABLED, 1);
		m_Line->Update(command->m_Points[0], command->m_Points[1]);
		m_Line->Render(m_Camera->GetOrientation(), m_Camera->GetPerspective());
#ifdef _PROFILE
                 EASY_END_BLOCK; 
#endif	
        }
#ifdef _PROFILE
	EASY_END_BLOCK;
#endif

I tried putting a EASY_FUNCTION inside the Render function that m_Line calls to see if the memory leak persisted, it did.
I've got a separate configuration for my profiler & release which are setup the same way, but the profiler build has the _PROFILE flag defined, I flipped it over to release to check that it was not my own code that was causing the leak, I can confirm that it was not my own code causing this leak.
Is this something you can reproduce or have I managed to compile the lib incorrectly?

EDIT:
Forgot to mention that I can place a block AFTER the existing block and NOT leak memory.
EDIT 2:
Seems as if the memory leaking is only when I place a EASY_BLOCK around a loop and then another EASY_BLOCK / EASY_FUNCTION inside of the loop in someway.

Unused DAFAULT_ADDRESS

Hi!
There's unused global constant
const char* DAFAULT_ADDRESS = "tcp://127.0.0.1:28077";

Please remove it, because it is:

  1. Misspelled
  2. Not used
  3. Making impossible to build separate profiler lib and gui binary using it, because this constant shows up in different linkage units and than collides.

Empty Hierarchy window

Altought I have a lot of EASY_BLOCKs and EASY_FUNCTIONs in my code, I still see empty hierarchy window

profiler_gui_2017-04-12_10-08-34

What should I do to be able to see events also in hierarchy window?

profiler_sample frozes at dump blocks...

Hello,

I build easy_profiler with MSVC 2015 and Qt 5.8. For test I launch profiler_sample.exe

Objects count: 500
Render steps: 1500
Modelling steps: 1500
Resource loading count: 50
Frame time: max 4442 us // avg 4299 us
Frame time: max 35237 us // avg 4914 us
Frame time: max 6181 us // avg 4403 us
Frame time: max 6422 us // avg 4441 us
Frame time: max 7993 us // avg 4417 us
Frame time: max 11446 us // avg 4428 us
Frame time: max 6254 us // avg 4354 us
Frame time: max 6200 us // avg 4359 us
Frame time: max 5609 us // avg 4315 us
Frame time: max 7810 us // avg 4336 us
Frame time: max 15036 us // avg 4416 us
Frame time: max 42781 us // avg 4869 us
Frame time: max 6176 us // avg 4285 us
Frame time: max 6927 us // avg 4414 us
Elapsed time: 7073221 usec

And it frozen here...

Profiling arbitrary values

Would it be possible to keep track of arbitrary float/integer values? That would be useful for engine to track object counts. It could be represented simply as FPS graph. API could be something like profiler::sample(valueType, value).

Unrelated: we would love to track object lifetimes as well, however i have no idea how that could be presented in UI. Just something to think about.

How to use easy_profiler without CMake

I am working on very small cpp programs where I code and compile using command line using G++. I would like to see how my programs work and how much memory do they waste.

Is there a way to use the profiler without using CMake? If yes then please, care to explain how.

Thanks.

Procedure point can't be located in DLL

I keep getting this pop-up error on launch whenever I try to run profiler_gui.exe in anything other than debug. (In debug, the profiler open and seems to work just fine)

My current setup is using Visual Studio 2015, x64 and Qt5.9.1. Do you know if this is local issue on my computer or an issue with the project?


profiler_gui.exe - Entry Point Not Found

The procedure entry point ??4QColor@@QEAAAEAV0@$$QEAV0@@z could not be located in the dynamic link library E:\easy_profiler\visual_studio\bin\Release\profiler_gui.exe.

EASY_ENABLE_ALIGNMENT Broken for GCC (Non-MinGW)

This code in profile_manager.h:126 is broken for plain GCC:

#if EASY_ENABLE_ALIGNMENT == 0
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
# define EASY_FREE(MEMPTR) free(MEMPTR)
#else
# if defined(_MSC_VER)
# define EASY_ALIGNED(TYPE, VAR, A) __declspec(align(A)) TYPE VAR
# define EASY_MALLOC(MEMSIZE, A) _aligned_malloc(MEMSIZE, A)
# define EASY_FREE(MEMPTR) _aligned_free(MEMPTR)
# elif defined(__GNUC__)
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR __attribute__(aligned(A))
# else

# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
# endif
#endif

The code in the #elif defined(_GNUC_):
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR __attribute__(aligned(A))
should be:
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR __attribute__((aligned(A))) (missing a set of parentheses)

Once that is fixed, both EASY_MALLOC and EASY_FREE need to be defined to some reasonable value which is up to you guys, since there are a few candidates.

Forced Optimization on Unix

Now, I could be doing something stupid, but I'm pretty sure easy_profiler_core doesn't respect the build type option because of this cmake code in easy_profiler_core/CMakeLists.txt. Note the -O3

if (UNIX)
    target_compile_options(easy_profiler PRIVATE -Wall -Wno-long-long -Wno-reorder -Wno-braced-scalar-init -pedantic -O3)
    target_link_libraries(easy_profiler pthread)
elseif (WIN32)
    target_compile_definitions(easy_profiler PRIVATE -D_WIN32_WINNT=0x0600 -D_CRT_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS)
    target_link_libraries(easy_profiler ws2_32 psapi)
endif ()

I have been trying to debug an issue on my ARM platform for quite sometime now, and this really through me off. I had ruled out UB because it was still broken in the debug build...

Undefined Behavior

In profile_manager.h:chunk_allocator::allocate() / emplace_back() and elsewhere, there are lines like *(uint16_t*)(data + n) = 0; and *(uint16_t*)last->data = 0; that violate strict-aliasing rules:

/easy_profiler/easy_profiler_core/profile_manager.h:175:36: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] *(uint16_t*)last->data = 0;

I have confirmed that easy_profiler does not work correctly when cross compiled (with gcc-4.9.4) for a single core ARMv5 (32 bit) Linux, with pthreads enabled. It works, however, on Linux x86_64 with the same compiler version on the same machine used for cross-compiling. This could be direct result of the UB, as I have made similar mistakes that caused code to work on x86 but not the ARM platform I am using.

Even if my problems aren't caused by the UB, it still needs to be fixed anywhere it is found. I would suggest the use of std::memcpy / std::memset for such things.

EDIT the line *(uint16_t*)(data + n) = 0 doesn't violate strict-aliasing, only the second one.

Make histogram max value depend on visible region

Consider case where some very slow event happens:
hist1
Now if we scroll the view to the right and no longer see slow region we get this:
hist2
Visible data is still hanging at very bottom of the chart making it not really useful. I think histogram range in zoom mode should adapt to visible data instead of entire dataset.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.