From c51efbe68fab370321f662c71d8dce76a3a226e1 Mon Sep 17 00:00:00 2001 From: Edgar Arriaga Date: Wed, 12 Aug 2020 13:03:57 -0700 Subject: [PATCH 1/5] Migrate to use process_madvise syscall instead of procfs interface for memory compaction Currently the system uses procfs and we are migrating to use a syscall called process_madvise which makes the code upstreamable and will allow for making compaction widely available for multiple android devices. It also opens room for future developments that involve a finer grain VMA compressions than the current procfs allows. Test: Ran the system without crashes and verified am_compact was effectively showing compressed memory (free zram reduced) when compressing. Bug: 162993824 Test: Manual, verified that zram was being increased over time after compactions happened Change-Id: I9d9d895aee7fbc46a2f12f6ca080ab8457ea7222 Merged-In: I9d9d895aee7fbc46a2f12f6ca080ab8457ea7222 --- .../android/server/am/CachedAppOptimizer.java | 60 +++--- services/core/jni/Android.bp | 2 + ...m_android_server_am_CachedAppOptimizer.cpp | 177 ++++++++++++++++-- 3 files changed, 201 insertions(+), 38 deletions(-) diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 36d4a38c1624f..8e259b5f5075b 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -80,20 +80,22 @@ public final class CachedAppOptimizer { // Phenotype sends int configurations and we map them to the strings we'll use on device, // preventing a weird string value entering the kernel. + private static final int COMPACT_ACTION_NONE = 0; + private static final int COMPACT_ACTION_FILE = 1; + private static final int COMPACT_ACTION_ANON = 2; + private static final int COMPACT_ACTION_FULL = 3; + + private static final String COMPACT_ACTION_STRING[] = {"", "file", "anon", "all"}; + + // Keeps these flags in sync with services/core/jni/com_android_server_am_CachedAppOptimizer.cpp private static final int COMPACT_ACTION_FILE_FLAG = 1; private static final int COMPACT_ACTION_ANON_FLAG = 2; - private static final int COMPACT_ACTION_FULL_FLAG = 3; - private static final int COMPACT_ACTION_NONE_FLAG = 4; - private static final String COMPACT_ACTION_NONE = ""; - private static final String COMPACT_ACTION_FILE = "file"; - private static final String COMPACT_ACTION_ANON = "anon"; - private static final String COMPACT_ACTION_FULL = "all"; // Defaults for phenotype flags. @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false; @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = false; - @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE_FLAG; - @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_FULL_FLAG; + @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE; + @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_FULL; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500; @@ -405,6 +407,14 @@ public final class CachedAppOptimizer { private native void compactSystem(); + /** + * Compacts a process or app + * @param pid pid of process to compact + * @param compactionFlags selects the compaction type as defined by COMPACT_ACTION_{TYPE}_FLAG + * constants + */ + static private native void compactProcess(int pid, int compactionFlags); + /** * Reads the flag value from DeviceConfig to determine whether app compaction * should be enabled, and starts the freeze/compaction thread if needed. @@ -706,18 +716,11 @@ public final class CachedAppOptimizer { @VisibleForTesting static String compactActionIntToString(int action) { - switch(action) { - case COMPACT_ACTION_NONE_FLAG: - return COMPACT_ACTION_NONE; - case COMPACT_ACTION_FILE_FLAG: - return COMPACT_ACTION_FILE; - case COMPACT_ACTION_ANON_FLAG: - return COMPACT_ACTION_ANON; - case COMPACT_ACTION_FULL_FLAG: - return COMPACT_ACTION_FULL; - default: - return COMPACT_ACTION_NONE; + if (action < 0 || action >= COMPACT_ACTION_STRING.length) { + return ""; } + + return COMPACT_ACTION_STRING[action]; } // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS @@ -950,11 +953,11 @@ public final class CachedAppOptimizer { action = mCompactActionFull; break; default: - action = COMPACT_ACTION_NONE; + action = COMPACT_ACTION_STRING[COMPACT_ACTION_NONE]; break; } - if (COMPACT_ACTION_NONE.equals(action)) { + if (COMPACT_ACTION_STRING[COMPACT_ACTION_NONE].equals(action)) { return; } @@ -978,7 +981,8 @@ public final class CachedAppOptimizer { return; } - if (action.equals(COMPACT_ACTION_FULL) || action.equals(COMPACT_ACTION_ANON)) { + if (action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_FULL]) + || action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_ANON])) { if (mFullAnonRssThrottleKb > 0L && anonRssBefore < mFullAnonRssThrottleKb) { if (DEBUG_COMPACTION) { @@ -1054,8 +1058,8 @@ public final class CachedAppOptimizer { proc.lastCompactTime = end; proc.lastCompactAction = pendingAction; } - if (action.equals(COMPACT_ACTION_FULL) - || action.equals(COMPACT_ACTION_ANON)) { + if (action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_FULL]) + || action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_ANON])) { // Remove entry and insert again to update insertion order. mLastCompactionStats.remove(pid); mLastCompactionStats.put(pid, new LastCompactionStats(rssAfter)); @@ -1197,8 +1201,12 @@ public final class CachedAppOptimizer { // Compact process. @Override public void performCompaction(String action, int pid) throws IOException { - try (FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim")) { - fos.write(action.getBytes()); + if (action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_FULL])) { + compactProcess(pid, COMPACT_ACTION_FILE_FLAG | COMPACT_ACTION_ANON_FLAG); + } else if (action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_FILE])) { + compactProcess(pid, COMPACT_ACTION_FILE_FLAG); + } else if (action.equals(COMPACT_ACTION_STRING[COMPACT_ACTION_ANON])) { + compactProcess(pid, COMPACT_ACTION_ANON_FLAG); } } } diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index d0bd8b3e1ae29..a0c96f0f19b8b 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -74,6 +74,7 @@ cc_library_static { "frameworks/base/libs", "frameworks/native/services", "system/gatekeeper/include", + "system/memory/libmeminfo/include", ], header_libs: [ @@ -111,6 +112,7 @@ cc_defaults { "libhardware", "libhardware_legacy", "libhidlbase", + "libmeminfo", "libmemtrackproxy", "libmtp", "libnativehelper", diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index 678308af34ea3..156ef795db6d0 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -17,15 +17,25 @@ #define LOG_TAG "CachedAppOptimizer" //#define LOG_NDEBUG 0 +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include #include +#include #include +#include #include #include -#include -#include +#include #include #include @@ -35,12 +45,149 @@ using android::base::StringPrintf; using android::base::WriteStringToFile; +using android::meminfo::ProcMemInfo; +using namespace android::meminfo; + +// This is temporarily hard-coded and should be removed once +// bionic/libc/kernel/uapi/asm-generic/unistd.h are updated with process_madvise syscall header +#ifndef __NR_process_madvise +#define __NR_process_madvise 440 +#define MADV_COLD 20 /* deactivate these pages */ +#define MADV_PAGEOUT 21 +#endif + +#define COMPACT_ACTION_FILE_FLAG 1 +#define COMPACT_ACTION_ANON_FLAG 2 + +using VmaToAdviseFunc = std::function; #define SYNC_RECEIVED_WHILE_FROZEN (1) #define ASYNC_RECEIVED_WHILE_FROZEN (2) namespace android { +// Legacy method for compacting processes, any new code should +// use compactProcess instead. +static inline void compactProcessProcfs(int pid, const std::string& compactionType) { + std::string reclaim_path = StringPrintf("/proc/%d/reclaim", pid); + WriteStringToFile(compactionType, reclaim_path); +} + +static int compactMemory(const std::vector& 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]; + + int err = 0; + + if (vmas.empty()) { + return err; + } + + int pidfd = syscall(__NR_pidfd_open, pid, 0); + err = -errno; + if (err < 0) { + // Skip compaction if failed to open pidfd with any error + return err; + } + + for (int iBase = 0; iBase < vmas.size(); iBase += UIO_MAXIOV) { + 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; + } + + process_madvise(pidfd, vmasToKernel, totalVmasToKernel, madviseType, 0); + err = -errno; + if (CC_UNLIKELY(err == -ENOSYS)) { + // Syscall does not exist, skip trying more calls process_madvise + break; + } + } + + close(pidfd); + + return err; +} + +static int getFilePageAdvice(const Vma& vma) { + if (vma.inode > 0 && !vma.is_shared) { + return MADV_COLD; + } + return -1; +} +static int getAnonPageAdvice(const Vma& vma) { + if (vma.inode == 0 && !vma.is_shared) { + return MADV_PAGEOUT; + } + return -1; +} +static bool getAnyPageAdvice(const Vma& vma) { + if (vma.inode == 0 && !vma.is_shared) { + return MADV_PAGEOUT; + } + return MADV_COLD; +} + +// Perform a full process compaction using process_madvise syscall +// reading all filtering VMAs and filtering pages as specified by pageFilter +static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { + ProcMemInfo meminfo(pid); + std::vector pageoutVmas, coldVmas; + auto vmaCollectorCb = [&](Vma vma) { + int advice = vmaToAdviseFunc(vma); + switch (advice) { + case MADV_COLD: + coldVmas.push_back(vma); + break; + case MADV_PAGEOUT: + pageoutVmas.push_back(vma); + break; + } + }; + meminfo.ForEachVma(vmaCollectorCb); + + int err = compactMemory(pageoutVmas, pid, MADV_PAGEOUT); + if (!err) { + err = compactMemory(coldVmas, pid, MADV_COLD); + } + return err; +} + +// Compact process using process_madvise syscall or fallback to procfs in +// case syscall does not exist. +static void compactProcessOrFallback(int pid, int compactionFlags) { + if ((compactionFlags & (COMPACT_ACTION_ANON_FLAG | COMPACT_ACTION_FILE_FLAG)) == 0) return; + + bool compactAnon = compactionFlags & COMPACT_ACTION_ANON_FLAG; + bool compactFile = compactionFlags & COMPACT_ACTION_FILE_FLAG; + + // Set when the system does not support process_madvise syscall to avoid + // gathering VMAs in subsequent calls prior to falling back to procfs + static bool shouldForceProcFs = false; + std::string compactionType; + VmaToAdviseFunc vmaToAdviseFunc; + + if (compactAnon) { + if (compactFile) { + compactionType = "all"; + vmaToAdviseFunc = getAnyPageAdvice; + } else { + compactionType = "anon"; + vmaToAdviseFunc = getAnonPageAdvice; + } + } else { + compactionType = "file"; + vmaToAdviseFunc = getFilePageAdvice; + } + + if (shouldForceProcFs || compactProcess(pid, vmaToAdviseFunc) == -ENOSYS) { + shouldForceProcFs = true; + compactProcessProcfs(pid, compactionType); + } +} + // This performs per-process reclaim on all processes belonging to non-app UIDs. // For the most part, these are non-zygote processes like Treble HALs, but it // also includes zygote-derived processes that run in system UIDs, like bluetooth @@ -74,11 +221,17 @@ static void com_android_server_am_CachedAppOptimizer_compactSystem(JNIEnv *, job continue; } - std::string reclaim_path = StringPrintf("/proc/%s/reclaim", current->d_name); - WriteStringToFile(std::string("all"), reclaim_path); + int pid = atoi(current->d_name); + + compactProcessOrFallback(pid, COMPACT_ACTION_ANON_FLAG | COMPACT_ACTION_FILE_FLAG); } } +static void com_android_server_am_CachedAppOptimizer_compactProcess(JNIEnv*, jobject, jint pid, + jint compactionFlags) { + compactProcessOrFallback(pid, compactionFlags); +} + static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal( JNIEnv *env, jobject clazz, jboolean enable) { bool success = true; @@ -126,14 +279,14 @@ static jint com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo(JNIEnv } static const JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem}, - {"enableFreezerInternal", "(Z)V", - (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal}, - {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder}, - {"getBinderFreezeInfo", "(I)I", - (void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo} -}; + /* name, signature, funcPtr */ + {"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem}, + {"compactProcess", "(II)V", (void*)com_android_server_am_CachedAppOptimizer_compactProcess}, + {"enableFreezerInternal", "(Z)V", + (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal}, + {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder}, + {"getBinderFreezeInfo", "(I)I", + (void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo}}; int register_android_server_am_CachedAppOptimizer(JNIEnv* env) { From a4ecb890dfdfefe67cc926520f635fe43f383403 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Wed, 27 Jan 2021 08:59:19 -0800 Subject: [PATCH 2/5] Fix function return type Test: TreeHugger Change-Id: I2336a0c2bf3f71cc0b0bc1ef491a1043e88f359e Merged-In: I2336a0c2bf3f71cc0b0bc1ef491a1043e88f359e --- services/core/jni/com_android_server_am_CachedAppOptimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index 156ef795db6d0..31cc295406a50 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -123,7 +123,7 @@ static int getAnonPageAdvice(const Vma& vma) { } return -1; } -static bool getAnyPageAdvice(const Vma& vma) { +static int getAnyPageAdvice(const Vma& vma) { if (vma.inode == 0 && !vma.is_shared) { return MADV_PAGEOUT; } From 9a240462593cffa1590989d796a4814f47242d1f Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Mon, 22 Feb 2021 17:57:06 -0800 Subject: [PATCH 3/5] CachedAppOptimizer: fix fd leak. errno isn't modified when a syscall returns successfully: this would leak if errno was already non-zero before entering this function. Bug: 172518739 Test: none Change-Id: I38050863ceca226a9c2d143c85e0713c6a6fe511 Merged-In: I38050863ceca226a9c2d143c85e0713c6a6fe511 --- services/core/jni/com_android_server_am_CachedAppOptimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index 31cc295406a50..456ff0049303b 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -86,7 +86,7 @@ static int compactMemory(const std::vector& vmas, int pid, int madviseType) int pidfd = syscall(__NR_pidfd_open, pid, 0); err = -errno; - if (err < 0) { + if (pidfd < 0) { // Skip compaction if failed to open pidfd with any error return err; } From 3536bf7b5531a6f7a42d1c0366e36a651ebba656 Mon Sep 17 00:00:00 2001 From: Edgar Arriaga Date: Thu, 25 Feb 2021 19:20:05 -0800 Subject: [PATCH 4/5] Avoid unnecessary smaps logic during app compaction ForEachVma can extract data from both maps and smaps files, however the smaps logic is not used during app compaction. Replace its usage with ForEachVmaFromMaps which reads only maps file and skips any smaps logic. This results in ~22% CPU usage reduction. Test: Manual Bug: 181174877 Signed-off-by: Edgar Arriaga Change-Id: I165f211c2084676bc7872d190ffad14141f56ea8 Merged-In: I165f211c2084676bc7872d190ffad14141f56ea8 --- .../core/jni/com_android_server_am_CachedAppOptimizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index 456ff0049303b..f78e7bfc01a74 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -135,7 +135,7 @@ static int getAnyPageAdvice(const Vma& vma) { static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { ProcMemInfo meminfo(pid); std::vector pageoutVmas, coldVmas; - auto vmaCollectorCb = [&](Vma vma) { + auto vmaCollectorCb = [&coldVmas,&pageoutVmas,&vmaToAdviseFunc](const Vma& vma) { int advice = vmaToAdviseFunc(vma); switch (advice) { case MADV_COLD: @@ -146,7 +146,7 @@ static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { break; } }; - meminfo.ForEachVma(vmaCollectorCb); + meminfo.ForEachVmaFromMaps(vmaCollectorCb); int err = compactMemory(pageoutVmas, pid, MADV_PAGEOUT); if (!err) { From a251df62b7d92724e3ad1e924a1536e1b2558690 Mon Sep 17 00:00:00 2001 From: Edgar Arriaga Date: Mon, 5 Apr 2021 10:57:37 -0700 Subject: [PATCH 5/5] cleanups and fixes for process_madvise compaction some fix suggestions that came up on ag/13665789 and some other cleanups 1. Use unique_fd instead of raw int to keep pidfd 2. Return the total compacted bytes on success for compactProcess 3. Fix for error potentially returning a random value 4. Fix truncation that could happen when calling madvise 5. Fail fast after encountering an error instead of silently advancing to other VMAs when compacting. Bug: 162993824 Test: Manual Signed-off-by: Edgar Arriaga Change-Id: Ide644f66cf0ebdea570dcb365d6a2400ffb18f4e --- ...m_android_server_am_CachedAppOptimizer.cpp | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index f78e7bfc01a74..af3948bd7ce25 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -18,8 +18,11 @@ //#define LOG_NDEBUG 0 #include +#include #include +#include #include +#include #include #include #include @@ -27,9 +30,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -37,29 +42,16 @@ #include -#include -#include -#include -#include -#include - using android::base::StringPrintf; using android::base::WriteStringToFile; using android::meminfo::ProcMemInfo; using namespace android::meminfo; -// This is temporarily hard-coded and should be removed once -// bionic/libc/kernel/uapi/asm-generic/unistd.h are updated with process_madvise syscall header -#ifndef __NR_process_madvise -#define __NR_process_madvise 440 -#define MADV_COLD 20 /* deactivate these pages */ -#define MADV_PAGEOUT 21 -#endif - #define COMPACT_ACTION_FILE_FLAG 1 #define COMPACT_ACTION_ANON_FLAG 2 using VmaToAdviseFunc = std::function; +using android::base::unique_fd; #define SYNC_RECEIVED_WHILE_FROZEN (1) #define ASYNC_RECEIVED_WHILE_FROZEN (2) @@ -73,24 +65,25 @@ static inline void compactProcessProcfs(int pid, const std::string& compactionTy WriteStringToFile(compactionType, reclaim_path); } -static int compactMemory(const std::vector& vmas, int pid, int madviseType) { +// 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. +static int64_t compactMemory(const std::vector& 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]; - int err = 0; - if (vmas.empty()) { - return err; + return 0; } - int pidfd = syscall(__NR_pidfd_open, pid, 0); - err = -errno; + unique_fd pidfd(pidfd_open(pid, 0)); if (pidfd < 0) { // Skip compaction if failed to open pidfd with any error - return err; + return -errno; } + int64_t totalBytesCompacted = 0; for (int iBase = 0; iBase < vmas.size(); iBase += UIO_MAXIOV) { int totalVmasToKernel = std::min(UIO_MAXIOV, (int)(vmas.size() - iBase)); for (int iVec = 0, iVma = iBase; iVec < totalVmasToKernel; ++iVec, ++iVma) { @@ -98,17 +91,16 @@ static int compactMemory(const std::vector& vmas, int pid, int madviseType) vmasToKernel[iVec].iov_len = vmas[iVma].end - vmas[iVma].start; } - process_madvise(pidfd, vmasToKernel, totalVmasToKernel, madviseType, 0); - err = -errno; - if (CC_UNLIKELY(err == -ENOSYS)) { - // Syscall does not exist, skip trying more calls process_madvise - break; + auto bytesCompacted = + process_madvise(pidfd, vmasToKernel, totalVmasToKernel, madviseType, 0); + if (CC_UNLIKELY(bytesCompacted == -1)) { + return -errno; } + + totalBytesCompacted += bytesCompacted; } - close(pidfd); - - return err; + return totalBytesCompacted; } static int getFilePageAdvice(const Vma& vma) { @@ -132,7 +124,7 @@ 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 -static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { +static int64_t compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { ProcMemInfo meminfo(pid); std::vector pageoutVmas, coldVmas; auto vmaCollectorCb = [&coldVmas,&pageoutVmas,&vmaToAdviseFunc](const Vma& vma) { @@ -148,11 +140,19 @@ static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { }; meminfo.ForEachVmaFromMaps(vmaCollectorCb); - int err = compactMemory(pageoutVmas, pid, MADV_PAGEOUT); - if (!err) { - err = compactMemory(coldVmas, pid, MADV_COLD); + int64_t pageoutBytes = compactMemory(pageoutVmas, pid, MADV_PAGEOUT); + if (pageoutBytes < 0) { + // Error, just forward it. + return pageoutBytes; } - return err; + + int64_t coldBytes = compactMemory(coldVmas, pid, MADV_COLD); + if (coldBytes < 0) { + // Error, just forward it. + return coldBytes; + } + + return pageoutBytes + coldBytes; } // Compact process using process_madvise syscall or fallback to procfs in