From 6c51810b2b64e1a26ee89f8ba1dd7000a936b6cf Mon Sep 17 00:00:00 2001 From: Daniel Colascione Date: Thu, 27 Jul 2017 03:33:34 -0700 Subject: [PATCH] Use /proc/pid/smaps_rollup when available smaps_rollup saves CPU time by having the kernel sum smaps fields before formatting each VMA's smaps; this way, user-space gets a single dummy smaps entry with pre-summed fields, making it much less expensive to measure PSS of large processes. This change makes the Android framework attempt to use smaps_rollup when available; we fall back to regular smaps when it isn't. Test: pssbench; see log message about using smaps_rollup Bug: 63439864 Change-Id: I66e207b02626e3287791e1348f35f58a8d94efe9 --- core/jni/android_os_Debug.cpp | 48 +++++++++++++++++++++++++++++++-------- core/jni/android_os_Debug.h | 34 +++++++++++++++++++++++++++ core/jni/android_util_Process.cpp | 13 ++++------- 3 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 core/jni/android_os_Debug.h diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 6c2b4609ebc7..4d32c0546d93 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -44,16 +45,11 @@ #include "jni.h" #include #include +#include "android_os_Debug.h" namespace android { -static void safeFclose(FILE* fp) { - if (fp) fclose(fp); -} - -using UniqueFile = std::unique_ptr; - static inline UniqueFile MakeUniqueFile(const char* path, const char* mode) { return UniqueFile(fopen(path, mode), safeFclose); } @@ -155,6 +151,14 @@ struct stats_t { int swappedOutPss; }; +enum pss_rollup_support { + PSS_ROLLUP_UNTRIED, + PSS_ROLLUP_SUPPORTED, + PSS_ROLLUP_UNSUPPORTED +}; + +static std::atomic g_pss_rollup_support; + #define BINDER_STATS "/proc/binder/stats" static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz) @@ -548,6 +552,33 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object); } +UniqueFile OpenSmapsOrRollup(int pid) +{ + enum pss_rollup_support rollup_support = + g_pss_rollup_support.load(std::memory_order_relaxed); + if (rollup_support != PSS_ROLLUP_UNSUPPORTED) { + std::string smaps_rollup_path = + base::StringPrintf("/proc/%d/smaps_rollup", pid); + UniqueFile fp_rollup = MakeUniqueFile(smaps_rollup_path.c_str(), "re"); + if (fp_rollup == nullptr && errno != ENOENT) { + return fp_rollup; // Actual error, not just old kernel. + } + if (fp_rollup != nullptr) { + if (rollup_support == PSS_ROLLUP_UNTRIED) { + ALOGI("using rollup pss collection"); + g_pss_rollup_support.store(PSS_ROLLUP_SUPPORTED, + std::memory_order_relaxed); + } + return fp_rollup; + } + g_pss_rollup_support.store(PSS_ROLLUP_UNSUPPORTED, + std::memory_order_relaxed); + } + + std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid); + return MakeUniqueFile(smaps_path.c_str(), "re"); +} + static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUssSwapPss, jlongArray outMemtrack) { @@ -563,12 +594,11 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, } { - std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid); - UniqueFile fp = MakeUniqueFile(smaps_path.c_str(), "re"); + UniqueFile fp = OpenSmapsOrRollup(pid); if (fp != nullptr) { while (true) { - if (fgets(line, 1024, fp.get()) == NULL) { + if (fgets(line, sizeof (line), fp.get()) == NULL) { break; } diff --git a/core/jni/android_os_Debug.h b/core/jni/android_os_Debug.h new file mode 100644 index 000000000000..81270ca994bb --- /dev/null +++ b/core/jni/android_os_Debug.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_OS_DEBUG_H +#define ANDROID_OS_DEBUG_H + +#include +#include + +namespace android { + +inline void safeFclose(FILE* fp) { + if (fp) fclose(fp); +} + +using UniqueFile = std::unique_ptr; +UniqueFile OpenSmapsOrRollup(int pid); + +} // namespace android + +#endif // ANDROID_OS_HW_BLOB_H diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 44f15cd637ed..33c8304f2547 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -31,6 +31,7 @@ #include "android_util_Binder.h" #include +#include "android_os_Debug.h" #include #include @@ -1092,27 +1093,21 @@ static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz) static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid) { - char filename[64]; - - snprintf(filename, sizeof(filename), "/proc/%" PRId32 "/smaps", pid); - - FILE * file = fopen(filename, "r"); - if (!file) { + UniqueFile file = OpenSmapsOrRollup(pid); + if (file == nullptr) { return (jlong) -1; } // Tally up all of the Pss from the various maps char line[256]; jlong pss = 0; - while (fgets(line, sizeof(line), file)) { + while (fgets(line, sizeof(line), file.get())) { jlong v; if (sscanf(line, "Pss: %" SCNd64 " kB", &v) == 1) { pss += v; } } - fclose(file); - // Return the Pss value in bytes, not kilobytes return pss * 1024; } -- 2.11.0