Skip to content

Commit 3d12b1b

Browse files
committed
Merge pull request mongodb#324 from utaal/blockInMemory-pagesInMemory
SERVER-7570 changed ProcessInfo::blockInMemory to leverage getPageSize, added pagesInMemory
2 parents 3551c2e + fe38a5e commit 3d12b1b

File tree

8 files changed

+132
-30
lines changed

8 files changed

+132
-30
lines changed

src/mongo/db/record.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ namespace mongo {
461461
if (seen || ps::rolling[ps::bigHash(region)].access( region , offset , false ) ) {
462462

463463
#ifdef _DEBUG
464-
if ( blockSupported && ! ProcessInfo::blockInMemory( const_cast<char*>(data) ) ) {
464+
if ( blockSupported && ! ProcessInfo::blockInMemory(data) ) {
465465
warning() << "we think data is in ram but system says no" << endl;
466466
}
467467
#endif

src/mongo/util/processinfo.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,27 @@ namespace mongo {
107107

108108
static bool blockCheckSupported();
109109

110-
static bool blockInMemory( char * start );
110+
static bool blockInMemory(const void* start);
111+
112+
/**
113+
* @return a pointer aligned to the start of the page the provided pointer belongs to.
114+
*
115+
* NOTE requires blockCheckSupported() == true
116+
*/
117+
inline static const void* alignToStartOfPage(const void* ptr) {
118+
return reinterpret_cast<const void*>(
119+
reinterpret_cast<unsigned long long>(ptr) & ~(getPageSize() - 1));
120+
}
121+
122+
/**
123+
* Sets i-th element of 'out' to non-zero if the i-th page starting from the one containing
124+
* 'start' is in memory.
125+
* The 'out' vector will be resized to fit the requested number of pages.
126+
* @return true on success, false otherwise
127+
*
128+
* NOTE: requires blockCheckSupported() == true
129+
*/
130+
static bool pagesInMemory(const void* start, size_t numPages, vector<char>* out);
111131

112132
private:
113133
/**

src/mongo/util/processinfo_darwin.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,18 +185,25 @@ namespace mongo {
185185
return true;
186186
}
187187

188-
bool ProcessInfo::blockInMemory( char * start ) {
189-
static long pageSize = 0;
190-
if ( pageSize == 0 ) {
191-
pageSize = sysconf( _SC_PAGESIZE );
192-
}
193-
start = start - ( (unsigned long long)start % pageSize );
188+
bool ProcessInfo::blockInMemory(const void* start) {
194189
char x = 0;
195-
if ( mincore( start , 128 , &x ) ) {
190+
if (mincore(alignToStartOfPage(start), getPageSize(), &x)) {
196191
log() << "mincore failed: " << errnoWithDescription() << endl;
197192
return 1;
198193
}
199194
return x & 0x1;
200195
}
201196

197+
bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
198+
out->resize(numPages);
199+
if (mincore(alignToStartOfPage(start), numPages * getPageSize(), &out->front())) {
200+
log() << "mincore failed: " << errnoWithDescription() << endl;
201+
return false;
202+
}
203+
for (size_t i = 0; i < numPages; ++i) {
204+
(*out)[i] &= 0x1;
205+
}
206+
return true;
207+
}
208+
202209
}

src/mongo/util/processinfo_freebsd.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ namespace mongo {
3838
ProcessInfo::~ProcessInfo() {
3939
}
4040

41-
static const uintptr_t pageSizeBytes = sysconf(_SC_PAGESIZE);
42-
4341
/**
4442
* Get a sysctl string value by name. Use string specialization by default.
4543
*/
@@ -152,19 +150,26 @@ namespace mongo {
152150
return true;
153151
}
154152

155-
inline char* getPageAddress(char* addr) {
156-
return reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(addr) & ~(pageSizeBytes - 1));
157-
}
158-
159-
bool ProcessInfo::blockInMemory( char * start ) {
160-
start = getPageAddress(start);
161-
153+
bool ProcessInfo::blockInMemory(const void* start) {
162154
char x = 0;
163-
if ( mincore( start , 128 , &x ) ) {
155+
if (mincore(alignToStartOfPage(start), getPageSize(), &x)) {
164156
log() << "mincore failed: " << errnoWithDescription() << endl;
165157
return 1;
166158
}
167159
return x & 0x1;
168160
}
169161

162+
bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
163+
out->resize(numPages);
164+
// int mincore(const void *addr, size_t len, char *vec);
165+
if (mincore(alignToStartOfPage(start), numPages * getPageSize(),
166+
&(out->front()))) {
167+
log() << "mincore failed: " << errnoWithDescription() << endl;
168+
return false;
169+
}
170+
for (size_t i = 0; i < numPages; ++i) {
171+
(*out)[i] = 0x1;
172+
}
173+
return true;
174+
}
170175
}

src/mongo/util/processinfo_linux2.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -451,19 +451,26 @@ namespace mongo {
451451
return true;
452452
}
453453

454-
bool ProcessInfo::blockInMemory( char * start ) {
455-
static long pageSize = 0;
456-
if ( pageSize == 0 ) {
457-
pageSize = sysconf( _SC_PAGESIZE );
458-
}
459-
start = start - ( (unsigned long long)start % pageSize );
454+
bool ProcessInfo::blockInMemory(const void* start) {
460455
unsigned char x = 0;
461-
if ( mincore( start , 128 , &x ) ) {
456+
if (mincore(const_cast<void*>(alignToStartOfPage(start)), getPageSize(), &x)) {
462457
log() << "mincore failed: " << errnoWithDescription() << endl;
463458
return 1;
464459
}
465460
return x & 0x1;
466461
}
467462

463+
bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
464+
out->resize(numPages);
465+
if (mincore(const_cast<void*>(alignToStartOfPage(start)), numPages * getPageSize(),
466+
reinterpret_cast<unsigned char*>(&out->front()))) {
467+
log() << "mincore failed: " << errnoWithDescription() << endl;
468+
return false;
469+
}
470+
for (size_t i = 0; i < numPages; ++i) {
471+
(*out)[i] &= 0x1;
472+
}
473+
return true;
474+
}
468475

469476
}

src/mongo/util/processinfo_none.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,12 @@ namespace mongo {
5757

5858
}
5959

60-
bool ProcessInfo::blockInMemory( char * start ) {
60+
bool ProcessInfo::blockInMemory(const void* start) {
61+
verify(0);
62+
}
63+
64+
bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<bool>* out) {
6165
verify(0);
62-
return true;
6366
}
6467

6568
}

src/mongo/util/processinfo_test.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
*/
1616

17+
#include <vector>
18+
19+
#include "boost/scoped_array.hpp"
20+
1721
#include "mongo/unittest/unittest.h"
1822
#include "mongo/util/processinfo.h"
1923

@@ -26,4 +30,38 @@ namespace mongo_test {
2630
ASSERT_FALSE(processInfo.getOsType().empty());
2731
}
2832
}
33+
34+
TEST(ProcessInfo, NonZeroPageSize) {
35+
if (ProcessInfo::blockCheckSupported()) {
36+
ASSERT_GREATER_THAN(ProcessInfo::getPageSize(), 0u);
37+
}
38+
}
39+
40+
const size_t PAGES = 10;
41+
42+
TEST(ProcessInfo, BlockInMemoryDoesNotThrowIfSupported) {
43+
if (ProcessInfo::blockCheckSupported()) {
44+
boost::scoped_array<char> ptr(new char[ProcessInfo::getPageSize() * PAGES]);
45+
ProcessInfo::blockInMemory(ptr.get() + ProcessInfo::getPageSize() * 2);
46+
}
47+
}
48+
49+
TEST(ProcessInfo, PagesInMemoryIsSensible) {
50+
if (ProcessInfo::blockCheckSupported()) {
51+
static volatile char ptr[4096 * PAGES];
52+
ptr[1] = 'a';
53+
std::vector<char> result;
54+
ASSERT_TRUE(ProcessInfo::pagesInMemory(const_cast<char*>(ptr), PAGES, &result));
55+
ASSERT_TRUE(result[0]);
56+
ASSERT_FALSE(result[1]);
57+
ASSERT_FALSE(result[2]);
58+
ASSERT_FALSE(result[3]);
59+
ASSERT_FALSE(result[4]);
60+
ASSERT_FALSE(result[5]);
61+
ASSERT_FALSE(result[6]);
62+
ASSERT_FALSE(result[7]);
63+
ASSERT_FALSE(result[8]);
64+
ASSERT_FALSE(result[9]);
65+
}
66+
}
2967
}

src/mongo/util/processinfo_win32.cpp

100755100644
Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ namespace mongo {
200200
return psapiGlobal.supported;
201201
}
202202

203-
bool ProcessInfo::blockInMemory( char * start ) {
203+
bool ProcessInfo::blockInMemory(const void* start) {
204204
#if 0
205205
// code for printing out page fault addresses and pc's --
206206
// this could be useful for targetting heavy pagefault locations in the code
@@ -216,12 +216,34 @@ namespace mongo {
216216
}
217217
#endif
218218
PSAPI_WORKING_SET_EX_INFORMATION wsinfo;
219-
wsinfo.VirtualAddress = start;
219+
wsinfo.VirtualAddress = const_cast<void*>(start);
220220
BOOL result = psapiGlobal.QueryWSEx( GetCurrentProcess(), &wsinfo, sizeof(wsinfo) );
221221
if ( result )
222222
if ( wsinfo.VirtualAttributes.Valid )
223223
return true;
224224
return false;
225225
}
226226

227+
bool ProcessInfo::pagesInMemory(const void* start, size_t numPages, vector<char>* out) {
228+
out->resize(numPages);
229+
scoped_array<PSAPI_WORKING_SET_EX_INFORMATION> wsinfo(
230+
new PSAPI_WORKING_SET_EX_INFORMATION[numPages]);
231+
232+
const void* startOfFirstPage = alignToStartOfPage(start);
233+
for (size_t i = 0; i < numPages; i++) {
234+
wsinfo[i].VirtualAddress = reinterpret_cast<void*>(
235+
reinterpret_cast<unsigned long long>(startOfFirstPage) + i * getPageSize());
236+
}
237+
238+
BOOL result = psapiGlobal.QueryWSEx(GetCurrentProcess(),
239+
wsinfo.get(),
240+
sizeof(PSAPI_WORKING_SET_EX_INFORMATION) * numPages);
241+
242+
if (!result) return false;
243+
for (size_t i = 0; i < numPages; ++i) {
244+
(*out)[i] = wsinfo[i].VirtualAttributes.Valid ? 1 : 0;
245+
}
246+
return true;
247+
}
248+
227249
}

0 commit comments

Comments
 (0)