1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _PAGEMAP_PAGEMAP_H
18#define _PAGEMAP_PAGEMAP_H
19
20#include <stdint.h>
21#include <stdio.h>
22#include <sys/cdefs.h>
23#include <sys/types.h>
24
25__BEGIN_DECLS
26
27typedef struct pm_memusage pm_memusage_t;
28
29/* Holds the various metrics for memory usage of a process or a mapping. */
30struct pm_memusage {
31    size_t vss;
32    size_t rss;
33    size_t pss;
34    size_t uss;
35    size_t swap;
36};
37
38/* Clears a memusage. */
39void pm_memusage_zero(pm_memusage_t *mu);
40/* Adds one memusage (a) to another (b). */
41void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b);
42
43typedef struct pm_kernel   pm_kernel_t;
44typedef struct pm_process  pm_process_t;
45typedef struct pm_map      pm_map_t;
46
47/* pm_kernel_t holds the state necessary to interface to the kernel's pagemap
48 * system on a global level. */
49struct pm_kernel {
50    int kpagecount_fd;
51    int kpageflags_fd;
52
53    int pagesize;
54};
55
56/* pm_process_t holds the state necessary to interface to a particular process'
57 * pagemap. */
58struct pm_process {
59    pm_kernel_t *ker;
60
61    pid_t pid;
62
63    pm_map_t **maps;
64    int num_maps;
65
66    int pagemap_fd;
67};
68
69/* pm_map_t holds the state necessary to access information about a particular
70 * mapping in a particular process. */
71struct pm_map {
72    pm_process_t *proc;
73
74    uint64_t start;
75    uint64_t end;
76    uint64_t offset;
77    int flags;
78
79    char *name;
80};
81
82/* Create a pm_kernel_t. */
83int pm_kernel_create(pm_kernel_t **ker_out);
84
85#define pm_kernel_pagesize(ker) ((ker)->pagesize)
86
87/* Get a list of probably-existing PIDs (returned through *pids_out).
88 * Length of the array (in sizeof(pid_t) units) is returned through *len.
89 * The array should be freed by the caller. */
90int pm_kernel_pids(pm_kernel_t *ker, pid_t **pids_out, size_t *len);
91
92/* Get the map count (from /proc/kpagecount) of a physical frame.
93 * The count is returned through *count_out. */
94int pm_kernel_count(pm_kernel_t *ker, uint64_t pfn, uint64_t *count_out);
95
96/* Get the page flags (from /proc/kpageflags) of a physical frame.
97 * The count is returned through *flags_out. */
98int pm_kernel_flags(pm_kernel_t *ker, uint64_t pfn, uint64_t *flags_out);
99
100#define PM_PAGE_LOCKED     (1 <<  0)
101#define PM_PAGE_ERROR      (1 <<  1)
102#define PM_PAGE_REFERENCED (1 <<  2)
103#define PM_PAGE_UPTODATE   (1 <<  3)
104#define PM_PAGE_DIRTY      (1 <<  4)
105#define PM_PAGE_LRU        (1 <<  5)
106#define PM_PAGE_ACTIVE     (1 <<  6)
107#define PM_PAGE_SLAB       (1 <<  7)
108#define PM_PAGE_WRITEBACK  (1 <<  8)
109#define PM_PAGE_RECLAIM    (1 <<  9)
110#define PM_PAGE_BUDDY      (1 << 10)
111
112/* for kernels >= 2.6.31 */
113#define PM_PAGE_MMAP          (1 << 11)
114#define PM_PAGE_ANON          (1 << 12)
115#define PM_PAGE_SWAPCACHE     (1 << 13)
116#define PM_PAGE_SWAPBACKED    (1 << 14)
117#define PM_PAGE_COMPOUND_HEAD (1 << 15)
118#define PM_PAGE_COMPOUND_TAIL (1 << 16)
119#define PM_PAGE_HUGE          (1 << 17)
120#define PM_PAGE_UNEVICTABLE   (1 << 18)
121#define PM_PAGE_HWPOISON      (1 << 19)
122#define PM_PAGE_NOPAGE        (1 << 20)
123
124/* for kernels >= 2.6.32 */
125#define PM_PAGE_KSM           (1 << 21)
126
127/* for kernels >= 3.4 */
128#define PM_PAGE_THP           (1 << 22)
129
130/* Destroy a pm_kernel_t. */
131int pm_kernel_destroy(pm_kernel_t *ker);
132
133/* Get the PID of a pm_process_t. */
134#define pm_process_pid(proc) ((proc)->pid)
135
136/* Create a pm_process_t and returns it through *proc_out.
137 * Takes a pm_kernel_t, and the PID of the process. */
138int pm_process_create(pm_kernel_t *ker, pid_t pid, pm_process_t **proc_out);
139
140/* Get the total memory usage of a process and store in *usage_out. */
141int pm_process_usage(pm_process_t *proc, pm_memusage_t *usage_out);
142
143/* Get the total memory usage of a process and store in *usage_out, only
144 * counting pages with specified flags. */
145int pm_process_usage_flags(pm_process_t *proc, pm_memusage_t *usage_out,
146                        uint64_t flags_mask, uint64_t required_flags);
147
148/* Get the working set of a process (if ws_out != NULL), and reset it
149 * (if reset != 0). */
150int pm_process_workingset(pm_process_t *proc, pm_memusage_t *ws_out, int reset);
151
152/* Get the PFNs corresponding to a range of virtual addresses.
153 * The array of PFNs is returned through *range_out, and the caller has the
154 * responsibility to free it. */
155int pm_process_pagemap_range(pm_process_t *proc,
156                             uint64_t low, uint64_t hi,
157                             uint64_t **range_out, size_t *len);
158
159#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
160
161#define PM_PAGEMAP_PRESENT(x)     (_BITS(x, 63, 1))
162#define PM_PAGEMAP_SWAPPED(x)     (_BITS(x, 62, 1))
163#define PM_PAGEMAP_SHIFT(x)       (_BITS(x, 55, 6))
164#define PM_PAGEMAP_PFN(x)         (_BITS(x, 0, 55))
165#define PM_PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
166#define PM_PAGEMAP_SWAP_TYPE(x)   (_BITS(x, 0,  5))
167
168/* Get the maps in the virtual address space of this process.
169 * Returns an array of pointers to pm_map_t through *maps.
170 * The array should be freed by the caller, but the maps should not be
171 * modified or destroyed. */
172int pm_process_maps(pm_process_t *proc, pm_map_t ***maps_out, size_t *len);
173
174/* Destroy a pm_process_t. */
175int pm_process_destroy(pm_process_t *proc);
176
177/* Get the name, flags, start/end address, or offset of a map. */
178#define pm_map_name(map)   ((map)->name)
179#define pm_map_flags(map)  ((map)->flags)
180#define PM_MAP_READ  1
181#define PM_MAP_WRITE 2
182#define PM_MAP_EXEC  4
183#define PM_MAP_PERMISSIONS (PM_MAP_READ | PM_MAP_WRITE | PM_MAP_EXEC)
184#define pm_map_start(map)  ((map)->start)
185#define pm_map_end(map)    ((map)->end)
186#define pm_map_offset(map) ((map)->offset)
187
188/* Get the PFNs of the pages in the virtual address space of this map.
189 * Array of PFNs is returned through *pagemap_out, and should be freed by the
190 * caller. */
191int pm_map_pagemap(pm_map_t *map, uint64_t **pagemap_out, size_t *len);
192
193/* Get the memory usage of this map alone. */
194int pm_map_usage(pm_map_t *map, pm_memusage_t *usage_out);
195
196/* Get the memory usage of this map alone, only counting pages with specified
197 * flags. */
198int pm_map_usage_flags(pm_map_t *map, pm_memusage_t *usage_out,
199                        uint64_t flags_mask, uint64_t required_flags);
200
201/* Get the working set of this map alone. */
202int pm_map_workingset(pm_map_t *map, pm_memusage_t *ws_out);
203
204__END_DECLS
205
206#endif
207