/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include // 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 s_bRecording; // true during recording static void addRecording(const OUString& sObject); static long long getNow() { TimeValue systemTime; osl_getSystemTime(&systemTime); return static_cast(systemTime.Seconds) * 1000000 + systemTime.Nanosec / 1000; } static OUString createArgsString(const std::map& args) { if (args.size() == 0) return ""; OUStringBuffer sResult; sResult.append(",\"args\":{"); bool first = true; for (auto& i : args) { if (!first) sResult.append(','); sResult.append('"'); sResult.append(i.first); sResult.append("\":\""); sResult.append(i.second); sResult.append('"'); 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& aArgs) : TraceEvent(createArgsString(aArgs)) { } public: static void addInstantEvent(const char* sName, const std::map& args = std::map()); static void startRecording(); static void stopRecording(); static void setBufferSizeAndCallback(std::size_t bufferSize, void (*bufferFullCallback)()); static std::vector getEventVectorAndClear(); static css::uno::Sequence 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& 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 { static int s_nIdCounter; int m_nId; bool m_bBeginRecorded; AsyncEvent(const char* sName, int nId, const std::map& 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& args = std::map()) : AsyncEvent(sName, s_nIdCounter++, args) { } ~AsyncEvent() { generateEnd(); } void finish() { generateEnd(); } }; } // namespace comphelper #endif // INCLUDED_COMPHELPER_TRACEEVENT_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */