1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #pragma once
27 
28 #include "perfprofiler_global.h"
29 #include "perfeventtype.h"
30 
31 #include <tracing/traceevent.h>
32 #include <utils/qtcassert.h>
33 
34 #include <QVariant>
35 #include <QVector>
36 #include <QDataStream>
37 
38 namespace PerfProfiler {
39 namespace Internal {
40 
41 class PerfEvent : public Timeline::TraceEvent
42 {
43 public:
44     static const qint32 staticClassId = 0x70657266; // 'perf'
45 
PerfEvent()46     PerfEvent() : TraceEvent(staticClassId) {}
47 
48     enum SpecialTypeId {
49         AmbiguousTypeId        =  0,
50         InvalidTypeId          = -1,
51         ThreadStartTypeId      = -2,
52         ThreadEndTypeId        = -3,
53         LostTypeId             = -4,
54         ContextSwitchTypeId    = -5,
55         LastSpecialTypeId      = -6
56     };
57 
numAttributes()58     int numAttributes() const { return m_values.length() + 1; }
attributeId(int i)59     qint32 attributeId(int i) const { return i == 0 ? typeIndex() : m_values[i - 1].first; }
attributeValue(int i)60     quint64 attributeValue(int i) const { return i == 0 ? m_value : m_values[i - 1].second; }
61 
origFrames()62     const QVector<qint32> &origFrames() const { return m_origFrames; }
origNumGuessedFrames()63     quint8 origNumGuessedFrames() const { return m_origNumGuessedFrames; }
64 
frames()65     const QVector<qint32> &frames() const { return m_frames; }
setFrames(const QVector<qint32> & frames)66     void setFrames(const QVector<qint32> &frames) { m_frames = frames; }
67 
traceData()68     const QHash<qint32, QVariant> &traceData() const { return m_traceData; }
69 
pid()70     quint32 pid() const { return m_pid; }
tid()71     quint32 tid() const { return m_tid; }
72 
numGuessedFrames()73     quint8 numGuessedFrames() const { return m_numGuessedFrames; }
setNumGuessedFrames(quint8 numGuessedFrames)74     void setNumGuessedFrames(quint8 numGuessedFrames) { m_numGuessedFrames = numGuessedFrames; }
75 
feature()76     quint8 feature() const { return m_feature; }
77 
extra()78     quint8 extra() const { return m_extra; }
setExtra(quint8 extra)79     void setExtra(quint8 extra) { m_extra = extra; }
80 
81 private:
82     friend QDataStream &operator>>(QDataStream &stream, PerfEvent &event);
83     friend QDataStream &operator<<(QDataStream &stream, const PerfEvent &event);
84 
85     QVector<QPair<qint32, quint64>> m_values;
86     QVector<qint32> m_origFrames;
87     QVector<qint32> m_frames;
88     QHash<qint32, QVariant> m_traceData;
89     quint32 m_pid = 0;
90     quint32 m_tid = 0;
91     quint64 m_value = 0;
92     quint32 m_cpu = 0;
93     quint8 m_origNumGuessedFrames = 0;
94     quint8 m_numGuessedFrames = 0;
95     quint8 m_feature = PerfEventType::InvalidFeature;
96     quint8 m_extra = 0;
97 };
98 
99 inline QDataStream &operator>>(QDataStream &stream, PerfEvent &event)
100 {
101     stream >> event.m_feature;
102     switch (event.m_feature) {
103     case PerfEventType::Command:
104     case PerfEventType::LocationDefinition:
105     case PerfEventType::SymbolDefinition:
106     case PerfEventType::AttributesDefinition:
107     case PerfEventType::StringDefinition:
108     case PerfEventType::FeaturesDefinition:
109     case PerfEventType::Error:
110     case PerfEventType::Progress:
111     case PerfEventType::TracePointFormat:
112         return stream; // in fact type data. to be handled elsewhere
113     case PerfEventType::ThreadStart:
114     case PerfEventType::ThreadEnd:
115     case PerfEventType::LostDefinition:
116     case PerfEventType::Sample:
117     case PerfEventType::TracePointSample:
118     case PerfEventType::ContextSwitchDefinition:
119         break;
120     case PerfEventType::InvalidFeature:
121         QTC_ASSERT(false, return stream);
122     }
123 
124     quint64 timestamp;
125     stream >> event.m_pid >> event.m_tid >> timestamp >> event.m_cpu;
126 
127     static const quint64 qint64Max = static_cast<quint64>(std::numeric_limits<qint64>::max());
128     event.setTimestamp(static_cast<qint64>(qMin(timestamp, qint64Max)));
129 
130     switch (event.m_feature) {
131     case PerfEventType::ThreadStart:
132         event.setTypeIndex(PerfEvent::ThreadStartTypeId);
133         break;
134     case PerfEventType::ThreadEnd:
135         event.setTypeIndex(PerfEvent::ThreadEndTypeId);
136         break;
137     case PerfEventType::LostDefinition:
138         event.setTypeIndex(PerfEvent::LostTypeId);
139         break;
140     case PerfEventType::ContextSwitchDefinition:
141         event.setTypeIndex(PerfEvent::ContextSwitchTypeId);
142         bool isSwitchOut;
143         stream >> isSwitchOut;
144         event.setExtra(isSwitchOut);
145         break;
146     default: {
147         qint32 firstAttributeId;
148         stream >> event.m_origFrames >> event.m_origNumGuessedFrames;
149         QVector<QPair<qint32, quint64>> values;
150         stream >> values;
151         if (values.isEmpty()) {
152             firstAttributeId = PerfEvent::LastSpecialTypeId;
153         } else {
154             firstAttributeId = PerfEvent::LastSpecialTypeId - values.first().first;
155             event.m_value = values.first().second;
156             for (auto it = values.constBegin() + 1, end = values.constEnd(); it != end; ++it) {
157                 event.m_values.push_back({ PerfEvent::LastSpecialTypeId - it->first,
158                                            it->second });
159             }
160         }
161         if (event.m_feature == PerfEventType::TracePointSample)
162             stream >> event.m_traceData;
163         event.setTypeIndex(firstAttributeId);
164     }
165     }
166 
167     return stream;
168 }
169 
170 inline QDataStream &operator<<(QDataStream &stream, const PerfEvent &event)
171 {
172     quint8 feature = event.feature();
173     stream << feature << event.m_pid << event.m_tid
174            << (event.timestamp() < 0ll ? 0ull : static_cast<quint64>(event.timestamp()))
175            << event.m_cpu;
176     switch (feature) {
177     case PerfEventType::ThreadStart:
178     case PerfEventType::ThreadEnd:
179     case PerfEventType::LostDefinition:
180         break;
181     case PerfEventType::ContextSwitchDefinition:
182         stream << bool(event.extra());
183         break;
184     case PerfEventType::Sample:
185     case PerfEventType::TracePointSample: {
186         stream << event.m_origFrames << event.m_origNumGuessedFrames;
187 
188         QVector<QPair<qint32, quint64>> values;
189         for (int i = 0, end = event.numAttributes(); i < end; ++i) {
190             values.push_back({ PerfEvent::LastSpecialTypeId - event.attributeId(i),
191                                event.attributeValue(i) });
192         }
193         stream << values;
194 
195         if (feature == PerfEventType::TracePointSample)
196             stream << event.m_traceData;
197         break;
198     }
199     default:
200         QTC_CHECK(false);
201     }
202 
203     return stream;
204 }
205 
206 } // namespace Internal
207 } // namespace PerfProfiler
208