summaryrefslogtreecommitdiffstats
path: root/include/comphelper/traceevent.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'include/comphelper/traceevent.hxx')
-rw-r--r--include/comphelper/traceevent.hxx217
1 files changed, 217 insertions, 0 deletions
diff --git a/include/comphelper/traceevent.hxx b/include/comphelper/traceevent.hxx
new file mode 100644
index 0000000000..6409c43eee
--- /dev/null
+++ b/include/comphelper/traceevent.hxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+*/
+
+#ifndef INCLUDED_COMPHELPER_TRACEEVENT_HXX
+#define INCLUDED_COMPHELPER_TRACEEVENT_HXX
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <osl/time.h>
+#include <com/sun/star/uno/Sequence.h>
+#include <comphelper/comphelperdllapi.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+
+// implementation of XToolkitExperimental profiling API
+
+namespace comphelper
+{
+class COMPHELPER_DLLPUBLIC TraceEvent
+{
+private:
+ static int getPid()
+ {
+ oslProcessInfo aProcessInfo;
+ aProcessInfo.Size = sizeof(oslProcessInfo);
+ if (osl_getProcessInfo(nullptr, osl_Process_IDENTIFIER, &aProcessInfo)
+ == osl_Process_E_None)
+ return aProcessInfo.Ident;
+ return -1;
+ }
+
+ static std::size_t s_nBufferSize;
+ static void (*s_pBufferFullCallback)();
+
+protected:
+ static std::atomic<bool> s_bRecording; // true during recording
+
+ static void addRecording(const OUString& sObject);
+
+ static long long getNow()
+ {
+ TimeValue systemTime;
+ osl_getSystemTime(&systemTime);
+ return static_cast<long long>(systemTime.Seconds) * 1000000 + systemTime.Nanosec / 1000;
+ }
+
+ static OUString createArgsString(const std::map<OUString, OUString>& args)
+ {
+ if (args.size() == 0)
+ return "";
+
+ OUStringBuffer sResult(",\"args\":{");
+ bool first = true;
+ for (auto& i : args)
+ {
+ if (!first)
+ sResult.append(',');
+ sResult.append("\"" + i.first + "\":\"" + i.second + "\"");
+ first = false;
+ }
+ sResult.append('}');
+
+ return sResult.makeStringAndClear();
+ }
+
+ const int m_nPid;
+ const OUString m_sArgs;
+
+ TraceEvent(OUString sArgs)
+ : m_nPid(s_bRecording ? getPid() : 1)
+ , m_sArgs(std::move(sArgs))
+ {
+ }
+
+ TraceEvent(const std::map<OUString, OUString>& aArgs)
+ : TraceEvent(createArgsString(aArgs))
+ {
+ }
+
+public:
+ static void addInstantEvent(const char* sName, const std::map<OUString, OUString>& args
+ = std::map<OUString, OUString>());
+
+ static void startRecording();
+ static void stopRecording();
+ static void setBufferSizeAndCallback(std::size_t bufferSize, void (*bufferFullCallback)());
+
+ static std::vector<OUString> getEventVectorAndClear();
+
+ static css::uno::Sequence<OUString> getRecordingAndClear();
+};
+
+class COMPHELPER_DLLPUBLIC NamedEvent : public TraceEvent
+{
+protected:
+ const char* m_sName;
+
+ NamedEvent(const char* sName, const OUString& sArgs)
+ : TraceEvent(sArgs)
+ , m_sName(sName ? sName : "(null)")
+ {
+ }
+
+ NamedEvent(const char* sName, const std::map<OUString, OUString>& aArgs)
+ : TraceEvent(aArgs)
+ , m_sName(sName ? sName : "(null)")
+ {
+ }
+};
+
+// An AsyncEvent generates an 'S' (start) event when constructed and a 'F' (finish) event when it
+// is destructed.
+
+// The Trace Event specification claims that these event types are deprecated and replaces by
+// nestable 'b' (begin) and 'e' (end) events, but Chrome does not seem to support those.
+
+// To generate a pair of 'S' and 'F' events, create an AsyncEvent object using the AsyncEvent(const
+// char* sName) constructor when you want the 'S' event to be generated, and destroy it when you
+// want the corresponding 'F' event to be generated.
+
+class COMPHELPER_DLLPUBLIC AsyncEvent : public NamedEvent,
+ public std::enable_shared_from_this<AsyncEvent>
+{
+ static int s_nIdCounter;
+ int m_nId;
+ bool m_bBeginRecorded;
+
+ AsyncEvent(const char* sName, int nId, const std::map<OUString, OUString>& args)
+ : NamedEvent(sName, args)
+ , m_nId(nId)
+ , m_bBeginRecorded(false)
+ {
+ if (!s_bRecording)
+ return;
+
+ long long nNow = getNow();
+
+ // Generate a "Start" (type S) event
+ TraceEvent::addRecording("{"
+ "\"name\":\""
+ + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8)
+ + "\","
+ "\"ph\":\"S\""
+ ","
+ "\"id\":"
+ + OUString::number(m_nId) + m_sArgs
+ + ","
+ "\"ts\":"
+ + OUString::number(nNow)
+ + ","
+ "\"pid\":"
+ + OUString::number(m_nPid)
+ + ","
+ "\"tid\":"
+ + OUString::number(osl_getThreadIdentifier(nullptr)) + "},");
+ m_bBeginRecorded = true;
+ }
+
+ void generateEnd()
+ {
+ if (!m_bBeginRecorded)
+ return;
+
+ m_bBeginRecorded = false;
+
+ long long nNow = getNow();
+ // Generate a "Finish" (type F) event
+ TraceEvent::addRecording("{"
+ "\"name\":\""
+ + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8)
+ + "\","
+ "\"ph\":\"F\""
+ ","
+ "\"id\":"
+ + OUString::number(m_nId) + m_sArgs
+ + ","
+ "\"ts\":"
+ + OUString::number(nNow)
+ + ","
+ "\"pid\":"
+ + OUString::number(m_nPid)
+ + ","
+ "\"tid\":"
+ + OUString::number(osl_getThreadIdentifier(nullptr)) + "},");
+ }
+
+public:
+ AsyncEvent(const char* sName,
+ const std::map<OUString, OUString>& args = std::map<OUString, OUString>())
+ : AsyncEvent(sName, s_nIdCounter++, args)
+ {
+ }
+
+ ~AsyncEvent() { generateEnd(); }
+
+ void finish() { generateEnd(); }
+};
+
+} // namespace comphelper
+
+#endif // INCLUDED_COMPHELPER_TRACEEVENT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */