1 // Copyright (C) 2021 The Android Open Source Project
2 // Copyright (C) 2021 Google Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include "aemu/base/Metrics.h"
17
18 #include <memory>
19 #include <sstream>
20 #include <variant>
21
22 #include "host-common/logging.h"
23
24 namespace android {
25 namespace base {
26
27 // These correspond to events defined in
28 // go/gpg-event-codes
29 constexpr int64_t kEmulatorGraphicsFreeze = 10009;
30 constexpr int64_t kEmulatorGraphicsUnfreeze = 10010;
31 constexpr int64_t kEmulatorGfxstreamVkAbortReason = 10011;
32 constexpr int64_t kEmulatorGraphicsHangRenderThread = 10024;
33 constexpr int64_t kEmulatorGraphicsUnHangRenderThread = 10025;
34 constexpr int64_t kEmulatorGraphicsHangSyncThread = 10026;
35 constexpr int64_t kEmulatorGraphicsUnHangSyncThread = 10027;
36 constexpr int64_t kEmulatorGraphicsBadPacketLength = 10031;
37 constexpr int64_t kEmulatorGraphicsDuplicateSequenceNum = 10032;
38 constexpr int64_t kEmulatorGraphicsVulkanOutOfMemory = 10033;
39 constexpr int64_t kEmulatorGraphicsHangOther = 10034;
40 constexpr int64_t kEmulatorGraphicsUnHangOther = 10035;
41
42 constexpr int64_t kHangDepthMetricLimit = 10;
43
44 void (*MetricsLogger::add_instant_event_callback)(int64_t event_code) = nullptr;
45 void (*MetricsLogger::add_instant_event_with_descriptor_callback)(int64_t event_code,
46 int64_t descriptor) = nullptr;
47 void (*MetricsLogger::add_instant_event_with_metric_callback)(int64_t event_code,
48 int64_t metric_value) = nullptr;
49 void (*MetricsLogger::add_vulkan_out_of_memory_event)(int64_t result_code, uint32_t op_code,
50 const char* function, uint32_t line,
51 uint64_t allocation_size,
52 bool is_host_side_result,
53 bool is_allocation) = nullptr;
54 void (*MetricsLogger::set_crash_annotation_callback)(const char* key, const char* value) = nullptr;
55
logEventHangMetadata(const EventHangMetadata * metadata)56 void logEventHangMetadata(const EventHangMetadata* metadata) {
57 ERR("Metadata:");
58 ERR("\t file: %s", metadata->file);
59 ERR("\t function: %s", metadata->function);
60 ERR("\t line: %d", metadata->line);
61 ERR("\t msg: %s", metadata->msg);
62 ERR("\t thread: %d (0x%08x)", metadata->threadId, metadata->threadId);
63 if (metadata->data) {
64 ERR("\t Additional information:");
65 for (auto& [key, value] : *metadata->data) {
66 ERR("\t \t %s: %s", key.c_str(), value.c_str());
67 }
68 }
69 }
70
71 struct MetricTypeVisitor {
operator ()android::base::MetricTypeVisitor72 void operator()(const std::monostate /*_*/) const { ERR("MetricEventType not initialized"); }
73
operator ()android::base::MetricTypeVisitor74 void operator()(const MetricEventFreeze freezeEvent) const {
75 if (MetricsLogger::add_instant_event_callback) {
76 MetricsLogger::add_instant_event_callback(kEmulatorGraphicsFreeze);
77 }
78 }
79
operator ()android::base::MetricTypeVisitor80 void operator()(const MetricEventUnFreeze unfreezeEvent) const {
81 if (MetricsLogger::add_instant_event_with_metric_callback) {
82 MetricsLogger::add_instant_event_with_metric_callback(kEmulatorGraphicsUnfreeze,
83 unfreezeEvent.frozen_ms);
84 }
85 }
86
operator ()android::base::MetricTypeVisitor87 void operator()(const MetricEventHang hangEvent) const {
88 // Logging a hang event will trigger a crash report upload. If crash reporting is enabled,
89 // the set_annotation_callback will be populated.
90 if (MetricsLogger::set_crash_annotation_callback) {
91 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_file",
92 hangEvent.metadata->file);
93 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_function",
94 hangEvent.metadata->function);
95 MetricsLogger::set_crash_annotation_callback(
96 "gfxstream_hang_line", std::to_string(hangEvent.metadata->line).c_str());
97 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_msg",
98 hangEvent.metadata->msg);
99 std::stringstream threadDesc;
100 threadDesc << hangEvent.metadata->threadId << " (0x" << std::hex
101 << hangEvent.metadata->threadId << ")";
102 std::string threadStr = threadDesc.str();
103 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_thread",
104 threadStr.c_str());
105
106 if (hangEvent.metadata->data) {
107 for (auto& [key, value] : *hangEvent.metadata->data) {
108 MetricsLogger::set_crash_annotation_callback(key.c_str(), value.c_str());
109 }
110 }
111 }
112
113 ERR("Logging hang event. Number of tasks already hung: %d", hangEvent.otherHungTasks);
114 logEventHangMetadata(hangEvent.metadata);
115 if (MetricsLogger::add_instant_event_with_metric_callback &&
116 hangEvent.otherHungTasks <= kHangDepthMetricLimit) {
117 switch (hangEvent.metadata->hangType) {
118 case EventHangMetadata::HangType::kRenderThread: {
119 MetricsLogger::add_instant_event_with_metric_callback(
120 kEmulatorGraphicsHangRenderThread, hangEvent.otherHungTasks);
121 break;
122 }
123 case EventHangMetadata::HangType::kSyncThread: {
124 MetricsLogger::add_instant_event_with_metric_callback(
125 kEmulatorGraphicsHangSyncThread, hangEvent.otherHungTasks);
126 break;
127 }
128 case EventHangMetadata::HangType::kOther: {
129 MetricsLogger::add_instant_event_with_metric_callback(
130 kEmulatorGraphicsHangOther, hangEvent.otherHungTasks);
131 break;
132 }
133 }
134 }
135
136 // We have to unset all annotations since this is not necessarily a fatal crash
137 // and we need to ensure we don't pollute future crash reports.
138 if (MetricsLogger::set_crash_annotation_callback) {
139 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_file", "");
140 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_function", "");
141 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_line", "");
142 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_msg", "");
143 MetricsLogger::set_crash_annotation_callback("gfxstream_hang_thread", "");
144 if (hangEvent.metadata->data) {
145 for (auto& [key, value] : *hangEvent.metadata->data) {
146 MetricsLogger::set_crash_annotation_callback(key.c_str(), "");
147 }
148 }
149 }
150 }
151
operator ()android::base::MetricTypeVisitor152 void operator()(const MetricEventUnHang unHangEvent) const {
153 ERR("Logging unhang event. Hang time: %d ms", unHangEvent.hung_ms);
154 logEventHangMetadata(unHangEvent.metadata);
155 if (MetricsLogger::add_instant_event_with_metric_callback &&
156 unHangEvent.otherHungTasks <= kHangDepthMetricLimit) {
157 switch (unHangEvent.metadata->hangType) {
158 case EventHangMetadata::HangType::kRenderThread: {
159 MetricsLogger::add_instant_event_with_metric_callback(
160 kEmulatorGraphicsUnHangRenderThread, unHangEvent.hung_ms);
161 break;
162 }
163 case EventHangMetadata::HangType::kSyncThread: {
164 MetricsLogger::add_instant_event_with_metric_callback(
165 kEmulatorGraphicsUnHangSyncThread, unHangEvent.hung_ms);
166 break;
167 }
168 case EventHangMetadata::HangType::kOther: {
169 MetricsLogger::add_instant_event_with_metric_callback(
170 kEmulatorGraphicsUnHangOther, unHangEvent.hung_ms);
171 break;
172 }
173 }
174 }
175 }
176
operator ()android::base::MetricTypeVisitor177 void operator()(const GfxstreamVkAbort abort) const {
178 // Ensure clearcut logs are uploaded before aborting.
179 if (MetricsLogger::add_instant_event_with_descriptor_callback) {
180 MetricsLogger::add_instant_event_with_descriptor_callback(
181 kEmulatorGfxstreamVkAbortReason, abort.abort_reason);
182 }
183
184 if (MetricsLogger::set_crash_annotation_callback) {
185 MetricsLogger::set_crash_annotation_callback("gfxstream_abort_file", abort.file);
186 MetricsLogger::set_crash_annotation_callback("gfxstream_abort_function",
187 abort.function);
188 MetricsLogger::set_crash_annotation_callback("gfxstream_abort_line",
189 std::to_string(abort.line).c_str());
190 MetricsLogger::set_crash_annotation_callback(
191 "gfxstream_abort_code", std::to_string(abort.abort_reason).c_str());
192 MetricsLogger::set_crash_annotation_callback("gfxstream_abort_msg", abort.msg);
193 }
194 }
195
operator ()android::base::MetricTypeVisitor196 void operator()(const MetricEventBadPacketLength BadPacketLengthEvent) const {
197 if (MetricsLogger::add_instant_event_with_metric_callback) {
198 MetricsLogger::add_instant_event_with_metric_callback(kEmulatorGraphicsBadPacketLength,
199 BadPacketLengthEvent.len);
200 }
201 }
202
operator ()android::base::MetricTypeVisitor203 void operator()(const MetricEventDuplicateSequenceNum DuplicateSequenceNumEvent) const {
204 if (MetricsLogger::add_instant_event_with_descriptor_callback) {
205 MetricsLogger::add_instant_event_with_descriptor_callback(
206 kEmulatorGraphicsDuplicateSequenceNum, DuplicateSequenceNumEvent.opcode);
207 }
208 }
209
operator ()android::base::MetricTypeVisitor210 void operator()(const MetricEventVulkanOutOfMemory vkOutOfMemoryEvent) const {
211 if (MetricsLogger::add_vulkan_out_of_memory_event) {
212 MetricsLogger::add_vulkan_out_of_memory_event(
213 vkOutOfMemoryEvent.vkResultCode,
214 vkOutOfMemoryEvent.opCode.value_or(0),
215 vkOutOfMemoryEvent.function,
216 vkOutOfMemoryEvent.line.value_or(0),
217 vkOutOfMemoryEvent.allocationSize.value_or(0),
218 !vkOutOfMemoryEvent.opCode.has_value(), // is_host_side_result
219 vkOutOfMemoryEvent.allocationSize.has_value()); // is_allocation
220 }
221 }
222 };
223
224 // MetricsLoggerImpl
225 class MetricsLoggerImpl : public MetricsLogger {
logMetricEvent(MetricEventType eventType)226 void logMetricEvent(MetricEventType eventType) override {
227 std::visit(MetricTypeVisitor(), eventType);
228 }
229
setCrashAnnotation(const char * key,const char * value)230 void setCrashAnnotation(const char* key, const char* value) override {
231 if (MetricsLogger::set_crash_annotation_callback) {
232 MetricsLogger::set_crash_annotation_callback(key, value);
233 }
234 }
235 };
236
CreateMetricsLogger()237 std::unique_ptr<MetricsLogger> CreateMetricsLogger() {
238 return std::make_unique<MetricsLoggerImpl>();
239 }
240
241 } // namespace base
242 } // namespace android
243