-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathProcIdlePages.h
147 lines (110 loc) · 3.46 KB
/
ProcIdlePages.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* SPDX-License-Identifier: GPL-2.0
*
* Copyright (c) 2018 Intel Corporation
*
* Authors: Fengguang Wu <fengguang.wu@intel.com>
* Yao Yuan <yuan.yao@intel.com>
* Liu Jingqi <jingqi.liu@intel.com>
*/
#ifndef AEP_PROC_IDLE_PAGES_H
#define AEP_PROC_IDLE_PAGES_H
// interface to /proc/PID/idle_pages
#include <string>
#include <sys/user.h>
#include <sys/types.h>
#include <unordered_map>
#include "ProcMaps.h"
#include "AddrSequence.h"
#include "Option.h"
static const unsigned long PTE_SIZE = 1UL << 12;
static const unsigned long PMD_SIZE = 1UL << 21;
static const unsigned long PUD_SIZE = 1UL << 30;
static const unsigned long P4D_SIZE = 1UL << 39;
static const unsigned long PGDIR_SIZE = 1UL << 39;
static const unsigned long TASK_SIZE_MAX = (1UL << 47) - PAGE_SIZE;
#define SCAN_HUGE_PAGE O_NONBLOCK
#define SCAN_SKIM_IDLE O_NOFOLLOW
enum ProcIdlePageType
{
PTE_ACCESSED, /* 4k page */
PMD_ACCESSED, /* 2M page */
PUD_PRESENT, /* 1G page */
MAX_ACCESSED = PUD_PRESENT,
PTE_DIRTY, /* 3 */
PMD_DIRTY,
PTE_IDLE, /* 5 */
PMD_IDLE,
PMD_IDLE_PTES, /* all PTE idle */
PTE_HOLE, /* 8 */
PMD_HOLE,
PIP_CMD, /* 10 */
IDLE_PAGE_TYPE_MAX
};
#define PIP_TYPE(a) (0xf & (a >> 4))
#define PIP_SIZE(a) (0xf & a)
#define PIP_COMPOSE(type, nr) ((type << 4) | nr)
#define PIP_CMD_SET_HVA PIP_COMPOSE(PIP_CMD, 0)
#define EPT_IDLE_BUF_MIN ((sizeof(uint64_t) + 2) * 2)
extern unsigned long pagetype_size[IDLE_PAGE_TYPE_MAX];
extern const char* pagetype_name[IDLE_PAGE_TYPE_MAX];
extern int pagetype_shift[IDLE_PAGE_TYPE_MAX];
extern int pagetype_index[];
extern int pagetype_batchsize[IDLE_PAGE_TYPE_MAX];
typedef std::unordered_map<unsigned long, uint8_t> page_refs_map;
struct ProcIdleRefs
{
// VA => refs
// accumulated by walk()
AddrSequence page_refs;
// refs => page count
// accumulated by count_refs()
std::vector<unsigned long> refs_count;
};
class ProcIdlePages
{
public:
ProcIdlePages();
void set_pid(pid_t i) { pid = i; }
pid_t get_pid() { return pid; }
void set_va_range(unsigned long start, unsigned long end);
void set_policy(Policy &pol);
int walk();
int has_io_error() const { return io_error; }
ProcIdleRefs& get_pagetype_refs(ProcIdlePageType type)
{ return pagetype_refs[pagetype_index[type]]; }
int get_nr_walks() { return nr_walks; }
private:
int walk_vma(proc_maps_entry& vma);
int open_file(void);
uint64_t u8_to_u64(uint8_t a[]);
void parse_idlepages(proc_maps_entry& vma,
unsigned long& va,
unsigned long end,
int bytes);
void dump_idlepages(proc_maps_entry& vma, int bytes);
void inc_page_refs(ProcIdlePageType type, int nr,
unsigned long va, unsigned long end);
unsigned long va_to_offset(unsigned long va);
unsigned long offset_to_va(unsigned long offset);
protected:
pid_t pid;
Policy policy;
ProcMaps proc_maps;
unsigned long va_start;
unsigned long va_end;
// if negative, indicates exited process;
// if positive, indicates skipped process
int io_error;
protected:
int nr_walks;
ProcIdleRefs pagetype_refs[MAX_ACCESSED + 1];
private:
static const int READ_BUF_SIZE = 1 << 20;
int idle_fd;
std::vector<uint8_t> read_buf;
unsigned long min_read_size;
unsigned long next_va;
};
#endif
// vim:set ts=2 sw=2 et: