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