New Module: Profile your JUCE UI/dsp performance with Perfetto

Hmmm, I have been wrestling with this now for an entire day. It seems impossible to make this work with Projucer on Windows/VS 2019.

I downloaded the latest perfetto v33.1 which they said fixed the issue with the C++17 false flag.

But when I try to run my project in VS2019, there are thousands of warnings and errors generated. This is with the two /perfetto/sdk files added into my Projucer Project, as directed.

I was talking to devs on the discord for perfetto, and was advised that CMAKE (which I am NOT using) requires a #define of WIN32_LEAN_AND_MEAN, but have no idea where to put that in Projucer (or VS). Is that a precompile option? I tried WIN32_LEAN_AND_MEAN=1 in Projucer Precompile Options, but it didn’t fix anything.

Then I was advised to “use “/permissive-” for MSVC as suggested on the CMake file in the docs” - which again is a reference to CMAKE, so I tried adding /permissive- as an Extra Compiler Flag setting in projucer, which seemed to do nothing.

Example of errors:

Warning    C4127    conditional expression is constant    (my path)\perfetto\sdk\perfetto.cc 238
Warning    C4127    conditional expression is constant    (my path)\perfetto\sdk\perfetto.cc 2382
Warning    C4996    'fileno': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _fileno. See online help for details.    (my path)s\perfetto\sdk\perfetto.cc    3228
Error    C2589    '(': illegal token on right side of '::'    (my path)\modules\perfetto\sdk\perfetto.cc 3244
Error    C2062    type 'unknown-type' unexpected    (my path)\modules\perfetto\sdk\perfetto.cc 3244
Error    C2144    syntax error: 'unknown-type' should be preceded by '('    (my path)\perfetto\sdk\perfetto.cc    3244

Hi Stephen,

Yes, perfetto itself is difficult to setup on Windows, even with CMake. It took me a few sessions to get it running on windows. That was a large part of motivation for releasing the module, so that someone wouldn’t have to duplicate that effort and it would all be documented.

I don’t use the Projucer… I would expect it to be cumbersome but possible. It sounds like you’ve managed to run into almost all the same solutions I did, so you are almost there.

The compiler flags for the perfetto target should be:

/bigobj
/Zc:__cplusplus
/permissive-

In addition you’ll need the preprocessor definitions set:

NOMINMAX=1 
WIN32_LEAN_AND_MEAN=1

In CMake we do this on the Perfetto target itself, but I’m not sure how this translates in Projucer world.

If that works for you, let me know and we can update the docs to save anyone else this trouble going forward.

Thanks! I was finally able to get it to compile on Windows by putting those flags here in the following locations in the Projucer (along with a few other things I already had in there):

If you want to add it to the docs, that is the Settings page for the Visual Studio 2019 Exporter.

But even so, building it the first time in VS2019 had nearly 6000 warnings from perfetto! I guess this would only happen the first time you build it and it “makes” the library (?), but if anyone’s interested, I suppressed all the errors by putting this at the head and tail of both perfetto.cc and perfetto.h:

#if _WINDOWS
#pragma warning( push )
#pragma warning( disable : 4127 )   // conditional expression is constant 
#pragma warning( disable : 4996 )   // The POSIX name for this item is deprecated 
#pragma warning( disable : 4459 )   // declaration hides global declaration
#pragma warning( disable : 4244 )   // conversion from ' ' to ' ', possible loss of data
#pragma warning( disable : 4267 )   // conversion from ' ' to ' ', possible loss of data
#pragma warning( disable : 4065 )   // switch statement contains 'default' but no 'case' labels
#pragma warning( disable : 4706 )   // assignment within conditional expression
#endif //_WINDOWS

(body...)

#if _WINDOWS
#pragma warning( pop )
#endif //_WINDOWS

The first disable (4127) is good for over 5500+ warnings itself.

I mentioned this over on the perfetto discord; I don’t know if they care about this kind of thing…

1 Like

Glad you got it working! Thanks for confirming.

I bumped the perfetto version to 33.1 on the module, added the windows instructions and acknowledged your efforts at the bottom of the Readme! Bump Perfetto Version. Add Windows Projucer Instructions. by sudara · Pull Request #18 · sudara/melatonin_perfetto · GitHub

1 Like

Thanks! Slight error in the new READ ME:

Should be “Extra Compiler Flags”.

1 Like

BTW, I forgot to mention: when I run my project on Windows with this enabled, I get 150+ memory leaks on quit. Are you seeing that as well? I suppose it’s nothing to worry about if it’s just a debugging tool…

I haven’t seen anything like that. Is this the JUCE leak detector? Are the leaked objects perfetto related?

No, it’s just the standard leak detection errors that Visual Studio puts up. Hundreds of them if I use PERFETTO=1. With PERFETTO=0, no memory leaks.

This is what happens when I exit my GUI App:

The thread 0x73d4 has exited with code 0 (0x0).
The thread 0x57bc has exited with code 0 (0x0).
The thread 0x4ef8 has exited with code 0 (0x0).
Detected memory leaks!
Dumping objects ->
{402792} normal block at 0x000001FBBEE25200, 257 bytes long.
 Data: <Perfetto v33.0-5> 50 65 72 66 65 74 74 6F 20 76 33 33 2E 30 2D 35 
{402701} normal block at 0x000001FBCB850B00, 104 bytes long.
 Data: <                > C0 11 A8 BC FB 01 00 00 90 0B A8 BC FB 01 00 00 
{342073} normal block at 0x000001FBCBE100A0, 48 bytes long.
 Data: <@       `       > 40 EE E0 CB FB 01 00 00 60 ED E0 CB FB 01 00 00 
{334782} normal block at 0x000001FBCBE0DA20, 48 bytes long.
 Data: <        0       > 10 F3 E0 CB FB 01 00 00 30 E4 E0 CB FB 01 00 00 
{334731} normal block at 0x000001FBCBE0E430, 48 bytes long.
 Data: <        `       > 20 DA E0 CB FB 01 00 00 60 D8 E0 CB FB 01 00 00 
{334680} normal block at 0x000001FBCBE0D860, 48 bytes long.
 Data: <                > B0 D9 E0 CB FB 01 00 00 10 F3 E0 CB FB 01 00 00 
{334569} normal block at 0x000001FBCBE0D9B0, 48 bytes long.
 Data: <        `       > 10 F3 E0 CB FB 01 00 00 60 D8 E0 CB FB 01 00 00 
{334568} normal block at 0x000001FBCBE0F310, 48 bytes long.
 Data: <        `       > B0 D9 E0 CB FB 01 00 00 60 D8 E0 CB FB 01 00 00 
{334567} normal block at 0x000001FBCBCCC0B0, 16 bytes long.
 Data: <Xds             > 58 64 73 CB FB 01 00 00 00 00 00 00 00 00 00 00 
{334566} normal block at 0x000001FBCB736450, 32 bytes long.
 Data: <  f             > D0 91 66 C8 F7 7F 00 00 B0 C0 CC CB FB 01 00 00 
{334563} normal block at 0x000001FBCBE0ED60, 48 bytes long.
 Data: <@       @       > 40 EE E0 CB FB 01 00 00 40 EE E0 CB FB 01 00 00 
{334562} normal block at 0x000001FBCBE0EE40, 48 bytes long.
 Data: <`       `       > 60 ED E0 CB FB 01 00 00 60 ED E0 CB FB 01 00 00 
{334561} normal block at 0x000001FBCBCCC830, 16 bytes long.
 Data: < ps             > B8 70 73 CB FB 01 00 00 00 00 00 00 00 00 00 00 
{334560} normal block at 0x000001FBCB7370B0, 32 bytes long.
 Data: <  f     0       > A0 91 66 C8 F7 7F 00 00 30 C8 CC CB FB 01 00 00 
{334559} normal block at 0x000001FBCAAADB60, 4096 bytes long.
 Data: <         LED::LE> 12 97 80 80 00 08 02 12 13 4C 45 44 3A 3A 4C 45 
{334558} normal block at 0x000001FBCB736B70, 24 bytes long.
 Data: <                > 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 
{334557} normal block at 0x000001FBCBE0EDD0, 48 bytes long.
 Data: <@       @       > 40 E7 E0 CB FB 01 00 00 40 E7 E0 CB FB 01 00 00 
{334556} normal block at 0x000001FBCBE0E740, 48 bytes long.
 Data: <                > D0 ED E0 CB FB 01 00 00 D0 ED E0 CB FB 01 00 00 
{334555} normal block at 0x000001FBCBCCC1A0, 16 bytes long.
 Data: <Xms             > 58 6D 73 CB FB 01 00 00 00 00 00 00 00 00 00 00 
{334554} normal block at 0x000001FBCB736D50, 32 bytes long.
 Data: <p f             > 70 91 66 C8 F7 7F 00 00 A0 C1 CC CB FB 01 00 00 
{334416} normal block at 0x000001FBCB732F70, 32 bytes long.
 Data: <                > F0 D1 CA BE FB 01 00 00 F0 D1 CA BE FB 01 00 00 
{334415} normal block at 0x000001FBCB7343B0, 24 bytes long.
 Data: <                > 00 00 00 CD CD CD CD CD 01 00 00 00 00 00 00 00 
{334414} normal block at 0x000001FBCBD913E0, 128 bytes long.
 Data: <  s       s     > 90 1B 73 CB FB 01 00 00 90 1B 73 CB FB 01 00 00 
{334413} normal block at 0x000001FBCBCCC7E0, 16 bytes long.
 Data: <                > 00 10 CB CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334412} normal block at 0x000001FBCB731B90, 32 bytes long.
 Data: <  s       s     > 90 1B 73 CB FB 01 00 00 90 1B 73 CB FB 01 00 00 
{334411} normal block at 0x000001FBCBCCCBF0, 16 bytes long.
 Data: <                > E8 0F CB CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334410} normal block at 0x000001FBCBD93120, 128 bytes long.
 Data: <                > F0 1F 9D CA FB 01 00 00 F0 1F 9D CA FB 01 00 00 
{334409} normal block at 0x000001FBCBCCBE30, 16 bytes long.
 Data: <                > A8 0F CB CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334408} normal block at 0x000001FBCA9D1FF0, 64 bytes long.
 Data: <                > F0 1F 9D CA FB 01 00 00 F0 1F 9D CA FB 01 00 00 
{334407} normal block at 0x000001FBCBCCC290, 16 bytes long.
 Data: <                > 90 0F CB CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334406} normal block at 0x000001FBCBCCCE20, 16 bytes long.
 Data: <h               > 68 0F CB CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334405} normal block at 0x000001FBCBC88410, 784 bytes long.
 Data: <                > 00 00 00 00 00 00 00 00 00 0D CB CA FB 01 00 00 
{334404} normal block at 0x000001FBCBCCC790, 16 bytes long.
 Data: <X               > 58 0D CB CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334403} normal block at 0x000001FBCBCCCDD0, 16 bytes long.
 Data: <                > C8 0C CB CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334402} normal block at 0x000001FBCACB0CA0, 920 bytes long.
 Data: <        8ef     > 00 00 00 00 00 00 00 00 38 65 66 C8 F7 7F 00 00 
{334401} normal block at 0x000001FBCBC880C0, 784 bytes long.
 Data: <         j      > 00 00 00 00 00 00 00 00 E8 6A D5 CB FB 01 00 00 
{334400} normal block at 0x000001FBCBCCC6F0, 16 bytes long.
 Data: <                > 20 F5 9C CA FB 01 00 00 00 00 00 00 00 00 00 00 
{334399} normal block at 0x000001FBCA9CF4F0, 64 bytes long.
 Data: < j              > E8 6A D5 CB FB 01 00 00 20 F5 9C CA FB 01 00 00 
{334398} normal block at 0x000001FBCBCCC5B0, 16 bytes long.
 Data: <0k      @k      > 30 6B D5 CB FB 01 00 00 40 6B D5 CB FB 01 00 00 
{334397} normal block at 0x000001FBCBD56AB0, 184 bytes long.
 Data: <  f       f     > D0 8F 66 C8 F7 7F 00 00 18 90 66 C8 F7 7F 00 00 
{334396} normal block at 0x000001FBCBC77B30, 4 bytes long.
 Data: <    > 02 00 00 00 
{9178} normal block at 0x000001FBBECC9EB0, 16 bytes long.
 Data: <                > 90 0C A8 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{9177} normal block at 0x000001FBBCA80C40, 112 bytes long.
 Data: <        P       > 02 01 00 00 00 00 00 00 50 BC A8 7F FE 7F 00 00 
{9093} normal block at 0x000001FBBE80C4A0, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
{9011} normal block at 0x000001FBBCA80B90, 104 bytes long.
 Data: <                > C0 11 A8 BC FB 01 00 00 C0 11 A8 BC FB 01 00 00 
{8927} normal block at 0x000001FBBECAD130, 24 bytes long.
 Data: <( f             > 28 E6 66 C8 F7 7F 00 00 01 00 00 00 01 00 00 00 
{8926} normal block at 0x000001FBBECCAD60, 8 bytes long.
 Data: <0       > 30 D8 C9 BE FB 01 00 00 
{8925} normal block at 0x000001FBBECCBDF0, 40 bytes long.
 Data: <                > F0 BD CC BE FB 01 00 00 F0 BD CC BE FB 01 00 00 
{8924} normal block at 0x000001FBBECCB620, 16 bytes long.
 Data: <`               > 60 D9 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8923} normal block at 0x000001FBBECCB530, 16 bytes long.
 Data: <8               > 38 D9 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8922} normal block at 0x000001FBBCA9F7E0, 40 bytes long.
 Data: <                > E0 F7 A9 BC FB 01 00 00 E0 F7 A9 BC FB 01 00 00 
{8921} normal block at 0x000001FBBECCAB80, 16 bytes long.
 Data: <                > 20 D9 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8920} normal block at 0x000001FBBECCB170, 16 bytes long.
 Data: <                > E8 D8 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8919} normal block at 0x000001FBBECCB6C0, 16 bytes long.
 Data: <                > F0 D8 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8918} normal block at 0x000001FBBEC9D830, 344 bytes long.
 Data: <P f      )      > 50 8F 66 C8 F7 7F 00 00 B0 29 C9 BE FB 01 00 00 
{8917} normal block at 0x000001FBBECAD370, 32 bytes long.
 Data: <  f             > E8 A0 66 C8 F7 7F 00 00 00 10 EC BE FB 01 00 00 
{8860} normal block at 0x000001FBBE835960, 4 bytes long.
 Data: <    > 00 00 00 00 
{8854} normal block at 0x000001FBBECAD0D0, 24 bytes long.
 Data: <  f             > E0 E6 66 C8 F7 7F 00 00 01 00 00 00 01 00 00 00 
{8853} normal block at 0x000001FBBECCA9F0, 8 bytes long.
 Data: <        > 00 00 00 00 00 00 00 00 
{8756} normal block at 0x000001FBBE80D8A0, 64 bytes long.
 Data: <X f      J      > 58 EF 66 C8 F7 7F 00 00 A0 4A C9 BE FB 01 00 00 
{8725} normal block at 0x000001FBBECC3FF0, 8 bytes long.
 Data: < K      > 00 4B CC BE FB 01 00 00 
{8627} normal block at 0x000001FBBECB5570, 16 bytes long.
 Data: <                > B8 C1 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8626} normal block at 0x000001FBBECB5660, 16 bytes long.
 Data: <                > 90 C1 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8623} normal block at 0x000001FBBECB6420, 16 bytes long.
 Data: <@               > 40 C1 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8622} normal block at 0x000001FBBECB60B0, 16 bytes long.
 Data: <                > 08 C1 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8621} normal block at 0x000001FBBECB5930, 16 bytes long.
 Data: <                > D0 C0 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8619} normal block at 0x000001FBBEC9C0B0, 312 bytes long.
 Data: <0       0       > 30 BF C9 BE FB 01 00 00 30 BF C9 BE FB 01 00 00 
{8615} normal block at 0x000001FBBCA9FC40, 48 bytes long.
 Data: <       component> 0A 96 80 80 00 0A 09 63 6F 6D 70 6F 6E 65 6E 74 
{8614} normal block at 0x000001FBBECB6100, 16 bytes long.
 Data: <h               > 68 C1 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8589} normal block at 0x000001FBBCAA0180, 48 bytes long.
 Data: <       component> 0A 96 80 80 00 0A 09 63 6F 6D 70 6F 6E 65 6E 74 
{8583} normal block at 0x000001FBBECA36B0, 16 bytes long.
 Data: <h               > 68 C4 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8582} normal block at 0x000001FBBECA3890, 16 bytes long.
 Data: <@               > 40 C4 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8581} normal block at 0x000001FBBECA3C50, 16 bytes long.
 Data: <                > 18 C4 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8580} normal block at 0x000001FBBECA3520, 16 bytes long.
 Data: <                > F0 C3 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8579} normal block at 0x000001FBBECA32F0, 16 bytes long.
 Data: <                > B8 C3 C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8578} normal block at 0x000001FBBEC9C3B0, 312 bytes long.
 Data: < ^f      2      > C8 5E 66 C8 F7 7F 00 00 F0 32 CA BE FB 01 00 00 
{8550} normal block at 0x000001FBBEC9F210, 16 bytes long.
 Data: <                > C0 D3 80 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8549} normal block at 0x000001FBBE80D3A0, 64 bytes long.
 Data: <                > 20 DF 80 BE FB 01 00 00 A0 DA 80 BE FB 01 00 00 
{8548} normal block at 0x000001FBBECAD070, 32 bytes long.
 Data: <0 f             > 30 ED 66 C8 F7 7F 00 00 01 00 00 00 01 00 00 00 
{8547} normal block at 0x000001FBBE80D820, 64 bytes long.
 Data: <  g             > E8 01 67 C8 F7 7F 00 00 00 00 00 00 00 00 00 00 
{8546} normal block at 0x000001FBBCA9F770, 48 bytes long.
 Data: <                > D0 FB A9 BC FB 01 00 00 D0 FB A9 BC FB 01 00 00 
{8545} normal block at 0x000001FBBECAD970, 24 bytes long.
 Data: <h f             > 68 E5 66 C8 F7 7F 00 00 01 00 00 00 01 00 00 00 
{8544} normal block at 0x000001FBBEC9F170, 8 bytes long.
 Data: < )      > B0 29 C9 BE FB 01 00 00 
{8543} normal block at 0x000001FBBECAD1F0, 32 bytes long.
 Data: <p/s     p/s     > 70 2F 73 CB FB 01 00 00 70 2F 73 CB FB 01 00 00 
{8542} normal block at 0x000001FBBEC9EEA0, 16 bytes long.
 Data: < *              > A8 2A C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8541} normal block at 0x000001FBBECADE50, 32 bytes long.
 Data: <P       P       > 50 DE CA BE FB 01 00 00 50 DE CA BE FB 01 00 00 
{8540} normal block at 0x000001FBBEC9FC10, 16 bytes long.
 Data: < *              > 90 2A C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8539} normal block at 0x000001FBBEC9FB70, 16 bytes long.
 Data: <`*              > 60 2A C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8538} normal block at 0x000001FBBECAE0F0, 32 bytes long.
 Data: <XXXXX-apphostDB> 4B 41 52 4D 41 33 2D 61 70 70 68 6F 73 74 44 42 
{8537} normal block at 0x000001FBBEC9FAD0, 16 bytes long.
 Data: <8*              > 38 2A C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8536} normal block at 0x000001FBBEC929B0, 296 bytes long.
 Data: <  f             > D0 9B 66 C8 F7 7F 00 00 01 00 CD CD 00 00 00 00 
{8534} normal block at 0x000001FBBECADC10, 24 bytes long.
 Data: <  f             > 08 E5 66 C8 F7 7F 00 00 02 00 00 00 01 00 00 00 
{8533} normal block at 0x000001FBBEC9F940, 8 bytes long.
 Data: < ,      > 90 2C CA BE FB 01 00 00 
{8532} normal block at 0x000001FBBECBCA80, 16407 bytes long.
 Data: <                > 80 CA CB BE FB 01 00 00 ED ED ED ED ED ED ED ED 
{8531} normal block at 0x000001FBBCAA7AA0, 80 bytes long.
 Data: < z       z      > A0 7A AA BC FB 01 00 00 A0 7A AA BC FB 01 00 00 
{8530} normal block at 0x000001FBBEC9F850, 16 bytes long.
 Data: < -              > 80 2D CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8529} normal block at 0x000001FBBCA9F700, 48 bytes long.
 Data: <                > 00 F7 A9 BC FB 01 00 00 00 F7 A9 BC FB 01 00 00 
{8528} normal block at 0x000001FBBEC9FA80, 16 bytes long.
 Data: <h-              > 68 2D CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8527} normal block at 0x000001FBBECA1FE0, 1232 bytes long.
 Data: <                > E0 1F CA BE FB 01 00 00 E0 1F CA BE FB 01 00 00 
{8526} normal block at 0x000001FBBEC9FBC0, 16 bytes long.
 Data: <P-              > 50 2D CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8525} normal block at 0x000001FBBCAA0030, 40 bytes long.
 Data: <0       0       > 30 00 AA BC FB 01 00 00 30 00 AA BC FB 01 00 00 
{8524} normal block at 0x000001FBBEC9F080, 16 bytes long.
 Data: <8-              > 38 2D CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8523} normal block at 0x000001FBBCA9FBD0, 48 bytes long.
 Data: <p       p       > 70 F7 A9 BC FB 01 00 00 70 F7 A9 BC FB 01 00 00 
{8522} normal block at 0x000001FBBEC9F120, 16 bytes long.
 Data: < -              > 20 2D CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8521} normal block at 0x000001FBBEC9BF30, 312 bytes long.
 Data: <                > B0 C0 C9 BE FB 01 00 00 B0 C0 C9 BE FB 01 00 00 
{8520} normal block at 0x000001FBBEC9F800, 16 bytes long.
 Data: < -              > 08 2D CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8519} normal block at 0x000001FBBEC9F8A0, 16 bytes long.
 Data: < ,              > D8 2C CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8518} normal block at 0x000001FBBEC9F440, 16 bytes long.
 Data: < ,              > E0 2C CA BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8517} normal block at 0x000001FBBECA2C90, 416 bytes long.
 Data: <0 f             > 30 9D 66 C8 F7 7F 00 00 F0 DA CA BE FB 01 00 00 
{8516} normal block at 0x000001FBBEC9F7B0, 8 bytes long.
 Data: <  f     > 10 A1 66 C8 F7 7F 00 00 
{8514} normal block at 0x000001FBBECAD490, 32 bytes long.
 Data: XXXXX-apphostDB> 4B 41 52 4D 41 33 2D 61 70 70 68 6F 73 74 44 42 
{8513} normal block at 0x000001FBBEC9F490, 16 bytes long.
 Data: <                > 98 94 A7 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8510} normal block at 0x000001FBBE80D020, 64 bytes long.
 Data: <                > 20 D0 80 BE FB 01 00 00 20 D0 80 BE FB 01 00 00 
{8509} normal block at 0x000001FBBEC9FC60, 16 bytes long.
 Data: <                > 18 14 A8 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8508} normal block at 0x000001FBBECADBB0, 32 bytes long.
 Data: <                > B0 DB CA BE FB 01 00 00 B0 DB CA BE FB 01 00 00 
{8507} normal block at 0x000001FBBEC9F6C0, 16 bytes long.
 Data: <                > 00 14 A8 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8506} normal block at 0x000001FBBCA813D0, 112 bytes long.
 Data: <  f      J      > 88 94 66 C8 F7 7F 00 00 A0 4A C9 BE FB 01 00 00 
{8505} normal block at 0x000001FBBEC9FCB0, 16 bytes long.
 Data: <                > E8 94 A7 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8503} normal block at 0x000001FBBCA79470, 152 bytes long.
 Data: <        0       > 90 8C A7 BC FB 01 00 00 30 9D A7 BC FB 01 00 00 
{8502} normal block at 0x000001FBBECAD6D0, 24 bytes long.
 Data: < bf     8bf     > 18 62 66 C8 F7 7F 00 00 38 62 66 C8 F7 7F 00 00 
{8501} normal block at 0x000001FBBEC9F8F0, 16 bytes long.
 Data: <@               > 40 DF 80 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8500} normal block at 0x000001FBBE80DF20, 64 bytes long.
 Data: <                > A0 DA 80 BE FB 01 00 00 A0 D3 80 BE FB 01 00 00 
{8499} normal block at 0x000001FBBECAD790, 32 bytes long.
 Data: <0 f             > 30 ED 66 C8 F7 7F 00 00 01 00 00 00 01 00 00 00 
{8498} normal block at 0x000001FBBECB6510, 25896 bytes long.
 Data: <pdf             > 70 64 66 C8 F7 7F 00 00 00 00 00 00 00 00 00 00 
{8497} normal block at 0x000001FBBECADB50, 24 bytes long.
 Data: <  f             > F8 E5 66 C8 F7 7F 00 00 01 00 00 00 01 00 00 00 
{8496} normal block at 0x000001FBBEC9F3A0, 8 bytes long.
 Data: <        > C0 FF A9 BC FB 01 00 00 
{8495} normal block at 0x000001FBBCA9FFC0, 48 bytes long.
 Data: <  f             > 98 92 66 C8 F7 7F 00 00 80 14 A8 BC FB 01 00 00 
{8493} normal block at 0x000001FBBECAD550, 32 bytes long.
 Data: <XXXXXX-apphostDB> 4B 41 52 4D 41 33 2D 61 70 70 68 6F 73 74 44 42 
{8488} normal block at 0x000001FBBEC9F710, 16 bytes long.
 Data: <                > B8 8C A7 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8485} normal block at 0x000001FBBE80D420, 64 bytes long.
 Data: <                > 20 D4 80 BE FB 01 00 00 20 D4 80 BE FB 01 00 00 
{8484} normal block at 0x000001FBBEC9F030, 16 bytes long.
 Data: <                > C8 14 A8 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8483} normal block at 0x000001FBBECAD430, 32 bytes long.
 Data: <0       0       > 30 D4 CA BE FB 01 00 00 30 D4 CA BE FB 01 00 00 
{8482} normal block at 0x000001FBBEC9EEF0, 16 bytes long.
 Data: <                > B0 14 A8 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8481} normal block at 0x000001FBBCA81480, 112 bytes long.
 Data: <  f      J      > 88 94 66 C8 F7 7F 00 00 A0 4A C9 BE FB 01 00 00 
{8480} normal block at 0x000001FBBEC9FDA0, 16 bytes long.
 Data: <                > 08 8D A7 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8478} normal block at 0x000001FBBCA78C90, 152 bytes long.
 Data: <0       p       > 30 9D A7 BC FB 01 00 00 70 94 A7 BC FB 01 00 00 
{8476} normal block at 0x000001FBBEC9F990, 16 bytes long.
 Data: <X f     x f     > 58 92 66 C8 F7 7F 00 00 78 92 66 C8 F7 7F 00 00 
{8467} normal block at 0x000001FBBCAA7A10, 80 bytes long.
 Data: < z       z      > 10 7A AA BC FB 01 00 00 10 7A AA BC FB 01 00 00 
{8466} normal block at 0x000001FBBEC9F5D0, 16 bytes long.
 Data: <@               > 40 18 A8 BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8465} normal block at 0x000001FBBCA817F0, 104 bytes long.
 Data: <        P       > 02 00 00 00 CD CD CD CD 50 BC A8 7F FE 7F 00 00 
{8464} normal block at 0x000001FBBECA4840, 25896 bytes long.
 Data: <pdf             > 70 64 66 C8 F7 7F 00 00 00 00 00 00 00 00 00 00 
{8462} normal block at 0x000001FBBE835820, 1 bytes long.
 Data: < > CD 
{8461} normal block at 0x000001FBBEC9F580, 8 bytes long.
 Data: <        > D0 03 00 00 00 00 00 00 
{8460} normal block at 0x000001FBBE80D0A0, 64 bytes long.
 Data: <8 f      J      > 38 EE 66 C8 F7 7F 00 00 A0 4A C9 BE FB 01 00 00 
{8459} normal block at 0x000001FBBE80CC20, 64 bytes long.
 Data: <                > A0 D0 80 BE FB 01 00 00 20 D8 80 BE FB 01 00 00 
{8457} normal block at 0x000001FBBCA81740, 112 bytes long.
 Data: <p       p       > 70 12 A8 BC FB 01 00 00 70 12 A8 BC FB 01 00 00 
{8456} normal block at 0x000001FBBCA81270, 112 bytes long.
 Data: <@       @       > 40 17 A8 BC FB 01 00 00 40 17 A8 BC FB 01 00 00 
{8455} normal block at 0x000001FBBEC9FB20, 16 bytes long.
 Data: <h  c            > 68 FD CF 63 AD 00 00 00 00 00 00 00 00 00 00 00 
{8454} normal block at 0x000001FBBCA811C0, 104 bytes long.
 Data: <                > 90 0B A8 BC FB 01 00 00 90 0B A8 BC FB 01 00 00 
{8453} normal block at 0x000001FBBEC9EF40, 16 bytes long.
 Data: <H  c            > 48 FD CF 63 AD 00 00 00 00 00 00 00 00 00 00 00 
{8452} normal block at 0x000001FBBEC9F0D0, 16 bytes long.
 Data: <   c            > 20 FD CF 63 AD 00 00 00 00 00 00 00 00 00 00 00 
{8451} normal block at 0x000001FBBEC9F350, 16 bytes long.
 Data: <   c            > B0 FC CF 63 AD 00 00 00 00 00 00 00 00 00 00 00 
{8446} normal block at 0x000001FBBCA87A60, 96 bytes long.
 Data: <  f     @w      > F8 E7 66 C8 F7 7F 00 00 40 77 AA BC FB 01 00 00 
{8445} normal block at 0x000001FBBEC9EFE0, 16 bytes long.
 Data: <Xw              > 58 77 AA BC FB 01 00 00 00 00 00 00 00 00 00 00 
{8444} normal block at 0x000001FBBCAA7740, 72 bytes long.
 Data: <  f             > B8 8B 66 C8 F7 7F 00 00 CC 03 00 00 00 00 00 00 
{8443} normal block at 0x000001FBBECADAF0, 24 bytes long.
 Data: <p f      J      > 70 96 66 C8 F7 7F 00 00 A0 4A C9 BE FB 01 00 00 
{8441} normal block at 0x000001FBBCA7A7B0, 152 bytes long.
 Data: <                > B0 A7 A7 BC FB 01 00 00 B0 A7 A7 BC FB 01 00 00 
{8440} normal block at 0x000001FBBEC9FD00, 16 bytes long.
 Data: <XK              > 58 4B C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8439} normal block at 0x000001FBBEC9FA30, 16 bytes long.
 Data: < K              > 10 4B C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8438} normal block at 0x000001FBBE80DAA0, 64 bytes long.
 Data: <                > A0 D3 80 BE FB 01 00 00 20 DF 80 BE FB 01 00 00 
{8437} normal block at 0x000001FBBEC9EF90, 16 bytes long.
 Data: < J              > F8 4A C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8436} normal block at 0x000001FBBCA79D30, 152 bytes long.
 Data: <p               > 70 94 A7 BC FB 01 00 00 90 8C A7 BC FB 01 00 00 
{8435} normal block at 0x000001FBBEC9F530, 16 bytes long.
 Data: < J              > E0 4A C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8434} normal block at 0x000001FBBEC9F760, 16 bytes long.
 Data: < J              > C0 4A C9 BE FB 01 00 00 00 00 00 00 00 00 00 00 
{8433} normal block at 0x000001FBBEC9EE50, 16 bytes long.
 Data: <  f     $       > E8 AB 66 C8 F7 7F 00 00 24 00 00 00 CD CD CD CD 
{8432} normal block at 0x000001FBBEC94AA0, 208 bytes long.
 Data: <  f     P       > 20 96 66 C8 F7 7F 00 00 50 EE C9 BE FB 01 00 00 
Object dump complete.
The program '[27988] XXXXXX-apphostDB.exe' has exited with code 0 (0x0).
1 Like

Did you ever get as far as cleaning this up?

Yes, I got something working that’s used successfully internally. Still it is one of the most hacky pieces of code that I’ve written so far, especially since it relies on undocumented Apple APIs and since it uses two macros that are intended to look like classes – in the hope that I’ll find a solution for it that does not rely on macros at some point. So nothing that I’d usually share with the world claiming it to be production ready or following any best practice :wink:

The usage is quite simple:

// Somewhere once
ProfilerSignpost::init();

// Emit some signposts
void myFunction()
{
    // Will appear in the profiler as interval, named myFunction
    const auto sp = ProfilerSignpostForCurrentFunction().makeScopedInterval();
   
    // do some heavy stuff here that is measured within the interval
    
    if (somethingSpecial)
    {
        // Instead of creating an interval, we can also emit an event. We can also create custom signpost names
        NamedProfilerSignpost ("Something special").emitEvent();
       
        // do something special here
    }
}

Below you find the actual implementation, it has become part of our in house framework and I quickly stripped away all namespaces and references to our code, but I think it should work like this. Feel free to comment on it and share improvements to it if you have any, especially to get rid of those macros. The great challenge were the unique asm labels for the static strings, which I approached with a compile time counter implementation combined with again some macros.

#include <os/signpost.h>

class ProfilerSignpost
{
public:
    /** Initializes the profiler signpost facility and sets a name to identify signposts from the product
      in a profiling session. This should usually be the bundle identifier.

      If init has not been called, no signposts will be emitted
   */
    static void init (std::string_view subsystemName = JUCE_STRINGIFY (JucePlugin_CFBundleIdentifier))
    {
        if (log != NULL)
            return;

        if (__builtin_available (macOS 10.14, *))
        {
            log = os_log_create (subsystemName.data(), OS_LOG_CATEGORY_POINTS_OF_INTEREST);
        }
    }

private:
    static inline os_log_t log = NULL; // NOLINT

    /** A availability guarded wrapper around os_signpost_id_generate. Will return 0 in case of running on macOS < 10.14. */
    static os_signpost_id_t generateID()
    {
        if (__builtin_available (macOS 10.14, *))
        {
            jassert (log != NULL); // If you hit this assertion, you probably forgot to call ProfilerSignpost::init
            return os_signpost_id_generate (log);
        }

        return 0;
    }

    /** Helper class to create up to 24 unique log strings, placed in a special section of the binary so that the profiler can access them. */
    template <StringLiteral text, int index>
    class StaticString
    {
    private:
        template <size_t... i>
        static const char* get (const std::index_sequence<i...>&)
        {
            // Reverse engineering takeaway: The asm label seems to be mandatory, otherwise only the first string declared in a translation unit appears in the profiler.
            // The exact label text seems unimportant as long as it's unique. Apple macros generate labels like LOS_##_ns<N> where <N> is a value returned by the __COUNTER__
            // macro. Trying to find a way to generate the label from the string literal template failed so far. Therefore, we need these multiple hardcoded if/else branches,
            // each with different predefined indices in order to build up to 24 unique asm labels.
            #define SIGNPOST_STRING(idx)                                                                                                                                                                            \
            if constexpr (index == idx)                                                                                                                                                                             \
            {                                                                                                                                                                                                       \
                __attribute__ ((section ("__TEXT,__oslogstring,cstring_literals"), internal_linkage)) static const char t[text.len] asm (OS_STRINGIFY (OS_CONCAT (profilerSignpost_, idx))) = { text.value[i]... }; \
                return t;                                                                                                                                                                                           \
            }

            SIGNPOST_STRING (0)
            SIGNPOST_STRING (1)
            SIGNPOST_STRING (2)
            SIGNPOST_STRING (3)
            SIGNPOST_STRING (4)
            SIGNPOST_STRING (5)
            SIGNPOST_STRING (6)
            SIGNPOST_STRING (7)
            SIGNPOST_STRING (8)
            SIGNPOST_STRING (9)
            SIGNPOST_STRING (10)
            SIGNPOST_STRING (11)
            SIGNPOST_STRING (12)
            SIGNPOST_STRING (13)
            SIGNPOST_STRING (14)
            SIGNPOST_STRING (15)
            SIGNPOST_STRING (16)
            SIGNPOST_STRING (17)
            SIGNPOST_STRING (18)
            SIGNPOST_STRING (19)
            SIGNPOST_STRING (20)
            SIGNPOST_STRING (21)
            SIGNPOST_STRING (22)
            SIGNPOST_STRING (23)

#undef SIGNPOST_STRING

            static_assert (index < 24, "Only 24 different named signpost instances are supported per translation unit");
            return nullptr;
        }

    public:
        static const char* get()
        {
            return get (std::make_index_sequence<text.len>());
        }
    };

    /** Returns a string intended to mark the beginning of a signpost interval. */
    static const char* startString()
    {
        __attribute__ ((section ("__TEXT,__oslogstring,cstring_literals"), internal_linkage)) static const char t[] __asm ("profilerSignpost_Begin") = "Begin";
        return t;
    }

    /** Returns a string intended to mark the end of a signpost interval. */
    static const char* endString()
    {
        __attribute__ ((section ("__TEXT,__oslogstring,cstring_literals"), internal_linkage)) static const char t[] __asm ("profilerSignpost_End") = "End";
        return t;
    }

    /** Returns a string intended to mark a signpost event. */
    static const char* eventString()
    {
        __attribute__ ((section ("__TEXT,__oslogstring,cstring_literals"), internal_linkage)) static const char t[] __asm ("profilerSignpost_Event") = "Event";
        return t;
    }

    /** Implementation detail for a consteval counter. See https://stackoverflow.com/a/74453799/10215177 */
    template <auto id>
    class Counter
    {
    private:
        using Tag = Counter;

        struct Generator
        {
            friend consteval auto isDefined (Tag) { return true; }
        };

        friend consteval auto isDefined (Tag);

    public:
        template <class TagType = Tag, auto = isDefined (TagType {})>
        static constexpr auto exists (auto)
        {
            return true;
        }

        static constexpr auto exists (...)
        {
            return Generator(), false;
        }
    };

public:
    /** Returns a unique integer with each invocation. Needed to feed the StaticString instances with unique indices. */
    template <auto id = 0, auto = [] {}>
    static constexpr int uniqueId()
    {
        if constexpr (Counter<id>::exists (id))
        {
            return uniqueId<id + 1>();
        }
        else
        {
            return id;
        }
    }

    /** Implementation of the named macOS profiler signposts. */
    template <StringLiteral name, int index>
    class WithName
    {
    private:
        static void emit (os_signpost_type_t type, const char* typeStr, os_signpost_id_t id)
        {
            if (__builtin_available (macOS 10.14, *))
            {
                // The content of this function body has been mainly generated by expanding the os_signpost_emit_with_type macro.
                if (id != ((os_signpost_id_t) 0) &&
                    id != ((os_signpost_id_t) ~0) &&
                    os_signpost_enabled (log))
                {
                    _Pragma ("clang diagnostic push")
                    _Pragma ("clang diagnostic ignored \"-Wvla\"")
                    _Pragma ("clang diagnostic error \"-Wformat\"")

                    // Todo: Find out if we can add extra runtime strings here.
                    uint8_t _Alignas (16) formatBuffer[__builtin_os_log_format_buffer_size ("")];

                    _os_signpost_emit_with_name_impl (&__dso_handle,
                                                      log,
                                                      type,
                                                      id,
                                                      StaticString<name, index>::get(),
                                                      typeStr,
                                                      (uint8_t*) __builtin_os_log_format (formatBuffer, ""),
                                                      (uint32_t) sizeof (formatBuffer));

                    _Pragma ("clang diagnostic pop")
                }
            }
        }

        class ScopedInterval
        {
        public:
            ScopedInterval()
                : id (generateID())
            {
                if (id > 0)
                    emit (OS_SIGNPOST_INTERVAL_BEGIN, startString(), id);
            }

            ~ScopedInterval()
            {
                if (id > 0)
                    emit (OS_SIGNPOST_INTERVAL_END, endString(), id);
            }

        private:
            os_signpost_id_t id;
        };

    public:
        /** Emits a single event for the named signpost. */
        void emitEvent()
        {
            emit (OS_SIGNPOST_EVENT, eventString(), generateID());
        }

        /** Returns a scoped interval object. */
        ScopedInterval makeScopedInterval()
        {
            return ScopedInterval();
        }
    };
};

/** A macro faking a class. Allows emitting singposts with a unique name.

  We need to generate a unique id number from a consteval counter, which only seems
  to work with the macro solution. The name string has to be a compile time constant string literal.
*/
#define NamedProfilerSignpost(name) ProfilerSignpost::WithName<name, ProfilerSignpost::uniqueId()>()

/** Like NamedProfilerSignpost but always taking the name of the local function as signpost name. */
#define ProfilerSignpostForCurrentFunction ProfilerSignpost::WithName<__PRETTY_FUNCTION__, ProfilerSignpost::uniqueId()>

Edit: Oh wait, I forgot to share that StringLiteral class with you, which proved to be a clever helper when passing string literals as template arguments, also in other contexts:

template <size_t n>
struct StringLiteral
{
    /** This constructor is only intended to be invoked through template argument deduction */
    constexpr StringLiteral (const char (&str)[n]) // NOLINT
    {
        std::copy_n (str, n, value);
    }

    /** The string. */
    char value[n]; // NOLINT

    /** The length of the string. */
    static constexpr size_t len = n;
};

I’ve not played with it a lot but wouldn’t something like this also work:

#include <os/signpost.h>

template<size_t n>
struct StringLiteral
{
    constexpr StringLiteral (const char (&str)[n])
    {
        std::copy_n (str, n, value);
    }

    char value[n];
    static constexpr size_t len = n;
};

template<StringLiteral name>
struct NamedSignpost
{
    NamedSignpost()
    {
        os_signpost_interval_begin (getLog(), id, "", "%s", name.value);
    }
    
    ~NamedSignpost()
    {
        os_signpost_interval_end (getLog(), id, "", "%s", name.value);
    }

private:
    const os_signpost_id_t id  { generateID() };

    static os_log_t getLog()
    {
        static os_log_t log;

        if (log == nullptr)
            log = os_log_create ("", OS_LOG_CATEGORY_POINTS_OF_INTEREST);

        return log;
    }

    static os_signpost_id_t generateID()
    {
        return os_signpost_id_generate (getLog());
    }
};

?

I’m not sure what all the logs and the IDs are for but this seems to display ok in Instruments.

But to be honest, I’m not sure we actually need all the C++20 trickery:

struct NamedSignpost
{
    NamedSignpost (const char* nameToUse)
        : name (nameToUse)
    {
        os_signpost_interval_begin (getLog(), id, "", "%s", name);
    }

    ~NamedSignpost2()
    {
        os_signpost_interval_end (getLog(), id, "", "%s", name);
    }

private:
    const char* name;
    const os_signpost_id_t id  { generateID() };

    static os_log_t getLog()
    {
        static os_log_t log;

        if (log == nullptr)
            log = os_log_create ("", OS_LOG_CATEGORY_POINTS_OF_INTEREST);

        return log;
    }

    static os_signpost_id_t generateID()
    {
        return os_signpost_id_generate (getLog());
    }
};

Of course, I initially tried the same simple approach, but without success. So first of all, did you try both approaches and verified that they actually compile and work as expected at runtime, especially with multiple signpost intervals being emitted in parallel? I had to realise that this was not the case if I went that simple approach. To understand this better, I digged quite a bit into this apple code.

First problem: Only compile time static strings can be used as names

The os_signpost_ function like macros that take a name argument expand to this after some layers of macros:

Static_assert(__builtin_constant_p(name),"format/label/description argument must be a string constant")

So first of all, we see that they enforce that the name is a compile time constant string literal. Attempting to compile something like your second simplified approach where a runtime string is passed to the macro always resulted in a compile error for me, so I’d be surprised to hear that it worked for you.

Second problem: Shadowed name strings

When attempting to wrap all this in that fancy class template in order to have a compile time static string literal, I quickly had to find out that as soon as I started to create multiple signpost intervals in a translation unit, they all appeared with the very same name in the profiler, which was always the name of the signpost declared first. So I digged deeper into the Apple macro world and found this:

__attribute__((section("__TEXT,__oslogstring,cstring_literals"),internal_linkage)) static const char _os_name_str[]__asm(OS_STRINGIFY(OS_CONCAT(LOS_##_ns, __COUNTER__))) = name;

So obviously, that name is assigned to a static variable which is placed in a specific binary section by the linker and furthermore gets a unique assembly label there. The uniqueness of that label is generated by expanding the __COUNTER__ macro every time that macro is called. While this works as expected for separate direct invocations of the macro in the code, the class template code of your first approach will only expand that macro once, which leads to the same assembly label for all strings. This was the start of my experiments with expanding the entire macro and try to rewrite its contents myself. I had to find out that in order to work, any combination of assembly labels work, as long as all occurrences have a translation unit wide unique label.

I tried hard to somehow mangle the actual name string into an asm label but had to realise that this just does not work since the asm keyword is expanded at an earlier pass of the compiler before expanding the template arguments. This is why I then came up with that SIGNPOST_STRING macro in my solution and the compile time counter.

After having spent quite a few hours on this, I decided to leave it in the state as posted above and revisit it at some timepoint in order to try to find an even easier solution. So I’m really happy about proposals on how to make this less complicated, but I’m not as optimistic after having tried all this that there is a super straightforward solution that really works with multiple signposts in one translation unit.

Wow, sounds like you went on a similar epic adventure with compile time strings as I did with Perfetto! Hopefully this stuff will be easier in a few years…

Well I did check that mine works with at least two nested signposts (with different literals).

I was getting the problem that the “name” param needs to be a string literal, so I just made that an empty string literal… Then there is the “meta” argument followed by some variadic format arguments. So I just used “%s” to signify a string and passed the name as a non-literal as the variadic argument. Then it just replaces that like printf.

The downside of this is there probably is some overhead to do the string replacement of the optimiser can’t do it at compile time.

I’m guessing all the nesting etc. works because it uses the signpost_id rather than any names.

The advantage of my way is that it doesn’t require C++20 which we don’t support yet. Has anyone else tried my version above?

Thank you for the module! I tried it, all compiles well, but I cannot find trace file after the standalone or the plugin closes. Where it saves?

Should be in Downloads (mac) or Desktop (windows) :slight_smile:
What also can go wrong is that the app needs to close properly for the trace file to be written - e.g. don’t terminate it by clicking stop in the IDE.

1 Like

I use Linux :slight_smile: No trace file at build dir, tmp, HOME, etc :frowning:

I see. I’ve never run this on Linux! You might want to step into the debugger here to see what file it is trying to write to. Maybe it’s because there’s no folder called Downloads on Linux?

2 Likes

It’s defaulting to a “Downloads” folder in the user directory. Not ideal, but you might be the first person to try the module on Linux!

I opened an issue for better linux support, including getting it running in tests/CI: Explicit Linux Support · Issue #22 · sudara/melatonin_perfetto · GitHub — You could submit a PR or let me know folder you would prefer and I’ll get it added when I’m next working on it.

1 Like