libreoffice-online/common/TraceEvent.hpp
Tor Lillqvist 4c68a97ce5 Re-factor Trace Event stuff for improved functionality and thread safety
Write to the Trace Event JSON file in just one place, protected by a
mutex.

Handle metadata events separately. We want them to propagate to the
output if Event Trace generation is just enabled, regardless whether
it has been turned on or not.

We can send the metadata for the Kit process only after we have opened
the docuemnt as sending a Trace Event to WSD uses the (singleton)
Document object in Kit.

Introduce some new functions for the above and adapt callers
appropriately.

Generate a Complete event for the handling of one image tile, from
setting the src attribute of the Image object to finishing the onload
function.

Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: I5978e0fb2495e0d2dc479bf861eb4ac7da03fa50
2021-06-21 12:43:17 +03:00

204 lines
5.3 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/.
*/
#pragma once
#include <atomic>
#include <chrono>
#include <map>
#include <string>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
#ifdef TEST_TRACEEVENT_EXE
#include <iostream>
#else
#include <Log.hpp>
#endif
// The base class for objects generating Trace Events when enabled.
//
// It depends on the embedding processs what is done to the Trace Events generated. In the WSD
// process they are written to the Trace Event log file as generated (as buffered by the C++
// library). In the Kit process they are buffered and then sent to the WSD process for writing to
// the same log file. In the TraceEvent test program they are written out to stdout.
class TraceEvent
{
private:
static void emitInstantEvent(const std::string& name, const std::string& args);
protected:
static std::atomic<bool> recordingOn; // True during recoding/emission
int _pid;
std::string _args;
thread_local static int threadLocalNesting; // For use only by the ProfileZone derived class
static long getThreadId()
{
#ifdef TEST_TRACEEVENT_EXE
static thread_local int threadId = 0;
static std::atomic<int> threadCounter(1);
if (!threadId)
threadId = threadCounter++;
return threadId;
#else
return Util::getThreadId();
#endif
}
static std::string createArgsString(const std::map<std::string, std::string>& args)
{
if (!recordingOn)
return "0";
std::string result = "{";
bool first = true;
for (auto i : args)
{
if (!first)
result += ',';
result += '"';
result += i.first;
result += "\":\"";
result += i.second;
result += '"';
first = false;
}
result += '}';
return result;
}
TraceEvent(const std::string &args)
: _pid(-1)
, _args(args)
{
if (recordingOn)
{
_pid = getpid();
}
}
public:
static void startRecording();
static void stopRecording();
static bool isRecordingOn()
{
return recordingOn;
}
static void emitInstantEvent(const std::string& name)
{
emitInstantEvent(name, "");
}
static void emitInstantEvent(const std::string& name, const std::map<std::string, std::string>& args)
{
emitInstantEvent(name, createArgsString(args));
}
// These methods need to be implemented separately in the WSD and Kit processes. (WSD writes the
// actual Trace Event log file, Kit just forwards the Trace Events to WSD for output.)
// This should do its thing if Trace Event generation is enabled, even if not turned on. Used
// for metadata that will be needed by a Trace Event viewer if Trace Event generation is turned
// on later during the process life-time.
static void emitOneRecordingIfEnabled(const std::string &recording);
// Unless Trace Event generation is enabled and turned on, this should do nothing.
static void emitOneRecording(const std::string &recording);
TraceEvent(const TraceEvent&) = delete;
void operator=(const TraceEvent&) = delete;
};
class NamedEvent : public TraceEvent
{
protected:
const std::string _name;
NamedEvent(const std::string& name)
: TraceEvent("")
, _name(name)
{
}
NamedEvent(const std::string& name, const std::string& args)
: TraceEvent(args)
, _name(name)
{
}
NamedEvent(const std::string& name, const std::map<std::string, std::string>& args)
: TraceEvent(createArgsString(args))
, _name(name)
{
}
};
class ProfileZone : public NamedEvent
{
private:
std::chrono::time_point<std::chrono::system_clock> _createTime;
int _nesting;
void emitRecording();
ProfileZone(const std::string& name, const std::string &args)
: NamedEvent(name, args)
, _nesting(-1)
{
if (recordingOn)
{
// Use system_clock as that matches the clock_gettime(CLOCK_REALTIME) that core uses.
_createTime = std::chrono::system_clock::now();
_nesting = threadLocalNesting++;
}
}
public:
ProfileZone(const std::string& name, const std::map<std::string, std::string> &arguments)
: ProfileZone(name, createArgsString(arguments))
{
}
ProfileZone(const char* id)
: ProfileZone(id, "")
{
}
~ProfileZone()
{
if (_pid > 0)
{
threadLocalNesting--;
if (_nesting != threadLocalNesting)
{
#ifdef TEST_TRACEEVENT_EXE
std::cerr << "Incorrect ProfileZone nesting for " << _name << "\n";
#else
LOG_WRN("Incorrect ProfileZone nesting for " << _name);
#endif
}
else
{
emitRecording();
}
}
}
ProfileZone(const ProfileZone&) = delete;
void operator=(const ProfileZone&) = delete;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */