Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */