summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdgar Arriaga <edgararriaga@google.com>2022-02-01 18:58:34 -0800
committerDivyanand Rangu <quic_drangu@quicinc.com>2022-03-28 06:46:02 +0000
commit66547e1c9c4a4bda8cbdf7687da2b599d343f8a0 (patch)
tree1e35fdbb35d65d774d7da57476c8cffdf46a9427
parent123e29b617e75aeaaf461a136be146953082094a (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
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp90
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;