Skip to content

Commit a6e2a7c

Browse files
committed
common: MemoryModel: keep /proc files open
Allowing clients to hold on to the MemoryModel object for multiple "snapshots", saving (per measurements) ~40% of the sampling run time. Also: separating the parsing of /proc/maps (which consumes most of the remaining execution time) into a separate function. This will allow us to create a "no need for precise heap" fast mode (in a future commit). Signed-off-by: Ronen Friedman <[email protected]>
1 parent e972233 commit a6e2a7c

File tree

2 files changed

+59
-39
lines changed

2 files changed

+59
-39
lines changed

src/common/MemoryModel.cc

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
#include <malloc.h>
66
#endif
77

8-
#include <fstream>
8+
#include <charconv>
9+
10+
#include "common/fmt_common.h"
11+
912

1013
#define dout_subsys ceph_subsys_
1114

@@ -17,45 +20,21 @@ MemoryModel::MemoryModel(CephContext *cct_)
1720
{
1821
}
1922

20-
void MemoryModel::_sample(mem_snap_t *psnap)
23+
std::optional<int64_t> MemoryModel::get_mapped_heap()
2124
{
22-
ifstream f;
23-
24-
f.open(PROCPREFIX "/proc/self/status");
25-
if (!f.is_open()) {
26-
ldout(cct, 0) << "check_memory_usage unable to open " PROCPREFIX "/proc/self/status" << dendl;
27-
return;
25+
if (!proc_maps.is_open()) {
26+
ldout(cct, 0) << fmt::format("MemoryModel::get_mapped_heap() unable to open {}", proc_maps_fn) << dendl;
27+
return std::nullopt;
2828
}
29-
while (!f.eof()) {
30-
string line;
31-
getline(f, line);
32-
33-
if (strncmp(line.c_str(), "VmSize:", 7) == 0)
34-
psnap->size = atol(line.c_str() + 7);
35-
else if (strncmp(line.c_str(), "VmRSS:", 6) == 0)
36-
psnap->rss = atol(line.c_str() + 7);
37-
else if (strncmp(line.c_str(), "VmHWM:", 6) == 0)
38-
psnap->hwm = atol(line.c_str() + 7);
39-
else if (strncmp(line.c_str(), "VmLib:", 6) == 0)
40-
psnap->lib = atol(line.c_str() + 7);
41-
else if (strncmp(line.c_str(), "VmPeak:", 7) == 0)
42-
psnap->peak = atol(line.c_str() + 7);
43-
else if (strncmp(line.c_str(), "VmData:", 7) == 0)
44-
psnap->data = atol(line.c_str() + 7);
45-
}
46-
f.close();
29+
// always rewind before reading
30+
proc_maps.clear();
31+
proc_maps.seekg(0);
4732

48-
f.open(PROCPREFIX "/proc/self/maps");
49-
if (!f.is_open()) {
50-
ldout(cct, 0) << "check_memory_usage unable to open " PROCPREFIX "/proc/self/maps" << dendl;
51-
return;
52-
}
33+
int64_t heap = 0;
5334

54-
long heap = 0;
55-
while (f.is_open() && !f.eof()) {
35+
while (proc_maps.is_open() && !proc_maps.eof()) {
5636
string line;
57-
getline(f, line);
58-
//ldout(cct, 0) << "line is " << line << dendl;
37+
getline(proc_maps, line);
5938

6039
const char *start = line.c_str();
6140
const char *dash = start;
@@ -69,8 +48,6 @@ void MemoryModel::_sample(mem_snap_t *psnap)
6948
unsigned long long as = strtoll(start, 0, 16);
7049
unsigned long long ae = strtoll(dash+1, 0, 16);
7150

72-
//ldout(cct, 0) << std::hex << as << " to " << ae << std::dec << dendl;
73-
7451
end++;
7552
const char *mode = end;
7653

@@ -83,7 +60,6 @@ void MemoryModel::_sample(mem_snap_t *psnap)
8360
end++;
8461

8562
long size = ae - as;
86-
//ldout(cct, 0) << "size " << size << " mode is '" << mode << "' end is '" << end << "'" << dendl;
8763

8864
/*
8965
* anything 'rw' and anon is assumed to be heap.
@@ -92,6 +68,39 @@ void MemoryModel::_sample(mem_snap_t *psnap)
9268
heap += size;
9369
}
9470

95-
psnap->heap = heap >> 10;
71+
return heap;
72+
}
73+
74+
75+
76+
void MemoryModel::_sample(mem_snap_t *psnap)
77+
{
78+
if (!proc_status.is_open()) {
79+
ldout(cct, 0) << fmt::format("MemoryModel::sample() unable to open {}", proc_stat_fn) << dendl;
80+
return;
81+
}
82+
// always rewind before reading
83+
proc_status.clear();
84+
proc_status.seekg(0);
85+
86+
while (!proc_status.eof()) {
87+
string line;
88+
getline(proc_status, line);
89+
90+
if (strncmp(line.c_str(), "VmSize:", 7) == 0)
91+
psnap->size = atol(line.c_str() + 7);
92+
else if (strncmp(line.c_str(), "VmRSS:", 6) == 0)
93+
psnap->rss = atol(line.c_str() + 7);
94+
else if (strncmp(line.c_str(), "VmHWM:", 6) == 0)
95+
psnap->hwm = atol(line.c_str() + 7);
96+
else if (strncmp(line.c_str(), "VmLib:", 6) == 0)
97+
psnap->lib = atol(line.c_str() + 7);
98+
else if (strncmp(line.c_str(), "VmPeak:", 7) == 0)
99+
psnap->peak = atol(line.c_str() + 7);
100+
else if (strncmp(line.c_str(), "VmData:", 7) == 0)
101+
psnap->data = atol(line.c_str() + 7);
102+
}
96103

104+
// get heap size
105+
psnap->heap = static_cast<long>(get_mapped_heap().value_or(0));
97106
}

src/common/MemoryModel.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
#ifndef CEPH_MEMORYMODEL_H
1616
#define CEPH_MEMORYMODEL_H
1717

18+
#include <fstream>
19+
#include <optional>
1820
#include "include/common_fwd.h"
21+
#include "include/compat.h"
22+
1923

2024
class MemoryModel {
2125
public:
@@ -39,8 +43,15 @@ class MemoryModel {
3943
} last;
4044

4145
private:
46+
static inline constexpr const char* proc_stat_fn = PROCPREFIX "/proc/self/status";
47+
static inline constexpr const char* proc_maps_fn = PROCPREFIX "/proc/self/maps";
48+
49+
std::ifstream proc_status{proc_stat_fn};
50+
std::ifstream proc_maps{proc_maps_fn};
51+
4252
CephContext *cct;
4353
void _sample(mem_snap_t *p);
54+
std::optional<int64_t> get_mapped_heap();
4455

4556
public:
4657
explicit MemoryModel(CephContext *cct);

0 commit comments

Comments
 (0)