1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "host-common/opengl/logger.h"
16
17 #include <inttypes.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20
21 #include <algorithm>
22 #include <fstream>
23 #include <string>
24
25 #include "aemu/base/files/PathUtils.h"
26 #include "aemu/base/msvc.h"
27 #include "aemu/base/synchronization/Lock.h"
28
29 #ifndef _MSC_VER
30 #include <sys/time.h>
31 #endif
32 #include <vector>
33
34 using android::base::AutoLock;
35 using android::base::Lock;
36 using android::base::PathUtils;
37
38 // The purpose of the OpenGL logger is to log
39 // information about such things as EGL initialization
40 // and possibly miscellanous OpenGL commands,
41 // in order to get a better idea of what is going on
42 // in crash reports.
43
44 // The OpenGLLogger implementation's initialization method
45 // by default uses the crash reporter's data directory.
46
47 static const int kBufferLen = 2048;
48
49 typedef std::pair<uint64_t, std::string> TimestampedLogEntry;
50
51 class OpenGLLogger {
52 public:
53 OpenGLLogger() = default;
54 OpenGLLogger(const char* filename);
55 void stop();
56
57 // Coarse log: Call this infrequently.
58 void writeCoarse(const char* str);
59
60 // Fine log: When we want to log very frequent events.
61 // Fine logs can be toggled on/off.
62 void writeFineTimestamped(const char* str);
63
64 void setLoggerFlags(AndroidOpenglLoggerFlags flags);
65 bool isFineLogging() const;
66
67 static OpenGLLogger* get();
68
69 private:
70 void writeFineLocked(uint64_t time, const char* str);
71 void stopFineLogLocked();
72
73 Lock mLock;
74 AndroidOpenglLoggerFlags mLoggerFlags = OPENGL_LOGGER_NONE;
75 uint64_t mPrevTimeUs = 0;
76 std::string mFileName;
77 std::ofstream mFileHandle;
78 std::string mFineLogFileName;
79 std::ofstream mFineLogFileHandle;
80 std::vector<TimestampedLogEntry> mFineLog;
81 DISALLOW_COPY_ASSIGN_AND_MOVE(OpenGLLogger);
82 };
83
sOpenGLLogger()84 static OpenGLLogger* sOpenGLLogger() {
85 static OpenGLLogger sLogger;
86 return &sLogger;
87 }
88
get()89 OpenGLLogger* OpenGLLogger::get() { return sOpenGLLogger(); }
90
91
OpenGLLogger(const char * filename)92 OpenGLLogger::OpenGLLogger(const char* filename) : mFileName(filename) {
93 mFileHandle.open(mFileName, std::ios::app);
94 }
95
writeCoarse(const char * str)96 void OpenGLLogger::writeCoarse(const char* str) {
97 AutoLock lock(mLock);
98 if (mLoggerFlags & OPENGL_LOGGER_PRINT_TO_STDOUT) {
99 printf("%s\n", str);
100 }
101 if (mFileHandle) {
102 mFileHandle << str << std::endl;
103 }
104 }
105
stop()106 void OpenGLLogger::stop() {
107 AutoLock lock(mLock);
108 stopFineLogLocked();
109 mFileHandle.close();
110 }
111
writeFineLocked(uint64_t time,const char * str)112 void OpenGLLogger::writeFineLocked(uint64_t time, const char* str) {
113 if (mLoggerFlags & OPENGL_LOGGER_PRINT_TO_STDOUT) {
114 printf("%s", str);
115 } else {
116 mFineLog.emplace_back(time, str);
117 }
118 }
119
writeFineTimestamped(const char * str)120 void OpenGLLogger::writeFineTimestamped(const char* str) {
121 if (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING) {
122 char buf[kBufferLen] = {};
123 struct timeval tv;
124 gettimeofday(&tv, NULL);
125
126 uint64_t curr_micros = (tv.tv_usec) % 1000;
127 uint64_t curr_millis = (tv.tv_usec / 1000) % 1000;
128 uint64_t curr_secs = tv.tv_sec;
129 uint64_t curr_us = tv.tv_sec * 1000000ULL + tv.tv_usec;
130 snprintf(buf, sizeof(buf) - 1,
131 "time_us="
132 "%" PRIu64
133 " s "
134 "%" PRIu64
135 " ms "
136 "%" PRIu64
137 " us deltaUs "
138 "%" PRIu64 " | %s",
139 curr_secs, curr_millis, curr_micros, curr_us - mPrevTimeUs, str);
140 AutoLock lock(mLock);
141 writeFineLocked(curr_micros + 1000ULL * curr_millis + 1000ULL * 1000ULL * curr_secs, buf);
142 mPrevTimeUs = curr_us;
143 }
144 }
145
setLoggerFlags(AndroidOpenglLoggerFlags flags)146 void OpenGLLogger::setLoggerFlags(AndroidOpenglLoggerFlags flags) {
147 AutoLock lock(mLock);
148 bool needStopFineLog = (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING) &&
149 (!(flags & OPENGL_LOGGER_DO_FINE_LOGGING));
150
151 if (needStopFineLog) {
152 stopFineLogLocked();
153 }
154
155 mLoggerFlags = flags;
156 }
157
isFineLogging() const158 bool OpenGLLogger::isFineLogging() const {
159 // For speed, we'll just let this read of mLoggerFlags race.
160 return (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING);
161 }
162
stopFineLogLocked()163 void OpenGLLogger::stopFineLogLocked() {
164 // Only print message when fine-grained
165 // logging is turned on.
166 if (!mFineLog.empty()) {
167 fprintf(stderr, "Writing fine-grained GL log to %s...", mFineLogFileName.c_str());
168 }
169
170 // Sort log entries according to their timestamps.
171 // This is because the log entries might arrive
172 // out of order.
173 std::sort(mFineLog.begin(), mFineLog.end(),
174 [](const TimestampedLogEntry& x, const TimestampedLogEntry& y) {
175 return x.first < y.first;
176 });
177
178 if (mFineLogFileHandle) {
179 for (const auto& entry : mFineLog) {
180 // The fine log does not print newlines
181 // as it is used with the opengl debug
182 // printout in emugl, which adds
183 // newlines of its own.
184 mFineLogFileHandle << entry.second;
185 }
186 mFineLogFileHandle.close();
187 if (!mFineLog.empty()) {
188 fprintf(stderr, "done\n");
189 }
190 }
191 mFineLog.clear();
192 }
193
194 // C interface
195
android_init_opengl_logger()196 void android_init_opengl_logger() { OpenGLLogger::get(); }
197
android_opengl_logger_set_flags(AndroidOpenglLoggerFlags flags)198 void android_opengl_logger_set_flags(AndroidOpenglLoggerFlags flags) {
199 OpenGLLogger::get()->setLoggerFlags(flags);
200 }
201
android_opengl_logger_write(char severity,const char * file,unsigned int line,int64_t timestamp_us,const char * message)202 void android_opengl_logger_write(char severity, const char* file, unsigned int line,
203 int64_t timestamp_us, const char* message) {
204 char buf[kBufferLen] = {};
205 auto gl_log = OpenGLLogger::get();
206
207 if (severity == 'V' || severity == 'D') {
208 // Not logging details if it is not requested
209 if (!gl_log->isFineLogging()) {
210 return;
211 }
212
213 snprintf(buf, sizeof(buf) - 1, "%c %s:%d %s", severity, file, line, message);
214 gl_log->writeFineTimestamped(buf);
215 return;
216 }
217
218 // Other log levels..
219 snprintf(buf, sizeof(buf) - 1, "%c %s:%d %s", severity, file, line, message);
220 gl_log->writeCoarse(buf);
221 }
222
android_stop_opengl_logger()223 void android_stop_opengl_logger() {
224 OpenGLLogger* gl_log = OpenGLLogger::get();
225 gl_log->stop();
226 }
227