Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.24 FATAL_ERROR)

project(MelatoninPerfetto
VERSION 1.1.0
VERSION 1.3.0
LANGUAGES CXX
DESCRIPTION "JUCE module for profiling with Perfetto"
HOMEPAGE_URL "https://github.com/sudara/melatonin_perfetto")
Expand All @@ -25,8 +25,9 @@ set(MP_INSTALL_DEST "${CMAKE_INSTALL_LIBDIR}/cmake/melatonin_perfetto"
CACHE STRING
"Path below the install prefix where melatonin_perfetto package files will be installed to")


message (STATUS "Grabbing Perfetto...")
CPMAddPackage(gh:google/perfetto@48.1)
CPMAddPackage(gh:google/perfetto@50.1)

# we need to manually set up a target for Perfetto
add_library(perfetto STATIC)
Expand Down
43 changes: 29 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,26 +176,15 @@ Include library:
#include <melatonin_perfetto/melatonin_perfetto.h>
```

Add a member of the plugin processor:
Add a member of the plugin processor, guarded by a preprocessor definition:
```cpp
#if PERFETTO
std::unique_ptr<perfetto::TracingSession> tracingSession;
MelatoninPerfetto tracingSession;
#endif
```

Put this in PluginProcessor's constructor:
That's it! Earlier versions (1.2 and before) had MelatoninPerfetto as a singleton that you'd have to setup in the constructor, but now it's just a regular class.

```cpp
#if PERFETTO
MelatoninPerfetto::get().beginSession();
#endif
```
and in the destructor:
```cpp
#if PERFETTO
MelatoninPerfetto::get().endSession();
#endif
```
### Step 2: Pepper around some sweet sweet trace macros

Perfetto will *only* measure functions you specifically tell it to.
Expand Down Expand Up @@ -389,6 +378,32 @@ If you use perfetto regularly, you can also do what I do and check for `PERFETTO

<img width="384" alt="AudioPluginHost - 2023-01-06 44@2x" src="https://user-images.githubusercontent.com/472/211118327-e984f359-4e2f-4aec-8b4d-991093b36e67.png">

## Running Perfetto in your tests

It can be really nice to run a few test cases through perfetto.

To do so with Catch2, for example, you'll need to first link against `Catch2::Catch2` instead of `Catch2::Catch2WithMain`:

```
target_link_libraries(Tests PRIVATE SharedCode Catch2::Catch2WithMain)
```

And then define your own `main` function.

```cpp
#include "melatonin_perfetto/melatonin_perfetto.h"
int main (int argc, char* argv[])
{
#if PERFETTO
MelatoninPerfetto perfetto;
#endif

const int result = Catch::Session().run (argc, argv);

return result;
}
```

## Running Melatonin::Perfetto's tests

`melatonin_perfetto` includes a test suite using CTest. To run the tests, clone the code and run these commands:
Expand Down
100 changes: 56 additions & 44 deletions melatonin_perfetto/melatonin_perfetto.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ BEGIN_JUCE_MODULE_DECLARATION

ID: melatonin_perfetto
vendor: Sudara
version: 1.2.0
version: 1.4.0
name: Melatonin Perfetto
description: Perfetto module for JUCE
license: MIT
Expand All @@ -16,7 +16,7 @@ END_JUCE_MODULE_DECLARATION
#pragma once

// I'm lazy and just toggle perfetto right here
// But you can define it in your build system or in the file that includes this
// But you can define it in your build system or in the file that includes this header
#ifndef PERFETTO
#define PERFETTO 0
#endif
Expand Down Expand Up @@ -47,15 +47,26 @@ PERFETTO_DEFINE_CATEGORIES (
class MelatoninPerfetto
{
public:
MelatoninPerfetto (const MelatoninPerfetto&) = delete;
explicit MelatoninPerfetto (const bool startTrace = true) : startTraceAutomatically (startTrace)
{
perfetto::TracingInitArgs args;
// The backends determine where trace events are recorded. For this example we
// are going to use the in-process tracing service, which only includes in-app events.
args.backends = perfetto::kInProcessBackend;
perfetto::Tracing::Initialize (args);
perfetto::TrackEvent::Register();

if (startTraceAutomatically)
beginSession();
}

static MelatoninPerfetto& get()
~MelatoninPerfetto()
{
static MelatoninPerfetto instance;
return instance;
if (started)
endSession();
}

void beginSession (uint32_t buffer_size_kb = 80000)
void beginSession (const uint32_t buffer_size_kb = 80000)
{
perfetto::TraceConfig cfg;
cfg.add_buffers()->set_size_kb (buffer_size_kb); // 80MB is the default
Expand All @@ -64,6 +75,7 @@ class MelatoninPerfetto
session = perfetto::Tracing::NewTrace();
session->Setup (cfg);
session->StartBlocking();
started = true;
}

// Returns the file where the dump was written to (or a null file if an error occurred)
Expand All @@ -75,7 +87,7 @@ class MelatoninPerfetto

// Stop tracing
session->StopBlocking();

started = false;
return writeFile();
}

Expand All @@ -89,17 +101,8 @@ class MelatoninPerfetto
}

private:
MelatoninPerfetto()
{
perfetto::TracingInitArgs args;
// The backends determine where trace events are recorded. For this example we
// are going to use the in-process tracing service, which only includes in-app
// events.
args.backends = perfetto::kInProcessBackend;
perfetto::Tracing::Initialize (args);
perfetto::TrackEvent::Register();
}

bool startTraceAutomatically;
bool started = true;
juce::File writeFile()
{
// Read trace data
Expand Down Expand Up @@ -162,7 +165,7 @@ namespace melatonin
{
// if we're C++20 or higher, ensure we're compile-time
#if __cplusplus >= 202002L
// This should never assert, but if so, report it on this issue:
// This should never assert, but if so, report it on this issue:
// https://github.com/sudara/melatonin_perfetto/issues/13#issue-1558171132
if (!std::is_constant_evaluated())
jassertfalse;
Expand Down Expand Up @@ -237,32 +240,41 @@ namespace melatonin
}
}

// Et voilà! Our nicer macros.
// This took > 20 hours, hope the DX is worth it...
// The separate constexpr calls are required for `compileTimePrettierFunction` to remain constexpr
// in other words, they can't be inline with perfetto::StaticString, otherwise it will go runtime

// we also can toggle dsp/component on/off individually to help clean up traces
#if PERFETTO_ENABLE_TRACE_DSP
#define TRACE_DSP(...) \
constexpr auto pf = melatonin::compileTimePrettierFunction (WRAP_COMPILE_TIME_STRING (PERFETTO_DEBUG_FUNCTION_IDENTIFIER())); \
TRACE_EVENT ("dsp", perfetto::StaticString (pf.data()), ##__VA_ARGS__)
#else
#define TRACE_DSP(...)
#endif

#if PERFETTO_ENABLE_TRACE_COMPONENT
#define TRACE_COMPONENT(...) \
constexpr auto pf = melatonin::compileTimePrettierFunction (WRAP_COMPILE_TIME_STRING (PERFETTO_DEBUG_FUNCTION_IDENTIFIER())); \
TRACE_EVENT ("component", perfetto::StaticString (pf.data()), ##__VA_ARGS__)
#else
#define TRACE_COMPONENT(...)
#endif

#else // if PERFETTO
#else
// allow people to keep perfetto helpers in-place even when disabled
#define TRACE_EVENT_BEGIN(category, ...)
#define TRACE_EVENT_END(category)
#define TRACE_EVENT(category, ...)
#endif

// Et voilà! Our nicer macros.
// This took > 20 hours, hope the DX is worth it...
// The separate constexpr calls are required for `compileTimePrettierFunction` to remain constexpr
// in other words, they can't be inline with perfetto::StaticString, otherwise it will go runtime

// we also can toggle dsp/component on/off individually to help clean up traces
#if PERFETTO_ENABLE_TRACE_DSP
#define TRACE_DSP(...) \
constexpr auto pf = melatonin::compileTimePrettierFunction (WRAP_COMPILE_TIME_STRING (PERFETTO_DEBUG_FUNCTION_IDENTIFIER())); \
TRACE_EVENT ("dsp", perfetto::StaticString (pf.data()), ##__VA_ARGS__)

#define TRACE_DSP_BEGIN(name) TRACE_EVENT_BEGIN ("dsp", perfetto::StaticString (name))
#define TRACE_DSP_END() TRACE_EVENT_END ("dsp")
#else
#define TRACE_DSP(...)
#define TRACE_DSP_BEGIN(name)
#define TRACE_DSP_END()
#endif

#if PERFETTO_ENABLE_TRACE_COMPONENT
#define TRACE_COMPONENT(...) \
constexpr auto pf = melatonin::compileTimePrettierFunction (WRAP_COMPILE_TIME_STRING (PERFETTO_DEBUG_FUNCTION_IDENTIFIER())); \
TRACE_EVENT ("component", perfetto::StaticString (pf.data()), ##__VA_ARGS__)

#define TRACE_COMPONENT_BEGIN(name) TRACE_EVENT_BEGIN ("component", perfetto::StaticString (name))
#define TRACE_COMPONENT_END() TRACE_EVENT_END ("component")
#else
#define TRACE_COMPONENT(...)
#endif // if PERFETTO
#define TRACE_COMPONENT_BEGIN(name)
#define TRACE_COMPONENT_END()
#endif
6 changes: 2 additions & 4 deletions tests/DumpFiles/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ int szudzikPair (int a, int b)

int main (int, char**)
{
std::unique_ptr<perfetto::TracingSession> tracingSession;

MelatoninPerfetto::get().beginSession();
MelatoninPerfetto tracingSession;

auto& rand = juce::Random::getSystemRandom();

Expand All @@ -35,7 +33,7 @@ int main (int, char**)
for (auto i = 0; i < 100; ++i)
values.push_back (szudzikPair (rand.nextInt(), rand.nextInt()));

const auto dumpFile = MelatoninPerfetto::get().endSession();
const auto dumpFile = tracingSession.endSession();

if (dumpFile.existsAsFile())
return EXIT_SUCCESS;
Expand Down