/src/libreoffice/include/comphelper/traceevent.hxx
Line | Count | Source |
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. |
4 | | * |
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 | | */ |
9 | | |
10 | | #ifndef INCLUDED_COMPHELPER_TRACEEVENT_HXX |
11 | | #define INCLUDED_COMPHELPER_TRACEEVENT_HXX |
12 | | |
13 | | #include <sal/config.h> |
14 | | |
15 | | #include <atomic> |
16 | | #include <map> |
17 | | #include <memory> |
18 | | #include <utility> |
19 | | #include <vector> |
20 | | |
21 | | #include <osl/process.h> |
22 | | #include <osl/thread.h> |
23 | | #include <osl/time.h> |
24 | | #include <comphelper/comphelperdllapi.h> |
25 | | #include <rtl/ustrbuf.hxx> |
26 | | #include <rtl/ustring.hxx> |
27 | | |
28 | | namespace com::sun::star::uno |
29 | | { |
30 | | template <class E> class Sequence; |
31 | | } |
32 | | |
33 | | // implementation of XToolkitExperimental profiling API |
34 | | |
35 | | namespace comphelper |
36 | | { |
37 | | class COMPHELPER_DLLPUBLIC TraceEvent |
38 | | { |
39 | | private: |
40 | | static int getPid() |
41 | 0 | { |
42 | 0 | oslProcessInfo aProcessInfo; |
43 | 0 | aProcessInfo.Size = sizeof(oslProcessInfo); |
44 | 0 | if (osl_getProcessInfo(nullptr, osl_Process_IDENTIFIER, &aProcessInfo) |
45 | 0 | == osl_Process_E_None) |
46 | 0 | return aProcessInfo.Ident; |
47 | 0 | return -1; |
48 | 0 | } |
49 | | |
50 | | static std::size_t s_nBufferSize; |
51 | | static void (*s_pBufferFullCallback)(); |
52 | | |
53 | | protected: |
54 | | static std::atomic<bool> s_bRecording; // true during recording |
55 | | |
56 | | static void addRecording(const OUString& sObject); |
57 | | |
58 | | static long long getNow() |
59 | 0 | { |
60 | 0 | TimeValue systemTime; |
61 | 0 | osl_getSystemTime(&systemTime); |
62 | 0 | return static_cast<long long>(systemTime.Seconds) * 1000000 + systemTime.Nanosec / 1000; |
63 | 0 | } |
64 | | |
65 | | static OUString createArgsString(const std::map<OUString, OUString>& args) |
66 | 0 | { |
67 | 0 | if (args.size() == 0) |
68 | 0 | return u""_ustr; |
69 | | |
70 | 0 | OUStringBuffer sResult(",\"args\":{"); |
71 | 0 | bool first = true; |
72 | 0 | for (auto& i : args) |
73 | 0 | { |
74 | 0 | if (!first) |
75 | 0 | sResult.append(','); |
76 | 0 | sResult.append("\"" + i.first + "\":\"" + i.second + "\""); |
77 | 0 | first = false; |
78 | 0 | } |
79 | 0 | sResult.append('}'); |
80 | |
|
81 | 0 | return sResult.makeStringAndClear(); |
82 | 0 | } |
83 | | |
84 | | const int m_nPid; |
85 | | const OUString m_sArgs; |
86 | | |
87 | | TraceEvent(OUString sArgs) |
88 | 656k | : m_nPid(s_bRecording ? getPid() : 1) |
89 | 656k | , m_sArgs(std::move(sArgs)) |
90 | 656k | { |
91 | 656k | } |
92 | | |
93 | | TraceEvent(const std::map<OUString, OUString>& aArgs) |
94 | | : TraceEvent(createArgsString(aArgs)) |
95 | 0 | { |
96 | 0 | } |
97 | | |
98 | | public: |
99 | | static void addInstantEvent(const char* sName, const std::map<OUString, OUString>& args |
100 | | = std::map<OUString, OUString>()); |
101 | | |
102 | | static void startRecording(); |
103 | | static void stopRecording(); |
104 | | static void setBufferSizeAndCallback(std::size_t bufferSize, void (*bufferFullCallback)()); |
105 | | |
106 | | static std::vector<OUString> getEventVectorAndClear(); |
107 | | |
108 | | static css::uno::Sequence<OUString> getRecordingAndClear(); |
109 | | }; |
110 | | |
111 | | class COMPHELPER_DLLPUBLIC NamedEvent : public TraceEvent |
112 | | { |
113 | | protected: |
114 | | const char* m_sName; |
115 | | |
116 | | NamedEvent(const char* sName, const OUString& sArgs) |
117 | 656k | : TraceEvent(sArgs) |
118 | 656k | , m_sName(sName ? sName : "(null)") |
119 | 656k | { |
120 | 656k | } |
121 | | |
122 | | NamedEvent(const char* sName, const std::map<OUString, OUString>& aArgs) |
123 | | : TraceEvent(aArgs) |
124 | | , m_sName(sName ? sName : "(null)") |
125 | 0 | { |
126 | 0 | } |
127 | | }; |
128 | | |
129 | | // An AsyncEvent generates an 'S' (start) event when constructed and a 'F' (finish) event when it |
130 | | // is destructed. |
131 | | |
132 | | // The Trace Event specification claims that these event types are deprecated and replaces by |
133 | | // nestable 'b' (begin) and 'e' (end) events, but Chrome does not seem to support those. |
134 | | |
135 | | // To generate a pair of 'S' and 'F' events, create an AsyncEvent object using the AsyncEvent(const |
136 | | // char* sName) constructor when you want the 'S' event to be generated, and destroy it when you |
137 | | // want the corresponding 'F' event to be generated. |
138 | | |
139 | | class COMPHELPER_DLLPUBLIC AsyncEvent : public NamedEvent, |
140 | | public std::enable_shared_from_this<AsyncEvent> |
141 | | { |
142 | | static int s_nIdCounter; |
143 | | int m_nId; |
144 | | bool m_bBeginRecorded; |
145 | | |
146 | | AsyncEvent(const char* sName, int nId, const std::map<OUString, OUString>& args) |
147 | | : NamedEvent(sName, args) |
148 | | , m_nId(nId) |
149 | | , m_bBeginRecorded(false) |
150 | 0 | { |
151 | 0 | if (!s_bRecording) |
152 | 0 | return; |
153 | 0 |
|
154 | 0 | long long nNow = getNow(); |
155 | 0 |
|
156 | 0 | // Generate a "Start" (type S) event |
157 | 0 | TraceEvent::addRecording("{" |
158 | 0 | "\"name\":\"" |
159 | 0 | + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8) |
160 | 0 | + "\"," |
161 | 0 | "\"ph\":\"S\"" |
162 | 0 | "," |
163 | 0 | "\"id\":" |
164 | 0 | + OUString::number(m_nId) + m_sArgs |
165 | 0 | + "," |
166 | 0 | "\"ts\":" |
167 | 0 | + OUString::number(nNow) |
168 | 0 | + "," |
169 | 0 | "\"pid\":" |
170 | 0 | + OUString::number(m_nPid) |
171 | 0 | + "," |
172 | 0 | "\"tid\":" |
173 | 0 | + OUString::number(osl_getThreadIdentifier(nullptr)) + "},"); |
174 | 0 | m_bBeginRecorded = true; |
175 | 0 | } |
176 | | |
177 | | void generateEnd() |
178 | 0 | { |
179 | 0 | if (!m_bBeginRecorded) |
180 | 0 | return; |
181 | 0 |
|
182 | 0 | m_bBeginRecorded = false; |
183 | 0 |
|
184 | 0 | long long nNow = getNow(); |
185 | 0 | // Generate a "Finish" (type F) event |
186 | 0 | TraceEvent::addRecording("{" |
187 | 0 | "\"name\":\"" |
188 | 0 | + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8) |
189 | 0 | + "\"," |
190 | 0 | "\"ph\":\"F\"" |
191 | 0 | "," |
192 | 0 | "\"id\":" |
193 | 0 | + OUString::number(m_nId) + m_sArgs |
194 | 0 | + "," |
195 | 0 | "\"ts\":" |
196 | 0 | + OUString::number(nNow) |
197 | 0 | + "," |
198 | 0 | "\"pid\":" |
199 | 0 | + OUString::number(m_nPid) |
200 | 0 | + "," |
201 | 0 | "\"tid\":" |
202 | 0 | + OUString::number(osl_getThreadIdentifier(nullptr)) + "},"); |
203 | 0 | } |
204 | | |
205 | | public: |
206 | | AsyncEvent(const char* sName, |
207 | | const std::map<OUString, OUString>& args = std::map<OUString, OUString>()) |
208 | | : AsyncEvent(sName, s_nIdCounter++, args) |
209 | 0 | { |
210 | 0 | } |
211 | | |
212 | 0 | ~AsyncEvent() { generateEnd(); } |
213 | | |
214 | 0 | void finish() { generateEnd(); } |
215 | | }; |
216 | | |
217 | | } // namespace comphelper |
218 | | |
219 | | #endif // INCLUDED_COMPHELPER_TRACEEVENT_HXX |
220 | | |
221 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |