diff options
author | Edgar Arriaga <edgararriaga@google.com> | 2022-02-01 18:58:34 -0800 |
---|---|---|
committer | Divyanand Rangu <quic_drangu@quicinc.com> | 2022-03-28 06:46:02 +0000 |
commit | 66547e1c9c4a4bda8cbdf7687da2b599d343f8a0 (patch) | |
tree | 1e35fdbb35d65d774d7da57476c8cffdf46a9427 /services | |
parent | 123e29b617e75aeaaf461a136be146953082094a (diff) |
Fix for compaction bailing out when MAX_RW_COUNT bytes are sent to compaction
Compaction uses process_madvise which internally makes use of iovec
which imposes certain restrictions on the amount of data that can be
sent, previously we had added a constraint of the total vmas sent within
a single syscall determined by UIO_MAXIOV. However, in this CL we also
added a cap on the amount of bytes sent per syscall up to the maximum
supported MAX_RW_COUNT and split the VMA into chunks which end up
being sent in different syscalls.
Test: Verified ZRAM changes during compaction and added logging to
verify that all VMAs where processed
Bug: 205658049
CRs-Fixed:3121545
Change-Id: Ib478397a1199d31a85606b0a38ab1b673b2333fc
(cherry picked from commit 95907f23d8f729168dd3d3cd30bed1744a574464)
Change-Id: I641b9c60c3c49d73190e9cfa4d2bd8cb5498c7a2
Diffstat (limited to 'services')
-rw-r--r-- | services/core/jni/com_android_server_am_CachedAppOptimizer.cpp | 90 |
1 files changed, 68 insertions, 22 deletions
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index 94bc22a05d7a..f0271f806e13 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -57,6 +57,19 @@ using android::base::unique_fd; #define ASYNC_RECEIVED_WHILE_FROZEN (2) #define TXNS_PENDING_WHILE_FROZEN (4) +#define MAX_RW_COUNT (INT_MAX & PAGE_MASK) + +// Defines the maximum amount of VMAs we can send per process_madvise syscall. +// Currently this is set to UIO_MAXIOV which is the maximum segments allowed by +// iovec implementation used by process_madvise syscall +#define MAX_VMAS_PER_COMPACTION UIO_MAXIOV + +// Maximum bytes that we can send per process_madvise syscall once this limit +// is reached we split the remaining VMAs into another syscall. The MAX_RW_COUNT +// limit is imposed by iovec implementation. However, if you want to use a smaller +// limit, it has to be a page aligned value, otherwise, compaction would fail. +#define MAX_BYTES_PER_COMPACTION MAX_RW_COUNT + namespace android { static bool cancelRunningCompaction; @@ -70,12 +83,9 @@ static inline void compactProcessProcfs(int pid, const std::string& compactionTy } // Compacts a set of VMAs for pid using an madviseType accepted by process_madvise syscall -// On success returns the total bytes that where compacted. On failure it returns -// a negative error code from the standard linux error codes. +// Returns the total bytes that where madvised. static int64_t compactMemory(const std::vector<Vma>& vmas, int pid, int madviseType) { - // UIO_MAXIOV is currently a small value and we might have more addresses - // we do multiple syscalls if we exceed its maximum - static struct iovec vmasToKernel[UIO_MAXIOV]; + static struct iovec vmasToKernel[MAX_VMAS_PER_COMPACTION]; if (vmas.empty()) { return 0; @@ -89,33 +99,64 @@ static int64_t compactMemory(const std::vector<Vma>& vmas, int pid, int madviseT compactionInProgress = true; cancelRunningCompaction = false; - int64_t totalBytesCompacted = 0; - for (int iBase = 0; iBase < vmas.size(); iBase += UIO_MAXIOV) { - if (CC_UNLIKELY(cancelRunningCompaction)) { - // There could be a significant delay betweenwhen a compaction - // is requested and when it is handled during this time - // our OOM adjust could have improved. + int64_t totalBytesProcessed = 0; + + int64_t vmaOffset = 0; + for (int iVma = 0; iVma < vmas.size();) { + uint64_t bytesSentToCompact = 0; + int iVec = 0; + while (iVec < MAX_VMAS_PER_COMPACTION && iVma < vmas.size()) { + if (CC_UNLIKELY(cancelRunningCompaction)) { + // There could be a significant delay between when a compaction + // is requested and when it is handled during this time our + // OOM adjust could have improved. + break; + } + + uint64_t vmaStart = vmas[iVma].start + vmaOffset; + uint64_t vmaSize = vmas[iVma].end - vmaStart; + if (vmaSize == 0) { + goto next_vma; + } + vmasToKernel[iVec].iov_base = (void*)vmaStart; + if (vmaSize > MAX_BYTES_PER_COMPACTION - bytesSentToCompact) { + // Exceeded the max bytes that could be sent, so clamp + // the end to avoid exceeding limit and issue compaction + vmaSize = MAX_BYTES_PER_COMPACTION - bytesSentToCompact; + } + + vmasToKernel[iVec].iov_len = vmaSize; + bytesSentToCompact += vmaSize; + ++iVec; + if (bytesSentToCompact >= MAX_BYTES_PER_COMPACTION) { + // Ran out of bytes within iovec, dispatch compaction. + vmaOffset += vmaSize; + break; + } + + next_vma: + // Finished current VMA, and have more bytes remaining + vmaOffset = 0; + ++iVma; + } + + if (cancelRunningCompaction) { cancelRunningCompaction = false; break; } - int totalVmasToKernel = std::min(UIO_MAXIOV, (int)(vmas.size() - iBase)); - for (int iVec = 0, iVma = iBase; iVec < totalVmasToKernel; ++iVec, ++iVma) { - vmasToKernel[iVec].iov_base = (void*)vmas[iVma].start; - vmasToKernel[iVec].iov_len = vmas[iVma].end - vmas[iVma].start; - } - auto bytesCompacted = - process_madvise(pidfd, vmasToKernel, totalVmasToKernel, madviseType, 0); - if (CC_UNLIKELY(bytesCompacted == -1)) { + auto bytesProcessed = process_madvise(pidfd, vmasToKernel, iVec, madviseType, 0); + + if (CC_UNLIKELY(bytesProcessed == -1)) { compactionInProgress = false; return -errno; } - totalBytesCompacted += bytesCompacted; + totalBytesProcessed += bytesProcessed; } compactionInProgress = false; - return totalBytesCompacted; + return totalBytesProcessed; } static int getFilePageAdvice(const Vma& vma) { @@ -138,7 +179,12 @@ static int getAnyPageAdvice(const Vma& vma) { } // Perform a full process compaction using process_madvise syscall -// reading all filtering VMAs and filtering pages as specified by pageFilter +// using the madvise behavior defined by vmaToAdviseFunc per VMA. +// +// Currently supported behaviors are MADV_COLD and MADV_PAGEOUT. +// +// Returns the total number of bytes compacted or forwards an +// process_madvise error. static int64_t compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { ProcMemInfo meminfo(pid); std::vector<Vma> pageoutVmas, coldVmas; |