platform_system_core/logd/SerializedLogEntry.h
Tom Cherry f74503dd46 logd: optionally track the full size of log buffers
ChattyLogBuffer ignores the metadata (timestamp, pid, std::list<>
iterators, etc) of log entries when calculating the size used by a
given log buffer. For example, if 1MB is the specified size of the
'main' log buffer, logd will use between ~1.3MB and ~2MB of overall
memory for 'main' log buffer.  LogStatistics does track the overall
memory used and labels it 'Overhead', however this 'Overhead' is only
informative and is not used for Pruning or Chatty calculations.

This is problematic, since it makes logd's memory usage inconsistent:
depending on the pattern of logging, there can be substantially more
memory used than the specified log buffer size.  This is further
complicated by the fact that chatty messages are entirely metadata and
therefore not counted as contributing to the log buffer size.

This change would switch logd to always track the full size of log
buffers, but there are two problems with this approach:
1) Unless users double their buffer sizes, then they'd have
   substantially fewer logs after the change
2) Chatty logic would change and it's difficult to evaluate.

Therefore this change only provides the framework to track the full
size of log buffers.  This allows an apples to apples comparison of
ChattyLogBuffer and SerializedLogBuffer.  With this option enabled,
logd reports the following values:

ChattyLogBuffer:
Total log size (logcat -g), 'Total' / 'Now' (logcat -S), and
'Overhead' (logcat -S) all report the full size of log entries
including metadata.

SerializedLogBuffer:
Total log size (logcat -g) and 'Overhead' (logcat -S) report the
compressed size of the log entries including metadata.
'Total' / 'Now' (logcat -S) reports the uncompressed size of the log
entries that are available including metadata.

Test: logging statistics are correct
Change-Id: If17682af8bb605f31387d7b210b69a301dd48f07
2020-07-01 14:35:33 -07:00

99 lines
3.4 KiB
C++

/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <log/log.h>
#include <log/log_read.h>
#include "LogStatistics.h"
#include "LogWriter.h"
// These structs are packed into a single chunk of memory for each log type within a
// SerializedLogChunk object. Their message is contained immediately at the end of the struct. The
// address of the next log in the buffer is *this + sizeof(SerializedLogEntry) + msg_len_. If that
// value would overflow the chunk of memory associated with the SerializedLogChunk object, then a
// new SerializedLogChunk must be allocated to contain the next SerializedLogEntry.
class __attribute__((packed)) SerializedLogEntry {
public:
SerializedLogEntry(uid_t uid, pid_t pid, pid_t tid, uint64_t sequence, log_time realtime,
uint16_t len)
: uid_(uid),
pid_(pid),
tid_(tid),
sequence_(sequence),
realtime_(realtime),
msg_len_(len) {}
SerializedLogEntry(const SerializedLogEntry& elem) = delete;
SerializedLogEntry& operator=(const SerializedLogEntry& elem) = delete;
~SerializedLogEntry() {
// Never place anything in this destructor. This class is in place constructed and never
// destructed.
}
LogStatisticsElement ToLogStatisticsElement(log_id_t log_id) const {
return LogStatisticsElement{
.uid = uid(),
.pid = pid(),
.tid = tid(),
.tag = IsBinary(log_id) ? MsgToTag(msg(), msg_len()) : 0,
.realtime = realtime(),
.msg = msg(),
.msg_len = msg_len(),
.dropped_count = 0,
.log_id = log_id,
.total_len = total_len(),
};
}
bool Flush(LogWriter* writer, log_id_t log_id) const {
struct logger_entry entry = {};
entry.hdr_size = sizeof(struct logger_entry);
entry.lid = log_id;
entry.pid = pid();
entry.tid = tid();
entry.uid = uid();
entry.sec = realtime().tv_sec;
entry.nsec = realtime().tv_nsec;
entry.len = msg_len();
return writer->Write(entry, msg());
}
uid_t uid() const { return uid_; }
pid_t pid() const { return pid_; }
pid_t tid() const { return tid_; }
uint16_t msg_len() const { return msg_len_; }
uint64_t sequence() const { return sequence_; }
log_time realtime() const { return realtime_; }
char* msg() { return reinterpret_cast<char*>(this) + sizeof(*this); }
const char* msg() const { return reinterpret_cast<const char*>(this) + sizeof(*this); }
uint16_t total_len() const { return sizeof(*this) + msg_len_; }
private:
const uint32_t uid_;
const uint32_t pid_;
const uint32_t tid_;
const uint64_t sequence_;
const log_time realtime_;
const uint16_t msg_len_;
};