1 /*
2  * Copyright (C) 2020 The Android Open Source Project
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 
17 #include <inttypes.h>
18 
19 #include <chrono>
20 #include <map>
21 
22 #include <android-base/file.h>
23 #include <android-base/mapped_file.h>
24 #include <android-base/parseint.h>
25 #include <android-base/strings.h>
26 #include <android-base/unique_fd.h>
27 #include <android/log.h>
28 #include <log/log_time.h>
29 #include <log/logprint.h>
30 
31 #include "ChattyLogBuffer.h"
32 #include "LogBuffer.h"
33 #include "LogStatistics.h"
34 #include "RecordedLogMessage.h"
35 #include "SerializedLogBuffer.h"
36 #include "SimpleLogBuffer.h"
37 
38 using android::base::MappedFile;
39 using android::base::ParseInt;
40 using android::base::ParseUint;
41 using android::base::Split;
42 
43 #ifndef __ANDROID__
44 // This is hard coded to 1MB on host.  On device use persist.logd.size to configure.
__android_logger_get_buffer_size(log_id_t)45 unsigned long __android_logger_get_buffer_size(log_id_t) {
46     return 1 * 1024 * 1024;
47 }
48 
__android_logger_valid_buffer_size(unsigned long)49 bool __android_logger_valid_buffer_size(unsigned long) {
50     return true;
51 }
52 #endif
53 
uidToName(uid_t)54 char* android::uidToName(uid_t) {
55     return nullptr;
56 }
57 
GetPrivateDirty()58 static size_t GetPrivateDirty() {
59     // Allocate once and hope that we don't need to reallocate >40000, to prevent heap fragmentation
60     static std::string smaps(40000, '\0');
61     android::base::ReadFileToString("/proc/self/smaps", &smaps);
62 
63     size_t result = 0;
64     size_t base = 0;
65     size_t found;
66     while (true) {
67         found = smaps.find("Private_Dirty:", base);
68         if (found == smaps.npos) break;
69 
70         found += sizeof("Private_Dirty:");
71 
72         result += atoi(&smaps[found]);
73 
74         base = found + 1;
75     }
76 
77     return result;
78 }
79 
GetLogFormat()80 static AndroidLogFormat* GetLogFormat() {
81     static AndroidLogFormat* format = [] {
82         auto* format = android_log_format_new();
83         android_log_setPrintFormat(format, android_log_formatFromString("threadtime"));
84         android_log_setPrintFormat(format, android_log_formatFromString("uid"));
85         return format;
86     }();
87     return format;
88 }
89 
PrintMessage(struct log_msg * buf)90 static void PrintMessage(struct log_msg* buf) {
91     bool is_binary =
92             buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
93 
94     AndroidLogEntry entry;
95     int err;
96     if (is_binary) {
97         char binaryMsgBuf[1024];
98         err = android_log_processBinaryLogBuffer(&buf->entry, &entry, nullptr, binaryMsgBuf,
99                                                  sizeof(binaryMsgBuf));
100     } else {
101         err = android_log_processLogBuffer(&buf->entry, &entry);
102     }
103     if (err < 0) {
104         fprintf(stderr, "Error parsing log message\n");
105     }
106 
107     android_log_printLogLine(GetLogFormat(), STDOUT_FILENO, &entry);
108 }
109 
GetFirstTimeStamp(const MappedFile & recorded_messages)110 static log_time GetFirstTimeStamp(const MappedFile& recorded_messages) {
111     if (sizeof(RecordedLogMessage) >= recorded_messages.size()) {
112         fprintf(stderr, "At least one log message must be present in the input\n");
113         exit(1);
114     }
115 
116     auto* meta = reinterpret_cast<RecordedLogMessage*>(recorded_messages.data());
117     return meta->realtime;
118 }
119 
120 class StdoutWriter : public LogWriter {
121   public:
StdoutWriter()122     StdoutWriter() : LogWriter(0, true) {}
Write(const logger_entry & entry,const char * message)123     bool Write(const logger_entry& entry, const char* message) override {
124         struct log_msg log_msg;
125         log_msg.entry = entry;
126         if (log_msg.entry.len > LOGGER_ENTRY_MAX_PAYLOAD) {
127             fprintf(stderr, "payload too large %" PRIu16, log_msg.entry.len);
128             exit(1);
129         }
130         memcpy(log_msg.msg(), message, log_msg.entry.len);
131 
132         PrintMessage(&log_msg);
133 
134         return true;
135     }
136 
name() const137     std::string name() const override { return "stdout writer"; }
138 };
139 
140 class Operation {
141   public:
~Operation()142     virtual ~Operation() {}
143 
Begin()144     virtual void Begin() {}
145     virtual void Log(const RecordedLogMessage& meta, const char* msg) = 0;
End()146     virtual void End() {}
147 };
148 
149 class PrintInteresting : public Operation {
150   public:
PrintInteresting(log_time first_log_timestamp)151     PrintInteresting(log_time first_log_timestamp)
152         : stats_simple_{false, false, first_log_timestamp},
153           stats_chatty_{false, false, first_log_timestamp},
154           stats_serialized_{false, true, first_log_timestamp} {}
155 
Begin()156     void Begin() override {
157         printf("message_count,simple_main_lines,simple_radio_lines,simple_events_lines,simple_"
158                "system_lines,simple_crash_lines,simple_stats_lines,simple_security_lines,simple_"
159                "kernel_lines,simple_main_size,simple_radio_size,simple_events_size,simple_system_"
160                "size,simple_crash_size,simple_stats_size,simple_security_size,simple_kernel_size,"
161                "simple_main_overhead,simple_radio_overhead,simple_events_overhead,simple_system_"
162                "overhead,simple_crash_overhead,simple_stats_overhead,simple_security_overhead,"
163                "simple_kernel_overhead,simple_main_range,simple_radio_range,simple_events_range,"
164                "simple_system_range,simple_crash_range,simple_stats_range,simple_security_range,"
165                "simple_kernel_range,chatty_main_lines,chatty_radio_lines,chatty_events_lines,"
166                "chatty_system_lines,chatty_crash_lines,chatty_stats_lines,chatty_security_lines,"
167                "chatty_"
168                "kernel_lines,chatty_main_size,chatty_radio_size,chatty_events_size,chatty_system_"
169                "size,chatty_crash_size,chatty_stats_size,chatty_security_size,chatty_kernel_size,"
170                "chatty_main_overhead,chatty_radio_overhead,chatty_events_overhead,chatty_system_"
171                "overhead,chatty_crash_overhead,chatty_stats_overhead,chatty_security_overhead,"
172                "chatty_kernel_overhead,chatty_main_range,chatty_radio_range,chatty_events_range,"
173                "chatty_system_range,chatty_crash_range,chatty_stats_range,chatty_security_range,"
174                "chatty_kernel_range,serialized_main_lines,serialized_radio_lines,serialized_events_"
175                "lines,serialized_"
176                "system_lines,serialized_crash_lines,serialized_stats_lines,serialized_security_"
177                "lines,serialized_"
178                "kernel_lines,serialized_main_size,serialized_radio_size,serialized_events_size,"
179                "serialized_system_"
180                "size,serialized_crash_size,serialized_stats_size,serialized_security_size,"
181                "serialized_kernel_size,"
182                "serialized_main_overhead,serialized_radio_overhead,serialized_events_overhead,"
183                "serialized_system_"
184                "overhead,serialized_crash_overhead,serialized_stats_overhead,serialized_security_"
185                "overhead,"
186                "serialized_kernel_overhead,serialized_main_range,serialized_radio_range,serialized_"
187                "events_range,"
188                "serialized_system_range,serialized_crash_range,serialized_stats_range,serialized_"
189                "security_range,"
190                "serialized_kernel_range\n");
191     }
192 
Log(const RecordedLogMessage & meta,const char * msg)193     void Log(const RecordedLogMessage& meta, const char* msg) override {
194         simple_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
195                                meta.pid, meta.tid, msg, meta.msg_len);
196 
197         chatty_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
198                                meta.pid, meta.tid, msg, meta.msg_len);
199 
200         serialized_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
201                                    meta.pid, meta.tid, msg, meta.msg_len);
202 
203         if (num_message_ % 10000 == 0) {
204             printf("%" PRIu64 ",%s,%s,%s\n", num_message_,
205                    stats_simple_.ReportInteresting().c_str(),
206                    stats_chatty_.ReportInteresting().c_str(),
207                    stats_serialized_.ReportInteresting().c_str());
208         }
209 
210         num_message_++;
211     }
212 
213   private:
214     uint64_t num_message_ = 1;
215 
216     LogReaderList reader_list_;
217     LogTags tags_;
218     PruneList prune_list_;
219 
220     LogStatistics stats_simple_;
221     SimpleLogBuffer simple_log_buffer_{&reader_list_, &tags_, &stats_simple_};
222 
223     LogStatistics stats_chatty_;
224     ChattyLogBuffer chatty_log_buffer_{&reader_list_, &tags_, &prune_list_, &stats_chatty_};
225 
226     LogStatistics stats_serialized_;
227     SerializedLogBuffer serialized_log_buffer_{&reader_list_, &tags_, &stats_serialized_};
228 };
229 
230 class SingleBufferOperation : public Operation {
231   public:
SingleBufferOperation(log_time first_log_timestamp,const char * buffer)232     SingleBufferOperation(log_time first_log_timestamp, const char* buffer) {
233         if (!strcmp(buffer, "simple")) {
234             stats_.reset(new LogStatistics{false, false, first_log_timestamp});
235             log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, stats_.get()));
236         } else if (!strcmp(buffer, "chatty")) {
237             stats_.reset(new LogStatistics{false, false, first_log_timestamp});
238             log_buffer_.reset(
239                     new ChattyLogBuffer(&reader_list_, &tags_, &prune_list_, stats_.get()));
240         } else if (!strcmp(buffer, "serialized")) {
241             stats_.reset(new LogStatistics{false, true, first_log_timestamp});
242             log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, stats_.get()));
243         } else {
244             fprintf(stderr, "invalid log buffer type '%s'\n", buffer);
245             abort();
246         }
247     }
248 
Log(const RecordedLogMessage & meta,const char * msg)249     void Log(const RecordedLogMessage& meta, const char* msg) override {
250         PreOperation();
251         log_buffer_->Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, meta.pid,
252                          meta.tid, msg, meta.msg_len);
253 
254         Operation();
255 
256         num_message_++;
257     }
258 
PreOperation()259     virtual void PreOperation() {}
Operation()260     virtual void Operation() {}
261 
262   protected:
263     uint64_t num_message_ = 1;
264 
265     LogReaderList reader_list_;
266     LogTags tags_;
267     PruneList prune_list_;
268 
269     std::unique_ptr<LogStatistics> stats_;
270     std::unique_ptr<LogBuffer> log_buffer_;
271 };
272 
273 class PrintMemory : public SingleBufferOperation {
274   public:
PrintMemory(log_time first_log_timestamp,const char * buffer)275     PrintMemory(log_time first_log_timestamp, const char* buffer)
276         : SingleBufferOperation(first_log_timestamp, buffer) {}
277 
Operation()278     void Operation() override {
279         if (num_message_ % 100000 == 0) {
280             printf("%" PRIu64 ",%s\n", num_message_,
281                    std::to_string(GetPrivateDirty() - baseline_memory_).c_str());
282         }
283     }
284 
285   private:
286     size_t baseline_memory_ = GetPrivateDirty();
287 };
288 
289 class PrintLogs : public SingleBufferOperation {
290   public:
PrintLogs(log_time first_log_timestamp,const char * buffer,const char * buffers,const char * print_point)291     PrintLogs(log_time first_log_timestamp, const char* buffer, const char* buffers,
292               const char* print_point)
293         : SingleBufferOperation(first_log_timestamp, buffer) {
294         if (buffers != nullptr) {
295             if (strcmp(buffers, "all") != 0) {
296                 std::vector<int> buffer_ids;
297                 auto string_ids = Split(buffers, ",");
298                 for (const auto& string_id : string_ids) {
299                     int result;
300                     if (!ParseInt(string_id, &result, 0, 7)) {
301                         fprintf(stderr, "Could not parse buffer_id '%s'\n", string_id.c_str());
302                         exit(1);
303                     }
304                     buffer_ids.emplace_back(result);
305                 }
306                 mask_ = 0;
307                 for (const auto& buffer_id : buffer_ids) {
308                     mask_ |= 1 << buffer_id;
309                 }
310             }
311         }
312         if (print_point != nullptr) {
313             uint64_t result = 0;
314             if (!ParseUint(print_point, &result)) {
315                 fprintf(stderr, "Could not parse print point '%s'\n", print_point);
316                 exit(1);
317             }
318             print_point_ = result;
319         }
320     }
321 
Operation()322     void Operation() override {
323         if (print_point_ && num_message_ >= *print_point_) {
324             End();
325             exit(0);
326         }
327     }
328 
End()329     void End() {
330         std::unique_ptr<LogWriter> test_writer(new StdoutWriter());
331         std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, mask_);
332         log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr);
333 
334         auto stats_string = stats_->Format(0, 0, mask_);
335         printf("%s\n", stats_string.c_str());
336     }
337 
338   private:
339     LogMask mask_ = kLogMaskAll;
340     std::optional<uint64_t> print_point_;
341 };
342 
343 class PrintLatency : public SingleBufferOperation {
344   public:
PrintLatency(log_time first_log_timestamp,const char * buffer)345     PrintLatency(log_time first_log_timestamp, const char* buffer)
346         : SingleBufferOperation(first_log_timestamp, buffer) {}
347 
PreOperation()348     void PreOperation() override { operation_start_ = std::chrono::steady_clock::now(); }
349 
Operation()350     void Operation() override {
351         auto end = std::chrono::steady_clock::now();
352         auto duration = (end - operation_start_).count();
353         durations_.emplace_back(duration);
354     }
355 
End()356     void End() {
357         std::sort(durations_.begin(), durations_.end());
358         auto q1 = durations_.size() / 4;
359         auto q2 = durations_.size() / 2;
360         auto q3 = 3 * durations_.size() / 4;
361 
362         auto p95 = 95 * durations_.size() / 100;
363         auto p99 = 99 * durations_.size() / 100;
364         auto p9999 = 9999 * durations_.size() / 10000;
365 
366         printf("q1: %lld q2: %lld q3: %lld  p95: %lld p99: %lld p99.99: %lld  max: %lld\n",
367                durations_[q1], durations_[q2], durations_[q3], durations_[p95], durations_[p99],
368                durations_[p9999], durations_.back());
369     }
370 
371   private:
372     std::chrono::steady_clock::time_point operation_start_;
373     std::vector<long long> durations_;
374 };
375 
main(int argc,char ** argv)376 int main(int argc, char** argv) {
377     if (argc < 3) {
378         fprintf(stderr, "Usage: %s FILE OPERATION [BUFFER] [OPTIONS]\n", argv[0]);
379         return 1;
380     }
381 
382     if (strcmp(argv[2], "interesting") != 0 && argc < 4) {
383         fprintf(stderr, "Operations other than 'interesting' require a BUFFER argument\n");
384         return 1;
385     }
386 
387     int recorded_messages_fd = open(argv[1], O_RDONLY);
388     if (recorded_messages_fd == -1) {
389         fprintf(stderr, "Couldn't open input file\n");
390         return 1;
391     }
392     struct stat fd_stat;
393     if (fstat(recorded_messages_fd, &fd_stat) != 0) {
394         fprintf(stderr, "Couldn't fstat input file\n");
395         return 1;
396     }
397     auto recorded_messages = MappedFile::FromFd(recorded_messages_fd, 0,
398                                                 static_cast<size_t>(fd_stat.st_size), PROT_READ);
399     if (recorded_messages == nullptr) {
400         fprintf(stderr, "Couldn't mmap input file\n");
401         return 1;
402     }
403 
404     // LogStatistics typically uses 'now()' to initialize its log range state, but this doesn't work
405     // when replaying older logs, so we instead give it the timestamp from the first log.
406     log_time first_log_timestamp = GetFirstTimeStamp(*recorded_messages);
407 
408     std::unique_ptr<Operation> operation;
409     if (!strcmp(argv[2], "interesting")) {
410         operation.reset(new PrintInteresting(first_log_timestamp));
411     } else if (!strcmp(argv[2], "memory_usage")) {
412         operation.reset(new PrintMemory(first_log_timestamp, argv[3]));
413     } else if (!strcmp(argv[2], "latency")) {
414         operation.reset(new PrintLatency(first_log_timestamp, argv[3]));
415     } else if (!strcmp(argv[2], "print_logs")) {
416         operation.reset(new PrintLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr,
417                                       argc > 5 ? argv[5] : nullptr));
418     } else if (!strcmp(argv[2], "nothing")) {
419         operation.reset(new SingleBufferOperation(first_log_timestamp, argv[3]));
420     } else {
421         fprintf(stderr, "unknown operation '%s'\n", argv[2]);
422         return 1;
423     }
424 
425     // LogBuffer::Log() won't log without this on host.
426     __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
427     // But we still want to suppress messages <= error to not interrupt the rest of the output.
428     __android_log_set_logger([](const struct __android_log_message* log_message) {
429         if (log_message->priority < ANDROID_LOG_ERROR) {
430             return;
431         }
432         __android_log_stderr_logger(log_message);
433     });
434 
435     operation->Begin();
436 
437     uint64_t read_position = 0;
438     while (read_position + sizeof(RecordedLogMessage) < recorded_messages->size()) {
439         auto* meta =
440                 reinterpret_cast<RecordedLogMessage*>(recorded_messages->data() + read_position);
441         if (read_position + sizeof(RecordedLogMessage) + meta->msg_len >=
442             recorded_messages->size()) {
443             break;
444         }
445         char* msg = recorded_messages->data() + read_position + sizeof(RecordedLogMessage);
446         read_position += sizeof(RecordedLogMessage) + meta->msg_len;
447 
448         operation->Log(*meta, msg);
449     }
450 
451     operation->End();
452 
453     return 0;
454 }
455