/* * Copyright (C) 2014 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "NativeInfo.h" void NativeFormatFloat(char* buffer, size_t buffer_len, uint64_t value, uint64_t divisor) { uint64_t hundreds = ((((value % divisor) * 1000) / divisor) + 5) / 10; snprintf(buffer, buffer_len, "%" PRIu64 ".%02" PRIu64, value / divisor, hundreds); } // This function is not re-entrant since it uses a static buffer for // the line data. void NativeGetInfo(int smaps_fd, size_t* rss_bytes, size_t* va_bytes) { size_t total_rss_bytes = 0; size_t total_va_bytes = 0; bool native_map = false; char buf[1024]; size_t buf_start = 0; size_t buf_bytes = 0; while (true) { ssize_t bytes = TEMP_FAILURE_RETRY(read(smaps_fd, buf + buf_bytes, sizeof(buf) - buf_bytes - 1)); if (bytes <= 0) { break; } buf_bytes += bytes; while (buf_bytes > 0) { char* newline = reinterpret_cast(memchr(&buf[buf_start], '\n', buf_bytes)); if (newline == nullptr) { break; } *newline = '\0'; uintptr_t start, end; int name_pos; size_t native_rss_kB; if (sscanf(&buf[buf_start], "%" SCNxPTR "-%" SCNxPTR " %*4s %*x %*x:%*x %*d %n", &start, &end, &name_pos) == 2) { char* map_name = &buf[buf_start + name_pos]; if (strcmp(map_name, "[anon:libc_malloc]") == 0 || strcmp(map_name, "[heap]") == 0 || strncmp(map_name, "[anon:scudo:", 12) == 0 || strncmp(map_name, "[anon:GWP-ASan", 14) == 0) { total_va_bytes += end - start; native_map = true; } else { native_map = false; } } else if (native_map && sscanf(&buf[buf_start], "Rss: %zu", &native_rss_kB) == 1) { total_rss_bytes += native_rss_kB * 1024; } buf_bytes -= newline - &buf[buf_start] + 1; buf_start = newline - buf + 1; } if (buf_start > 0) { if (buf_bytes > 0) { memmove(buf, &buf[buf_start], buf_bytes); } buf_start = 0; } } *rss_bytes = total_rss_bytes; *va_bytes = total_va_bytes; } void NativePrintInfo(const char* preamble) { size_t rss_bytes; size_t va_bytes; android::base::unique_fd smaps_fd(open("/proc/self/smaps", O_RDONLY)); if (smaps_fd == -1) { err(1, "Cannot open /proc/self/smaps"); } NativeGetInfo(smaps_fd, &rss_bytes, &va_bytes); // Avoid any allocations, so use special non-allocating printfs. char buffer[256]; NativeFormatFloat(buffer, sizeof(buffer), rss_bytes, 1024 * 1024); dprintf(STDOUT_FILENO, "%sNative RSS: %zu bytes %sMB\n", preamble, rss_bytes, buffer); NativeFormatFloat(buffer, sizeof(buffer), va_bytes, 1024 * 1024); dprintf(STDOUT_FILENO, "%sNative VA Space: %zu bytes %sMB\n", preamble, va_bytes, buffer); }