diff options
| author | Christopher Ferris <cferris@google.com> | 2014-03-07 19:42:19 -0800 |
|---|---|---|
| committer | Christopher Ferris <cferris@google.com> | 2014-04-03 14:19:24 -0700 |
| commit | e29609106033a48a6128664668d22bf4fb42a7ee (patch) | |
| tree | c01cd6a8fd876b11a08ff0120af3f263d71b7b53 /libbacktrace/GetPss.cpp | |
| parent | 223fc42b5e289e882f67c893374ffbef595a6901 (diff) | |
| download | system_core-e29609106033a48a6128664668d22bf4fb42a7ee.tar.gz system_core-e29609106033a48a6128664668d22bf4fb42a7ee.tar.bz2 system_core-e29609106033a48a6128664668d22bf4fb42a7ee.zip | |
Create an UnwindMapLocal object.
The way libunwind handles local unwinds is different from remote unwinds,
so create a new map object to handle the differences.
Add new test to verify the map data is being generated correctly.
Add new tests to check for leaks.
Refactor the BACK_LOGW code into a single header file.
Change-Id: I01f3cbfc4b927646174ea1b614fa25d23b9b3427
Diffstat (limited to 'libbacktrace/GetPss.cpp')
| -rw-r--r-- | libbacktrace/GetPss.cpp | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp new file mode 100644 index 000000000..442383b87 --- /dev/null +++ b/libbacktrace/GetPss.cpp @@ -0,0 +1,85 @@ +/* + * 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 <assert.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +// This is an extremely simplified version of libpagemap. + +#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1)) + +#define PAGEMAP_PRESENT(x) (_BITS(x, 63, 1)) +#define PAGEMAP_SWAPPED(x) (_BITS(x, 62, 1)) +#define PAGEMAP_SHIFT(x) (_BITS(x, 55, 6)) +#define PAGEMAP_PFN(x) (_BITS(x, 0, 55)) +#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50)) +#define PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5)) + +static bool ReadData(int fd, unsigned long place, uint64_t *data) { + if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) { + return false; + } + if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) { + return false; + } + return true; +} + +size_t GetPssBytes() { + FILE* maps = fopen("/proc/self/maps", "r"); + assert(maps != NULL); + + int pagecount_fd = open("/proc/kpagecount", O_RDONLY); + assert(pagecount_fd >= 0); + + int pagemap_fd = open("/proc/self/pagemap", O_RDONLY); + assert(pagemap_fd >= 0); + + char line[4096]; + size_t total_pss = 0; + int pagesize = getpagesize(); + while (fgets(line, sizeof(line), maps)) { + uintptr_t start, end; + if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) { + total_pss = 0; + break; + } + for (size_t page = start/pagesize; page < end/pagesize; page++) { + uint64_t data; + if (ReadData(pagemap_fd, page, &data)) { + if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) { + uint64_t count; + if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) { + total_pss += (count >= 1) ? pagesize / count : 0; + } + } + } + } + } + + fclose(maps); + + close(pagecount_fd); + close(pagemap_fd); + + return total_pss; +} |
