Skip to content

Commit 9068cc8

Browse files
committed
Merge branch 'ext-mmap-win' into ext-mmap
2 parents a61a079 + 4989269 commit 9068cc8

File tree

2 files changed

+57
-18
lines changed

2 files changed

+57
-18
lines changed

src/common/io.cc

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
#include <fcntl.h> // for open, O_RDONLY
66
#include <sys/mman.h> // for mmap, mmap64, munmap
77
#include <sys/stat.h>
8-
#include <unistd.h> // for close
8+
#include <unistd.h> // for close, getpagesize
9+
#elif defined(_MSC_VER)
10+
#include <windows.h>
911
#endif // defined(__unix__)
12+
1013
#include <algorithm>
1114
#include <cerrno> // for errno
1215
#include <cstdio>
@@ -171,33 +174,69 @@ std::size_t PadPageForMmap(std::size_t file_bytes, dmlc::Stream* fo) {
171174
return padded;
172175
}
173176

174-
void* PrivateMmapStream::Open(StringView path, bool read_only, std::size_t offset,
177+
struct PrivateMmapStream::MMAPFile {
178+
#if defined(_MSC_VER)
179+
HANDLE fd;
180+
#else
181+
std::int32_t fd;
182+
#endif
183+
std::string path;
184+
};
185+
186+
PrivateMmapStream::PrivateMmapStream(std::string path, bool read_only, std::size_t offset,
187+
std::size_t length)
188+
: MemoryFixSizeBuffer{Open(std::move(path), read_only, offset, length), length} {}
189+
190+
void* PrivateMmapStream::Open(std::string path, bool read_only, std::size_t offset,
175191
std::size_t length) {
176-
fd_ = open(path.c_str(), O_RDONLY);
177-
CHECK_GE(fd_, 0) << "Failed to open:" << path << ". " << strerror(errno);
192+
#if defined(_MSC_VER)
193+
HANDLE fd = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
194+
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
195+
CHECK_NE(fd, INVALID_HANDLE_VALUE) << "Failed to open:" << path;
196+
#else
197+
auto fd = open(path.c_str(), O_RDONLY);
198+
#endif
199+
CHECK_GE(fd, 0) << "Failed to open:" << path << ". " << strerror(errno);
200+
handle_ = std::make_unique<MMAPFile>(fd, std::move(path));
178201

179-
char* ptr{nullptr};
202+
void* ptr{nullptr};
203+
#if defined(__linux__) || defined(__GLIBC__)
180204
int prot{PROT_READ};
181205
if (!read_only) {
182206
prot |= PROT_WRITE;
183207
}
184-
#if defined(__linux__) || defined(__GLIBC__)
185-
ptr = reinterpret_cast<char*>(mmap64(nullptr, length, prot, MAP_PRIVATE, fd_, offset));
208+
ptr = reinterpret_cast<char*>(mmap64(nullptr, length, prot, MAP_PRIVATE, handle_->fd, offset));
209+
CHECK_NE(ptr, MAP_FAILED) << "Failed to map: " << handle_->path << ". " << strerror(errno);
186210
#elif defined(_MSC_VER)
187-
LOG(FATAL) << "External memory is not implemented for Windows.";
211+
auto file_size = GetFileSize(handle_->fd, nullptr);
212+
DWORD access = read_only ? PAGE_READONLY : PAGE_READWRITE;
213+
auto map_file = CreateFileMapping(handle_->fd, nullptr, access, 0, file_size, nullptr);
214+
access = read_only ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS;
215+
ptr = MapViewOfFile(map_file, access, 0, offset, length);
216+
CHECK_NE(ptr, nullptr) << "Failed to map: " << handle_->path << ". " << GetLastError();
188217
#else
189218
CHECK_LE(offset, std::numeric_limits<off_t>::max())
190219
<< "File size has exceeded the limit on the current system.";
220+
int prot{PROT_READ};
221+
if (!read_only) {
222+
prot |= PROT_WRITE;
223+
}
191224
ptr = reinterpret_cast<char*>(mmap(nullptr, length, prot, MAP_PRIVATE, fd_, offset));
225+
CHECK_NE(ptr, MAP_FAILED) << "Failed to map: " << handle_->path << ". " << strerror(errno);
192226
#endif // defined(__linux__)
193-
CHECK_NE(ptr, MAP_FAILED) << "Failed to map: " << path << ". " << strerror(errno);
194227
return ptr;
195228
}
196229

197230
PrivateMmapStream::~PrivateMmapStream() {
231+
CHECK(handle_);
232+
#if defined(_MSC_VER)
233+
CHECK(UnmapViewOfFile(p_buffer_)) "Faled to munmap." << handle_->path << ". " << GetLastError();
234+
CloseHandle(handle_->fd);
235+
#else
198236
CHECK_NE(munmap(p_buffer_, buffer_size_), -1)
199-
<< "Faled to munmap." << path_ << ". " << strerror(errno);
200-
CHECK_NE(close(fd_), -1) << "Faled to close: " << path_ << ". " << strerror(errno);
237+
<< "Faled to munmap." << handle_->path << ". " << strerror(errno);
238+
CHECK_NE(close(fd_), -1) << "Faled to close: " << handle_->path << ". " << strerror(errno);
239+
#endif
201240
}
202241
} // namespace common
203242
} // namespace xgboost

src/common/io.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010

1111
#include <dmlc/io.h>
1212
#include <rabit/rabit.h>
13-
#include <xgboost/string_view.h>
1413

1514
#include <cstring>
1615
#include <fstream>
1716
#include <string> // for string
17+
#include <utility> // for move
1818

1919
#include "common.h"
2020

@@ -129,6 +129,7 @@ inline std::string ReadAll(std::string const &path) {
129129
return content;
130130
}
131131

132+
std::size_t GetPageSize();
132133
/**
133134
* @brief Pad the output file for a page to make it mmap compatible.
134135
*
@@ -143,10 +144,11 @@ std::size_t PadPageForMmap(std::size_t file_bytes, dmlc::Stream* fo);
143144
* @brief Private mmap file, copy-on-write. File must be properly aligned by `PadPageForMmap()`.
144145
*/
145146
class PrivateMmapStream : public MemoryFixSizeBuffer {
146-
std::int32_t fd_;
147-
std::string path_;
147+
struct MMAPFile;
148148

149-
void* Open(StringView path, bool read_only, std::size_t offset, std::size_t length);
149+
std::unique_ptr<MMAPFile> handle_;
150+
151+
void* Open(std::string path, bool read_only, std::size_t offset, std::size_t length);
150152

151153
public:
152154
/**
@@ -158,9 +160,7 @@ class PrivateMmapStream : public MemoryFixSizeBuffer {
158160
* @param length See the `length` parameter of `mmap` for details.
159161
*/
160162
explicit PrivateMmapStream(std::string path, bool read_only, std::size_t offset,
161-
std::size_t length)
162-
: MemoryFixSizeBuffer{Open(StringView{path}, read_only, offset, length), length},
163-
path_{path} {}
163+
std::size_t length);
164164

165165
~PrivateMmapStream() override;
166166
};

0 commit comments

Comments
 (0)