libreoffice-online/common/TraceEvent.cpp
Tor Lillqvist 4f0f7d6123 Avoid assertion failure if toggling Trace Event generation back and forth
Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: Ie6b7144ecf16faa9d22e7d87801d9dbe9b97d3fc
2021-06-30 12:40:08 +03:00

182 lines
4.8 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// To build a freestanding test executable for just Tracevent:
// clang++ -Wall -Wextra -DTEST_TRACEEVENT_EXE TraceEvent.cpp -o TraceEvent -pthread
#include <cassert>
#include <mutex>
#include <sstream>
#include "TraceEvent.hpp"
std::atomic<bool> TraceEvent::recordingOn(false);
thread_local int TraceEvent::threadLocalNesting = 0; // level of overlapped zones
static std::mutex mutex;
void TraceEvent::emitInstantEvent(const std::string& name, const std::string& argsOrEmpty)
{
if (!recordingOn)
return;
emitOneRecording("{"
"\"name\":\""
+ name
+ "\","
"\"ph\":\"i\""
+ ",\"ts\":"
+ std::to_string(std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count())
+ ","
"\"pid\":"
+ std::to_string(getpid())
+ ","
"\"tid\":"
+ std::to_string(getThreadId())
+ (argsOrEmpty.length() == 0 ? "" : ",\"args\":" + argsOrEmpty)
+ "}"
// We add a trailing comma and newline, it is up to the code that handles these "recordings"
// (outputs them into a JSON array) to remove the final comma before adding the terminating
// ']'.
",\n");
}
void TraceEvent::startRecording()
{
recordingOn = true;
threadLocalNesting = 0;
}
void TraceEvent::stopRecording() { recordingOn = false; }
void ProfileZone::emitRecording()
{
if (!recordingOn)
return;
auto now = std::chrono::system_clock::now();
// Generate a single "Complete Event" (type X)
auto duration = now - _createTime;
std::string recordingData(
"{"
"\"name\":\""
+ std::string(_name)
+ "\","
"\"ph\":\"X\","
"\"ts\":"
+ std::to_string(std::chrono::duration_cast<std::chrono::microseconds>(
_createTime.time_since_epoch())
.count())
+ ","
"\"dur\":"
+ std::to_string(std::chrono::duration_cast<std::chrono::microseconds>(duration).count())
+ ","
"\"pid\":"
+ std::to_string(_pid)
+ ","
"\"tid\":"
+ std::to_string(getThreadId())
+ (_args.length() == 0 ? "" : ",\"args\":" + _args)
+ "},");
std::lock_guard<std::mutex> guard(mutex);
emitOneRecording(recordingData);
}
#ifdef TEST_TRACEEVENT_EXE
#include <iostream>
#include <thread>
void TraceEvent::emitOneRecording(const std::string &recording)
{
std::cout << " " << recording;
}
int main(int, char**)
{
std::cout << "[\n";
TraceEvent::startRecording();
{
ProfileZone b("first block");
for (auto n = 0; n < 100000000; n++)
{
volatile auto x = n * 42;
(void)x;
}
}
std::thread t1([]() {
ProfileZone b("thread t1");
for (auto n = 0; n < 400000000; n++)
{
volatile auto x = n * 42;
(void)x;
}
});
std::thread t2([]() {
ProfileZone b("thread t2");
for (auto n = 0; n < 400000000; n++)
{
auto x = n * 42ll;
if (n % 50000000 == 0)
TraceEvent::emitInstantEvent("instant t2." + std::to_string(x));
}
});
std::thread t3([]() {
ProfileZone b("thread t3", { { "foo", "bar"} } );
for (auto n = 0; n < 400000000; n++)
{
auto x = n * 42ll;
if (n % 50000000 == 0)
TraceEvent::emitInstantEvent("instant t3." + std::to_string(x));
}
});
{
ProfileZone b("second block");
for (auto n = 0; n < 300000000; n++)
{
auto x = n * 42ll;
if (n % 50000000 == 0)
TraceEvent::emitInstantEvent("instant m." + std::to_string(x));
}
}
t1.join();
t2.join();
t3.join();
// Intentional misuse: overlapping ProfileZones. Will generate "Incorrect ProfileZone nesting" messages.
auto p1 = new ProfileZone("p1");
auto p2 = new ProfileZone("p2");
delete p1;
delete p2;
// Add a dummy integer last in the array to avoid incorrect JSON syntax
std::cout << " 0\n";
std::cout << "]\n";
return 0;
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */