Coverage Report

Created: 2026-09-28 10:59

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
732k
        : m_nPid(s_bRecording ? getPid() : 1)
89
732k
        , m_sArgs(std::move(sArgs))
90
732k
    {
91
732k
    }
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
105
    static std::vector<OUString> getEventVectorAndClear();
106
107
    static css::uno::Sequence<OUString> getRecordingAndClear();
108
};
109
110
class COMPHELPER_DLLPUBLIC NamedEvent : public TraceEvent
111
{
112
protected:
113
    const char* m_sName;
114
115
    NamedEvent(const char* sName, const OUString& sArgs)
116
732k
        : TraceEvent(sArgs)
117
732k
        , m_sName(sName ? sName : "(null)")
118
732k
    {
119
732k
    }
120
121
    NamedEvent(const char* sName, const std::map<OUString, OUString>& aArgs)
122
        : TraceEvent(aArgs)
123
        , m_sName(sName ? sName : "(null)")
124
0
    {
125
0
    }
126
};
127
128
// An AsyncEvent generates an 'S' (start) event when constructed and a 'F' (finish) event when it
129
// is destructed.
130
131
// The Trace Event specification claims that these event types are deprecated and replaces by
132
// nestable 'b' (begin) and 'e' (end) events, but Chrome does not seem to support those.
133
134
// To generate a pair of 'S' and 'F' events, create an AsyncEvent object using the AsyncEvent(const
135
// char* sName) constructor when you want the 'S' event to be generated, and destroy it when you
136
// want the corresponding 'F' event to be generated.
137
138
class COMPHELPER_DLLPUBLIC AsyncEvent : public NamedEvent,
139
                                        public std::enable_shared_from_this<AsyncEvent>
140
{
141
    static int s_nIdCounter;
142
    int m_nId;
143
    bool m_bBeginRecorded;
144
145
    AsyncEvent(const char* sName, int nId, const std::map<OUString, OUString>& args)
146
        : NamedEvent(sName, args)
147
        , m_nId(nId)
148
        , m_bBeginRecorded(false)
149
0
    {
150
0
        if (!s_bRecording)
151
0
            return;
152
0
153
0
        long long nNow = getNow();
154
0
155
0
        // Generate a "Start" (type S) event
156
0
        TraceEvent::addRecording("{"
157
0
                                 "\"name\":\""
158
0
                                 + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8)
159
0
                                 + "\","
160
0
                                   "\"ph\":\"S\""
161
0
                                   ","
162
0
                                   "\"id\":"
163
0
                                 + OUString::number(m_nId) + m_sArgs
164
0
                                 + ","
165
0
                                   "\"ts\":"
166
0
                                 + OUString::number(nNow)
167
0
                                 + ","
168
0
                                   "\"pid\":"
169
0
                                 + OUString::number(m_nPid)
170
0
                                 + ","
171
0
                                   "\"tid\":"
172
0
                                 + OUString::number(osl_getThreadIdentifier(nullptr)) + "},");
173
0
        m_bBeginRecorded = true;
174
0
    }
175
176
    void generateEnd()
177
0
    {
178
0
        if (!m_bBeginRecorded)
179
0
            return;
180
0
181
0
        m_bBeginRecorded = false;
182
0
183
0
        long long nNow = getNow();
184
0
        // Generate a "Finish" (type F) event
185
0
        TraceEvent::addRecording("{"
186
0
                                 "\"name\":\""
187
0
                                 + OUString(m_sName, strlen(m_sName), RTL_TEXTENCODING_UTF8)
188
0
                                 + "\","
189
0
                                   "\"ph\":\"F\""
190
0
                                   ","
191
0
                                   "\"id\":"
192
0
                                 + OUString::number(m_nId) + m_sArgs
193
0
                                 + ","
194
0
                                   "\"ts\":"
195
0
                                 + OUString::number(nNow)
196
0
                                 + ","
197
0
                                   "\"pid\":"
198
0
                                 + OUString::number(m_nPid)
199
0
                                 + ","
200
0
                                   "\"tid\":"
201
0
                                 + OUString::number(osl_getThreadIdentifier(nullptr)) + "},");
202
0
    }
203
204
public:
205
    AsyncEvent(const char* sName,
206
               const std::map<OUString, OUString>& args = std::map<OUString, OUString>())
207
        : AsyncEvent(sName, s_nIdCounter++, args)
208
0
    {
209
0
    }
210
211
0
    ~AsyncEvent() { generateEnd(); }
212
213
0
    void finish() { generateEnd(); }
214
};
215
216
} // namespace comphelper
217
218
#endif // INCLUDED_COMPHELPER_TRACEEVENT_HXX
219
220
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */