Avoid potential negative array index access to cached text.
[LibreOffice.git] / include / comphelper / traceevent.hxx
blob6409c43eee4a7f6a3c5ad6d50993d053e42c843b
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #ifndef INCLUDED_COMPHELPER_TRACEEVENT_HXX
11 #define INCLUDED_COMPHELPER_TRACEEVENT_HXX
13 #include <sal/config.h>
15 #include <atomic>
16 #include <map>
17 #include <memory>
18 #include <utility>
19 #include <vector>
21 #include <osl/process.h>
22 #include <osl/thread.h>
23 #include <osl/time.h>
24 #include <com/sun/star/uno/Sequence.h>
25 #include <comphelper/comphelperdllapi.h>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/ustring.hxx>
29 // implementation of XToolkitExperimental profiling API
31 namespace comphelper
33 class COMPHELPER_DLLPUBLIC TraceEvent
35 private:
36 static int getPid()
38 oslProcessInfo aProcessInfo;
39 aProcessInfo.Size = sizeof(oslProcessInfo);
40 if (osl_getProcessInfo(nullptr, osl_Process_IDENTIFIER, &aProcessInfo)
41 == osl_Process_E_None)
42 return aProcessInfo.Ident;
43 return -1;
46 static std::size_t s_nBufferSize;
47 static void (*s_pBufferFullCallback)();
49 protected:
50 static std::atomic<bool> s_bRecording; // true during recording
52 static void addRecording(const OUString& sObject);
54 static long long getNow()
56 TimeValue systemTime;
57 osl_getSystemTime(&systemTime);
58 return static_cast<long long>(systemTime.Seconds) * 1000000 + systemTime.Nanosec / 1000;
61 static OUString createArgsString(const std::map<OUString, OUString>& args)
63 if (args.size() == 0)
64 return "";
66 OUStringBuffer sResult(",\"args\":{");
67 bool first = true;
68 for (auto& i : args)
70 if (!first)
71 sResult.append(',');
72 sResult.append("\"" + i.first + "\":\"" + i.second + "\"");
73 first = false;
75 sResult.append('}');
77 return sResult.makeStringAndClear();
80 const int m_nPid;
81 const OUString m_sArgs;
83 TraceEvent(OUString sArgs)
84 : m_nPid(s_bRecording ? getPid() : 1)
85 , m_sArgs(std::move(sArgs))
89 TraceEvent(const std::map<OUString, OUString>& aArgs)
90 : TraceEvent(createArgsString(aArgs))
94 public:
95 static void addInstantEvent(const char* sName, const std::map<OUString, OUString>& args
96 = std::map<OUString, OUString>());
98 static void startRecording();
99 static void stopRecording();
100 static void setBufferSizeAndCallback(std::size_t bufferSize, void (*bufferFullCallback)());
102 static std::vector<OUString> getEventVectorAndClear();
104 static css::uno::Sequence<OUString> getRecordingAndClear();
107 class COMPHELPER_DLLPUBLIC NamedEvent : public TraceEvent
109 protected:
110 const char* m_sName;
112 NamedEvent(const char* sName, const OUString& sArgs)
113 : TraceEvent(sArgs)
114 , m_sName(sName ? sName : "(null)")
118 NamedEvent(const char* sName, const std::map<OUString, OUString>& aArgs)
119 : TraceEvent(aArgs)
120 , m_sName(sName ? sName : "(null)")
125 // An AsyncEvent generates an 'S' (start) event when constructed and a 'F' (finish) event when it
126 // is destructed.
128 // The Trace Event specification claims that these event types are deprecated and replaces by
129 // nestable 'b' (begin) and 'e' (end) events, but Chrome does not seem to support those.
131 // To generate a pair of 'S' and 'F' events, create an AsyncEvent object using the AsyncEvent(const
132 // char* sName) constructor when you want the 'S' event to be generated, and destroy it when you
133 // want the corresponding 'F' event to be generated.
135 class COMPHELPER_DLLPUBLIC AsyncEvent : public NamedEvent,
136 public std::enable_shared_from_this<AsyncEvent>
138 static int s_nIdCounter;
139 int m_nId;
140 bool m_bBeginRecorded;
142 AsyncEvent(const char* sName, int nId, const std::map<OUString, OUString>& args)
143 : NamedEvent(sName, args)
144 , m_nId(nId)
145 , m_bBeginRecorded(false)
147 if (!s_bRecording)
148 return;
150 long long nNow = getNow();
152 // Generate a "Start" (type S) event
153 TraceEvent::addRecording("{"
154 "\"name\":\""
155 + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8)
156 + "\","
157 "\"ph\":\"S\""
159 "\"id\":"
160 + OUString::number(m_nId) + m_sArgs
161 + ","
162 "\"ts\":"
163 + OUString::number(nNow)
164 + ","
165 "\"pid\":"
166 + OUString::number(m_nPid)
167 + ","
168 "\"tid\":"
169 + OUString::number(osl_getThreadIdentifier(nullptr)) + "},");
170 m_bBeginRecorded = true;
173 void generateEnd()
175 if (!m_bBeginRecorded)
176 return;
178 m_bBeginRecorded = false;
180 long long nNow = getNow();
181 // Generate a "Finish" (type F) event
182 TraceEvent::addRecording("{"
183 "\"name\":\""
184 + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8)
185 + "\","
186 "\"ph\":\"F\""
188 "\"id\":"
189 + OUString::number(m_nId) + m_sArgs
190 + ","
191 "\"ts\":"
192 + OUString::number(nNow)
193 + ","
194 "\"pid\":"
195 + OUString::number(m_nPid)
196 + ","
197 "\"tid\":"
198 + OUString::number(osl_getThreadIdentifier(nullptr)) + "},");
201 public:
202 AsyncEvent(const char* sName,
203 const std::map<OUString, OUString>& args = std::map<OUString, OUString>())
204 : AsyncEvent(sName, s_nIdCounter++, args)
208 ~AsyncEvent() { generateEnd(); }
210 void finish() { generateEnd(); }
213 } // namespace comphelper
215 #endif // INCLUDED_COMPHELPER_TRACEEVENT_HXX
217 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */