Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Ruben Laso Rodríguez
Thanos
Commits
1201c0fe
Commit
1201c0fe
authored
May 23, 2022
by
Ruben Laso Rodríguez
Browse files
feat: use pfs library to extract info about memory pages from the '/proc/'
parent
d6a3759d
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/main.cpp
View file @
1201c0fe
...
...
@@ -353,8 +353,6 @@ namespace {
migration
::
add_pids
(
children
);
samples
::
update_PIDs_to_filter
(
children
);
memory_info
::
update_memory_regions
(
samples
::
PIDs_to_filter
);
}
if
(
update_mem
&&
utils
::
time
::
time_until
(
last_mem_update
,
current_time
)
>
secs_update_mem
)
{
...
...
src/migration/migration.hpp
View file @
1201c0fe
...
...
@@ -84,8 +84,6 @@ namespace migration {
}
}
memory_info
::
update_memory_regions
(
system_info
::
get_children
());
if
(
verbose
::
print_with_lvl
(
verbose
::
DEFAULT_LVL
))
{
const
auto
pages_proc
=
memory_info
::
n_pages_all_regions
();
const
auto
pages_enough_info
=
perf_table
.
pages_with_enough_info
();
...
...
src/system_info/memory/mem_region.hpp
View file @
1201c0fe
...
...
@@ -22,30 +22,17 @@
class
mem_region
:
public
mem_region_maps
,
public
mem_region_numa_maps
{
public:
mem_region
(
const
pid_t
pid
,
const
size_t
maps_index
,
const
size_t
numa_maps_index
)
:
mem_region_maps
(
pid
,
maps_index
),
mem_region_numa_maps
(
pid
,
numa_maps_index
)
{
}
mem_region
(
const
pid_t
pid
,
const
std
::
string
&
line_maps
,
const
size_t
index_maps
,
const
std
::
string
&
line_numa_maps
,
const
size_t
index_numa_maps
)
:
mem_region_maps
(
line_maps
,
index_maps
,
pid
),
mem_region_numa_maps
(
line_numa_maps
,
index_numa_maps
,
pid
)
{
}
mem_region
(
mem_region_maps
&
maps
,
mem_region_numa_maps
&
numa_maps
)
:
mem_region_maps
(
maps
),
mem_region_numa_maps
(
numa_maps
)
{
}
[[
nodiscard
]]
inline
auto
index_maps
()
const
{
return
mem_region_maps
::
index
();
}
[[
nodiscard
]]
inline
auto
index_numa_maps
()
const
{
return
mem_region_numa_maps
::
index
();
mem_region
(
mem_region_maps
maps
,
mem_region_numa_maps
numa_maps
)
:
mem_region_maps
(
std
::
move
(
maps
)),
mem_region_numa_maps
(
std
::
move
(
numa_maps
))
{
}
inline
friend
auto
operator
<<
(
std
::
ostream
&
os
,
const
mem_region
&
m
)
->
std
::
ostream
&
{
const
auto
raw_perm
=
m
.
flags
();
const
auto
perm
=
std
::
string
(
raw_perm
.
can_read
?
"r"
:
"-"
)
+
std
::
string
(
raw_perm
.
can_write
?
"w"
:
"-"
)
+
std
::
string
(
raw_perm
.
can_execute
?
"x"
:
"-"
);
os
<<
utils
::
string
::
to_string_hex
(
m
.
begin
())
<<
'-'
<<
utils
::
string
::
to_string_hex
(
m
.
end
())
<<
std
::
dec
<<
' '
<<
m
.
bytes
()
<<
"B "
<<
m
.
flags
()
<<
' '
<<
"policy="
<<
m
.
policy
()
<<
' '
;
<<
m
.
bytes
()
<<
"B "
<<
perm
<<
' '
<<
"policy="
<<
m
.
policy
()
<<
' '
;
os
<<
"Pages per node: "
;
for
(
const
auto
n
:
system_info
::
nodes
())
{
os
<<
m
.
pages_per_node
()[
n
]
<<
(
std
::
cmp_not_equal
(
n
,
m
.
pages_per_node
().
size
()
-
1
)
?
','
:
' '
);
...
...
src/system_info/memory/mem_region_maps.hpp
View file @
1201c0fe
...
...
@@ -19,101 +19,48 @@
#include
<stdexcept>
// for runtime_error
#include
<string>
// for string, getline, operator<<
#include
<sys/types.h>
// for pid_t
#include
<utility>
#include
"utils/types.hpp"
// for addr_t
#include
"third_party_libs/pfs/include/pfs/procfs.hpp"
class
mem_region_maps
{
private:
static
constexpr
const
char
SHARED
=
's'
;
static
constexpr
const
char
PRIVATE
=
'p'
;
// copy on write
static
constexpr
const
char
READ
=
'r'
;
static
constexpr
const
char
WRITE
=
'w'
;
static
constexpr
const
char
EXECUTE
=
'x'
;
static
constexpr
const
char
NO_PERMISSION
=
'-'
;
static
constexpr
const
char
*
const
STACK
=
"[stack]"
;
// Main process stack
static
constexpr
const
char
*
const
STACK_TID
=
"[heap:<tid>]"
;
// A thread's stack
static
constexpr
const
char
*
const
VDSO
=
"[vdso]"
;
// The virtual dynamically linked shared object
static
constexpr
const
char
*
const
HEAP
=
"[heap]"
;
// The process's heap
static
constexpr
const
std
::
string_view
STACK
=
"[stack]"
;
// Main process stack
static
constexpr
const
std
::
string_view
STACK_TID
=
"[heap:<tid>]"
;
// A thread's stack
static
constexpr
const
std
::
string_view
VDSO
=
"[vdso]"
;
// The virtual dynamically linked shared object
static
constexpr
const
std
::
string_view
HEAP
=
"[heap]"
;
// The process's heap
size_t
index_
;
pid_t
tid_
;
pid_t
pid_
;
addr_t
begin_
{};
addr_t
end_
{};
pfs
::
mem_region
mem_region_
;
size_t
bytes_
{};
std
::
array
<
char
,
5
>
flags_
{
'\0'
};
uint32_t
offset_
{};
uint32_t
device_maj_
{};
uint32_t
device_min_
{};
uint32_t
inode_
{};
std
::
array
<
char
,
PATH_MAX
>
path_
{
'\0'
};
inline
void
parse_line
(
const
std
::
string
&
line
)
{
std
::
sscanf
(
line
.
c_str
(),
"%lx-%lx %4c %x %x:%x %x %s"
,
&
begin_
,
&
end_
,
flags_
.
data
(),
&
offset_
,
&
device_maj_
,
&
device_min_
,
&
inode_
,
path_
.
data
());
flags_
.
back
()
=
'\0'
;
bytes_
=
end_
-
begin_
;
}
public:
mem_region_maps
(
const
pid_t
pid
,
const
size_t
index
)
:
index_
(
index
),
tid_
(
pid
)
{
const
auto
filename
=
"/proc/"
+
std
::
to_string
(
pid
)
+
"/maps"
;
std
::
ifstream
file
(
filename
);
if
(
!
file
.
good
())
{
const
auto
error
=
"Cannot open file "
+
filename
+
": "
+
strerror
(
errno
);
throw
std
::
runtime_error
(
error
);
}
bool
index_found
=
false
;
size_t
i
=
0
;
while
(
file
.
good
())
{
std
::
string
line
;
std
::
getline
(
file
,
line
);
++
i
;
if
(
std
::
cmp_equal
(
i
,
index
))
{
index_found
=
true
;
parse_line
(
line
);
break
;
}
}
if
(
!
index_found
)
{
const
auto
error
=
"Cannot found line number "
+
std
::
to_string
(
index
);
throw
std
::
runtime_error
(
error
);
}
}
mem_region_maps
(
const
std
::
string
&
line_info
,
const
size_t
&
index
,
const
pid_t
&
tid
)
:
index_
(
index
),
tid_
(
tid
)
{
parse_line
(
line_info
);
mem_region_maps
(
const
pid_t
pid
,
pfs
::
mem_region
region
)
:
pid_
(
pid
),
mem_region_
(
std
::
move
(
region
)),
bytes_
(
mem_region_
.
end_address
-
mem_region_
.
start_address
)
{
}
[[
nodiscard
]]
inline
auto
index
()
const
{
return
index_
;
mem_region_maps
(
const
pid_t
pid
,
const
size_t
index
)
:
pid_
(
pid
),
mem_region_
(
pfs
::
procfs
().
get_task
(
pid
).
get_maps
().
at
(
index
)),
bytes_
(
mem_region_
.
end_address
-
mem_region_
.
start_address
)
{
}
[[
nodiscard
]]
inline
auto
begin
()
const
{
return
b
egin_
;
return
mem_r
egi
o
n_
.
start_address
;
}
[[
nodiscard
]]
inline
auto
end
()
const
{
return
end_
;
return
mem_region_
.
end_address
;
}
[[
nodiscard
]]
inline
auto
bytes
()
const
{
...
...
@@ -121,59 +68,63 @@ public:
}
[[
nodiscard
]]
inline
auto
flags
()
const
{
return
flags_
.
data
()
;
return
mem_region_
.
perm
;
}
[[
nodiscard
]]
inline
auto
path
()
const
{
return
path_
;
return
mem_region_
.
pathname
;
}
[[
nodiscard
]]
inline
auto
read
()
const
->
bool
{
return
flags_
[
0
]
==
READ
;
return
mem_region_
.
perm
.
can_read
;
}
[[
nodiscard
]]
inline
auto
write
()
const
->
bool
{
return
flags_
[
1
]
==
WRITE
;
return
mem_region_
.
perm
.
can_write
;
}
[[
nodiscard
]]
inline
auto
execute
()
const
->
bool
{
return
flags_
[
2
]
==
EXECUTE
;
return
mem_region_
.
perm
.
can_execute
;
}
[[
nodiscard
]]
inline
auto
is_private
()
const
->
bool
{
return
flags_
[
4
]
==
PRIVATE
;
return
mem_region_
.
perm
.
is_private
;
}
[[
nodiscard
]]
inline
auto
is_shared
()
const
->
bool
{
return
flags_
[
4
]
==
SHARED
;
return
mem_region_
.
perm
.
is_shared
;
}
[[
nodiscard
]]
inline
auto
heap
()
->
bool
{
bool
is_heap
=
false
;
// First check if it is main process's stack
is_heap
=
strcmp
(
path_
.
data
(),
HEAP
)
==
0
;
is_heap
=
mem_region_
.
pathname
==
HEAP
;
if
(
!
is_heap
)
{
std
::
array
<
char
,
PATH_MAX
>
heap_tid
{
'\0'
}
;
sprintf
(
heap_tid
.
data
(),
"[heap:%ul]"
,
t
id_
);
is_heap
=
strcmp
(
path
_
.
d
at
a
(),
heap_tid
.
data
())
==
0
;
std
::
string
heap_tid
(
PATH_MAX
,
'\0'
)
;
sprintf
(
heap_tid
.
data
(),
"[heap:%ul]"
,
p
id_
);
is_heap
=
mem_region
_
.
p
at
hname
==
heap_tid
;
}
return
is_heap
;
}
[[
nodiscard
]]
inline
auto
stack
()
const
->
bool
{
return
strcmp
(
path_
.
data
(),
STACK
)
==
0
;
return
mem_region_
.
pathname
==
STACK
;
}
[[
nodiscard
]]
inline
auto
vdso
()
const
->
bool
{
return
strcmp
(
path_
.
data
(),
VDSO
)
==
0
;
return
mem_region_
.
pathname
==
VDSO
;
}
inline
friend
auto
operator
<<
(
std
::
ostream
&
os
,
const
mem_region_maps
&
m
)
->
std
::
ostream
&
{
os
<<
std
::
hex
<<
m
.
begin_
<<
'-'
<<
m
.
end_
<<
' '
<<
m
.
flags_
.
data
()
<<
' '
<<
m
.
offset_
<<
' '
<<
m
.
device_maj_
<<
':'
<<
m
.
device_min_
<<
' '
<<
std
::
dec
<<
m
.
inode_
<<
"
\t\t\t
"
<<
m
.
path_
.
data
();
inline
friend
auto
operator
<<
(
std
::
ostream
&
os
,
const
mem_region_maps
&
mem_region
)
->
std
::
ostream
&
{
const
auto
&
m
=
mem_region
.
mem_region_
;
const
auto
perm
=
std
::
string
(
1
,
m
.
perm
.
can_read
?
READ
:
NO_PERMISSION
)
+
std
::
string
(
1
,
m
.
perm
.
can_write
?
WRITE
:
NO_PERMISSION
)
+
std
::
string
(
1
,
m
.
perm
.
can_execute
?
EXECUTE
:
NO_PERMISSION
);
os
<<
std
::
hex
<<
m
.
start_address
<<
'-'
<<
m
.
end_address
<<
' '
<<
perm
<<
' '
<<
m
.
offset
<<
' '
<<
m
.
device
<<
' '
<<
std
::
dec
<<
m
.
inode
<<
"
\t\t\t
"
<<
m
.
pathname
;
return
os
;
}
...
...
src/system_info/memory/mem_region_numa_maps.hpp
View file @
1201c0fe
...
...
@@ -26,9 +26,6 @@
class
mem_region_numa_maps
{
protected:
static
constexpr
size_t
ADDRESS_POS
=
0
;
static
constexpr
size_t
POLICY_POS
=
1
;
static
constexpr
const
char
*
STACK_STR
=
"stack"
;
static
constexpr
const
char
*
HEAP_STR
=
"heap"
;
static
constexpr
const
char
*
HUGE_STR
=
"huge"
;
...
...
@@ -38,14 +35,14 @@ private:
pid_t
pid_
;
// PID of the process owning the memory page
// The first field of each line shows the starting address of the memory
// range.
This field allows a correlation with the contents of the
// range. This field allows a correlation with the contents of the
// /proc/<pid>/maps file, which contains the end address of the range
// and other information, such as the access permissions and sharing.
addr_t
address_
{};
// The second field shows the memory policy currently in effect for the
// memory range.
Note that the effective policy is not necessarily the
// policy installed by the process for that memory range.
Specifically,
// memory range. Note that the effective policy is not necessarily the
// policy installed by the process for that memory range. Specifically,
// if the process installed a "default" policy for that range, the
// effective policy for that range will be the process policy, which may
// or may not be "default".
...
...
@@ -55,16 +52,16 @@ private:
// The number of pages allocated on <node>. <nr_pages> includes
// only pages currently mapped by the process. Page migration
// and memory reclaim may have temporarily unmapped pages
// associated with this memory range.
These pages may show up
// associated with this memory range. These pages may show up
// again only after the process has attempted to reference them.
// If the memory range represents a shared memory area or file
// mapping, other processes may currently have additional pages
// mapped in a corresponding memory range.
std
::
vector
<
size_t
>
pages_per_node_
;
// The file backing the memory range.
If the file is mapped as
// The file backing the memory range. If the file is mapped as
// private, write accesses may have generated COW (Copy-On-Write)
// pages in this memory range.
These pages are displayed as
// pages in this memory range. These pages are displayed as
// anonymous pages.
std
::
string
file_
=
{};
...
...
src/system_info/memory/vmstat.hpp
View file @
1201c0fe
...
...
@@ -17,7 +17,9 @@
#include
"utils/types.hpp"
// for hres_clock, time_point
template
<
class
T
=
uint64_t
>
#include
"third_party_libs/pfs/include/pfs/procfs.hpp"
template
<
class
T
=
size_t
>
class
vmstat_t
{
public:
static
constexpr
const
char
*
VMSTAT_FILE
=
"/proc/vmstat"
;
...
...
@@ -187,23 +189,11 @@ public:
static
constexpr
const
char
*
vmacache_find_hits
=
"vmacache_find_hits"
;
static
constexpr
const
char
*
vmacache_full_flushes
=
"vmacache_full_flushes"
;
inline
auto
update
()
->
bool
{
std
::
ifstream
file
(
VMSTAT_FILE
);
if
(
!
file
.
good
())
{
return
false
;
}
auto
update
()
->
bool
{
param_val_map_
=
pfs
::
procfs
().
get_meminfo
();
last_update
=
hres_clock
::
now
();
while
(
file
.
good
())
{
std
::
string
param
;
T
value
;
file
>>
param
;
file
>>
value
;
param_val_map_
[
param
]
=
value
;
}
return
true
;
}
...
...
src/system_info/memory_info.hpp
View file @
1201c0fe
...
...
@@ -231,62 +231,48 @@ namespace memory_info {
[[
nodiscard
]]
auto
is_huge_page
(
const
addr_t
addr
,
const
pid_t
pid
)
->
bool
;
static
void
update_memory_regions
(
pid_t
pid
)
{
umap
<
addr_t
,
mem_region_maps
>
regions_maps
;
umap
<
addr_t
,
mem_region_numa_maps
>
regions_numa_maps
;
static
auto
memory_regions_maps
(
const
pid_t
pid
)
{
const
auto
maps
=
pfs
::
procfs
().
get_task
(
pid
).
get_maps
();
const
auto
maps_filename
=
"/proc/"
+
std
::
to_string
(
pid
)
+
"/
maps
"
;
map
<
addr_t
,
mem_region_maps
>
regions_
maps
;
std
::
ifstream
maps
(
maps_filename
);
if
(
!
maps
.
good
())
{
const
auto
error
=
"Cannot open file "
+
maps_filename
+
": "
+
strerror
(
errno
);
throw
std
::
runtime_error
(
error
);
for
(
const
auto
&
region
:
maps
)
{
regions_maps
.
emplace
(
region
.
start_address
,
mem_region_maps
(
pid
,
region
));
}
size_t
i
=
0
;
while
(
maps
.
good
())
{
std
::
string
line
;
std
::
getline
(
maps
,
line
);
mem_region_maps
region
(
line
,
i
,
pid
);
return
regions_maps
;
}
regions_maps
.
insert
(
std
::
make_pair
(
region
.
begin
(),
region
));
static
auto
memory_regions_numa_maps
(
const
pid_t
pid
)
{
map
<
addr_t
,
mem_region_numa_maps
>
regions_numa_maps
;
++
i
;
}
const
auto
file
=
"/proc/"
+
std
::
to_string
(
pid
)
+
"/numa_maps"
;
const
auto
numa_maps_filename
=
"/proc/"
+
std
::
to_string
(
pid
)
+
"/numa_maps"
;
std
::
ifstream
in
(
file
)
;
std
::
ifstream
numa_maps
(
numa_maps_filename
);
if
(
!
in
)
{
throw
std
::
runtime_error
(
"Cannot open file "
+
file
+
": "
+
strerror
(
errno
));
}
if
(
!
numa_maps
.
good
())
{
const
auto
error
=
"Cannot open file "
+
numa_maps_filename
+
": "
+
strerror
(
errno
);
throw
std
::
runtime_error
(
error
);
std
::
string
line
;
for
(
size_t
i
=
0
;
std
::
getline
(
in
,
line
);
++
i
)
{
const
mem_region_numa_maps
region
(
line
,
i
,
pid
);
regions_numa_maps
.
emplace
(
region
.
address
(),
region
);
}
i
=
0
;
while
(
numa_maps
.
good
())
{
std
::
string
line
;
std
::
getline
(
numa_maps
,
line
);
mem_region_numa_maps
region
(
line
,
i
,
pid
);
return
regions_numa_maps
;
}
regions_numa_maps
.
insert
(
std
::
make_pair
(
region
.
address
(),
region
));
static
void
update_memory_regions
(
const
pid_t
pid
)
{
const
auto
regions_maps
=
memory_regions_maps
(
pid
);
const
auto
regions_numa_maps
=
memory_regions_numa_maps
(
pid
);
++
i
;
}
for
(
const
auto
&
[
addr
,
region_maps
]
:
regions_maps
)
{
const
auto
&
it_region_numa_maps
=
regions_numa_maps
.
find
(
addr
);
for
(
auto
&
[
address
,
region_numa_maps
]
:
regions_numa_maps
)
{
const
auto
&
region_maps
=
regions_maps
.
find
(
address
);
if
(
it_region_numa_maps
==
regions_numa_maps
.
end
())
{
continue
;
}
if
(
region_maps
=
=
region
s_maps
.
end
())
{
continue
;
}
const
auto
&
region_
numa_
maps
=
it_
region
_numa_maps
->
second
;
details
::
memory_regions
.
insert
(
std
::
make_pair
(
addr
ess
,
mem_region
(
region_maps
->
second
,
region_numa_maps
))
);
details
::
memory_regions
.
emplace
(
addr
,
mem_region
{
region_maps
,
region_numa_maps
}
);
}
}
...
...
@@ -348,6 +334,7 @@ namespace memory_info {
template
<
template
<
typename
...
>
typename
Iterable
>
static
void
print_memory
(
const
Iterable
<
pid_t
>
&
pids
,
std
::
ostream
&
os
=
std
::
cout
)
{
update_vmstat
();
update_memory_regions
(
pids
);
os
<<
"NUMA hit: "
<<
details
::
vmstat
.
get_value
(
vmstat_t
<>::
numa_hit
)
<<
'\n'
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment