• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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