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 "aemu/base/files/PathUtils.h"
18 #include "aemu/base/synchronization/Lock.h"
19
20 #include <algorithm>
21 #include <fstream>
22 #include <inttypes.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string>
26
27 #include "aemu/base/msvc.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();
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
71 void writeFineLocked(uint64_t time, const char* str);
72 void stopFineLogLocked();
73
74 Lock mLock;
75 AndroidOpenglLoggerFlags mLoggerFlags = OPENGL_LOGGER_NONE;
76 uint64_t mPrevTimeUs = 0;
77 std::string mFileName;
78 std::ofstream mFileHandle;
79 std::string mFineLogFileName;
80 std::ofstream mFineLogFileHandle;
81 std::vector<TimestampedLogEntry> mFineLog;
82 DISALLOW_COPY_ASSIGN_AND_MOVE(OpenGLLogger);
83 };
84
sOpenGLLogger()85 static OpenGLLogger* sOpenGLLogger() {
86 static OpenGLLogger* g = new OpenGLLogger;
87 return g;
88 }
89
get()90 OpenGLLogger* OpenGLLogger::get() {
91 return sOpenGLLogger();
92 }
93
OpenGLLogger()94 OpenGLLogger::OpenGLLogger() {
95 // #ifdef AEMU_MIN
96 return;
97 // #else
98 // const std::string& data_dir =
99 // CrashReporter::get()->getDataExchangeDir();
100 // mFileName = PathUtils::join(data_dir,
101 // "opengl_log.txt");
102 // mFileHandle.open(mFileName, std::ios::app);
103 // mFineLogFileName = PathUtils::join(data_dir,
104 // "opengl_cxt_log.txt");
105 // mFineLogFileHandle.open(mFineLogFileName, std::ios::app);
106 // #endif
107 }
108
OpenGLLogger(const char * filename)109 OpenGLLogger::OpenGLLogger(const char* filename) :
110 mFileName(filename) {
111 mFileHandle.open(mFileName, std::ios::app);
112 }
113
writeCoarse(const char * str)114 void OpenGLLogger::writeCoarse(const char* str) {
115 AutoLock lock(mLock);
116 if (mLoggerFlags & OPENGL_LOGGER_PRINT_TO_STDOUT) {
117 printf("%s\n", str);
118 }
119 if (mFileHandle) {
120 mFileHandle << str << std::endl;
121 }
122 }
123
stop()124 void OpenGLLogger::stop() {
125 AutoLock lock(mLock);
126 stopFineLogLocked();
127 mFileHandle.close();
128 }
129
writeFineLocked(uint64_t time,const char * str)130 void OpenGLLogger::writeFineLocked(uint64_t time, const char* str) {
131 if (mLoggerFlags & OPENGL_LOGGER_PRINT_TO_STDOUT) {
132 printf("%s", str);
133 } else {
134 mFineLog.emplace_back(time, str);
135 }
136 }
137
writeFineTimestamped(const char * str)138 void OpenGLLogger::writeFineTimestamped(const char* str) {
139 if (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING) {
140 char buf[kBufferLen] = {};
141 struct timeval tv;
142 gettimeofday(&tv, NULL);
143
144 uint64_t curr_micros = (tv.tv_usec) % 1000;
145 uint64_t curr_millis = (tv.tv_usec / 1000) % 1000;
146 uint64_t curr_secs = tv.tv_sec;
147 uint64_t curr_us = tv.tv_sec * 1000000ULL + tv.tv_usec;
148 snprintf(buf, sizeof(buf) - 1,
149 "time_us="
150 "%" PRIu64 " s "
151 "%" PRIu64 " ms "
152 "%" PRIu64 " us deltaUs "
153 "%" PRIu64 " | %s",
154 curr_secs,
155 curr_millis,
156 curr_micros,
157 curr_us - mPrevTimeUs,
158 str);
159 AutoLock lock(mLock);
160 writeFineLocked(curr_micros + 1000ULL * curr_millis +
161 1000ULL * 1000ULL * curr_secs, buf);
162 mPrevTimeUs = curr_us;
163 }
164 }
165
setLoggerFlags(AndroidOpenglLoggerFlags flags)166 void OpenGLLogger::setLoggerFlags(AndroidOpenglLoggerFlags flags) {
167 AutoLock lock(mLock);
168 bool needStopFineLog =
169 (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING) &&
170 (!(flags & OPENGL_LOGGER_DO_FINE_LOGGING));
171
172 if (needStopFineLog) {
173 stopFineLogLocked();
174 }
175
176 mLoggerFlags = flags;
177 }
178
isFineLogging() const179 bool OpenGLLogger::isFineLogging() const {
180 // For speed, we'll just let this read of mLoggerFlags race.
181 return (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING);
182 }
183
stopFineLogLocked()184 void OpenGLLogger::stopFineLogLocked() {
185 // Only print message when fine-grained
186 // logging is turned on.
187 if (!mFineLog.empty()) {
188 fprintf(stderr,
189 "Writing fine-grained GL log to %s...",
190 mFineLogFileName.c_str());
191 }
192
193 // Sort log entries according to their timestamps.
194 // This is because the log entries might arrive
195 // out of order.
196 std::sort(mFineLog.begin(), mFineLog.end(),
197 [](const TimestampedLogEntry& x,
198 const TimestampedLogEntry& y) {
199 return x.first < y.first;
200 });
201
202 if (mFineLogFileHandle) {
203 for (const auto& entry : mFineLog) {
204 // The fine log does not print newlines
205 // as it is used with the opengl debug
206 // printout in emugl, which adds
207 // newlines of its own.
208 mFineLogFileHandle << entry.second;
209 }
210 mFineLogFileHandle.close();
211 if (!mFineLog.empty()) {
212 fprintf(stderr, "done\n");
213 }
214 }
215 mFineLog.clear();
216 }
217
218 // C interface
219
android_init_opengl_logger()220 void android_init_opengl_logger() {
221 OpenGLLogger::get();
222 }
223
android_opengl_logger_set_flags(AndroidOpenglLoggerFlags flags)224 void android_opengl_logger_set_flags(AndroidOpenglLoggerFlags flags) {
225 OpenGLLogger::get()->setLoggerFlags(flags);
226 }
227
android_opengl_logger_write(const char * fmt,...)228 void android_opengl_logger_write(const char* fmt, ...) {
229 char buf[kBufferLen] = {};
230 va_list ap;
231 va_start(ap, fmt);
232 vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
233 va_end(ap);
234 OpenGLLogger::get()->writeCoarse(buf);
235 }
236
android_opengl_cxt_logger_write(const char * fmt,...)237 void android_opengl_cxt_logger_write(const char* fmt, ...) {
238 auto gl_log = OpenGLLogger::get();
239
240 if (!gl_log->isFineLogging()) return;
241
242 char buf[kBufferLen] = {};
243 va_list ap;
244 va_start(ap, fmt);
245 vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
246 va_end(ap);
247
248 gl_log->writeFineTimestamped(buf);
249 }
250
android_stop_opengl_logger()251 void android_stop_opengl_logger() {
252 OpenGLLogger* gl_log = OpenGLLogger::get();
253 gl_log->stop();
254 }
255