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