mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-29 04:35:36 +08:00
Support experimental re-mmap wrappers
Summary: Add experimental support for reordering the pages of a file that is mmap:ed by JSBigFileString. The wrapper is auto-detected (by checking file size and magic header) and transparently reorders the pages. Reviewed By: ridiculousfish Differential Revision: D14721397 fbshipit-source-id: 34e095350a9eeb9b07105bed6f3379f2fe472ae6
This commit is contained in:
committed by
Facebook Github Bot
parent
7944d47a63
commit
407dca8cf0
@@ -44,6 +44,9 @@ rn_xplat_cxx_library(
|
|||||||
],
|
],
|
||||||
fbobjc_compiler_flags = get_apple_compiler_flags(),
|
fbobjc_compiler_flags = get_apple_compiler_flags(),
|
||||||
force_static = True,
|
force_static = True,
|
||||||
|
preprocessor_flags = [
|
||||||
|
"-DWITH_FBREMAP=1",
|
||||||
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -48,6 +48,65 @@ JSBigFileString::~JSBigFileString() {
|
|||||||
close(m_fd);
|
close(m_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_FBREMAP
|
||||||
|
// Read and advance the pointer.
|
||||||
|
static uint16_t read16(char *&data) {
|
||||||
|
uint16_t result;
|
||||||
|
::memcpy(&result, data, sizeof(result));
|
||||||
|
data += sizeof(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the given file has a remapping table header, remap its pages accordingly
|
||||||
|
// and return the byte offset from the beginning to the unwrapped payload.
|
||||||
|
static off_t maybeRemap(char *data, size_t size, int fd) {
|
||||||
|
// A remapped file's size must be a multiple of its page size, so quickly
|
||||||
|
// filter out files with incorrect size, without touching any pages.
|
||||||
|
static const size_t kMinPageSize = 4096;
|
||||||
|
if (size < kMinPageSize || size % kMinPageSize != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto begin = data;
|
||||||
|
static const uint8_t kRemapMagic[] = {
|
||||||
|
0xc6, 0x1f, 0xbc, 0x03, 0xc1, 0x03, 0x19, 0x1f, 0xa1, 0xd0, 0xeb, 0x73
|
||||||
|
};
|
||||||
|
if (::memcmp(data, kRemapMagic, sizeof(kRemapMagic)) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
data += sizeof(kRemapMagic);
|
||||||
|
const size_t filePS = static_cast<size_t>(1) << read16(data);
|
||||||
|
if (size & (filePS - 1)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// System page size must be at least as granular as the remapping.
|
||||||
|
// TODO: Consider fallback that reads entire file into memory.
|
||||||
|
const size_t systemPS = getpagesize();
|
||||||
|
CHECK(filePS >= systemPS)
|
||||||
|
<< "filePS: " << filePS
|
||||||
|
<< "systemPS: " << systemPS;
|
||||||
|
}
|
||||||
|
const off_t headerPages = read16(data);
|
||||||
|
uint16_t numMappings = read16(data);
|
||||||
|
size_t curFilePage = headerPages;
|
||||||
|
while (numMappings--) {
|
||||||
|
auto memPage = read16(data) + headerPages;
|
||||||
|
auto numPages = read16(data);
|
||||||
|
if (mmap(begin + memPage * filePS, numPages * filePS,
|
||||||
|
PROT_READ, MAP_FILE | MAP_PRIVATE | MAP_FIXED,
|
||||||
|
fd, curFilePage * filePS) == MAP_FAILED) {
|
||||||
|
CHECK(false)
|
||||||
|
<< " memPage: " << memPage
|
||||||
|
<< " numPages: " << numPages
|
||||||
|
<< " curFilePage: " << curFilePage
|
||||||
|
<< " size: " << size
|
||||||
|
<< " error: " << std::strerror(errno);
|
||||||
|
}
|
||||||
|
curFilePage += numPages;
|
||||||
|
}
|
||||||
|
return headerPages * filePS;
|
||||||
|
}
|
||||||
|
#endif // WITH_FBREMAP
|
||||||
|
|
||||||
const char *JSBigFileString::c_str() const {
|
const char *JSBigFileString::c_str() const {
|
||||||
if (!m_data) {
|
if (!m_data) {
|
||||||
@@ -58,11 +117,19 @@ const char *JSBigFileString::c_str() const {
|
|||||||
<< " size: " << m_size
|
<< " size: " << m_size
|
||||||
<< " offset: " << m_mapOff
|
<< " offset: " << m_mapOff
|
||||||
<< " error: " << std::strerror(errno);
|
<< " error: " << std::strerror(errno);
|
||||||
|
#ifdef WITH_FBREMAP
|
||||||
|
// Remapping is only attempted when the entire file was requested.
|
||||||
|
if (m_mapOff == 0 && m_pageOff == 0) {
|
||||||
|
m_pageOff = maybeRemap(const_cast<char *>(m_data), m_size, m_fd);
|
||||||
|
}
|
||||||
|
#endif // WITH_FBREMAP
|
||||||
}
|
}
|
||||||
return m_data + m_pageOff;
|
return m_data + m_pageOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JSBigFileString::size() const {
|
size_t JSBigFileString::size() const {
|
||||||
|
// Ensure mapping has been initialized.
|
||||||
|
c_str();
|
||||||
return m_size - m_pageOff;
|
return m_size - m_pageOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
int m_fd; // The file descriptor being mmaped
|
int m_fd; // The file descriptor being mmaped
|
||||||
size_t m_size; // The size of the mmaped region
|
size_t m_size; // The size of the mmaped region
|
||||||
off_t m_pageOff; // The offset in the mmaped region to the data.
|
mutable off_t m_pageOff; // The offset in the mmaped region to the data.
|
||||||
off_t m_mapOff; // The offset in the file to the mmaped region.
|
off_t m_mapOff; // The offset in the file to the mmaped region.
|
||||||
mutable const char *m_data; // Pointer to the mmaped region.
|
mutable const char *m_data; // Pointer to the mmaped region.
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,3 +60,46 @@ TEST(JSBigFileString, MapPartTest) {
|
|||||||
ASSERT_EQ(needle[i], bigStr.c_str()[i]);
|
ASSERT_EQ(needle[i], bigStr.c_str()[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(JSBigFileString, RemapTest) {
|
||||||
|
static const uint8_t kRemapMagic[] = {
|
||||||
|
0xc6, 0x1f, 0xbc, 0x03, 0xc1, 0x03, 0x19, 0x1f, 0xa1, 0xd0, 0xeb, 0x73
|
||||||
|
};
|
||||||
|
std::string data(std::begin(kRemapMagic), std::end(kRemapMagic));
|
||||||
|
auto app = [&data](uint16_t v) {
|
||||||
|
data.append(reinterpret_cast<char *>(&v), sizeof(v));
|
||||||
|
};
|
||||||
|
size_t pageSizeLog2 = 16;
|
||||||
|
app(pageSizeLog2);
|
||||||
|
size_t pageSize = 1 << pageSizeLog2;
|
||||||
|
app(1); // header pages
|
||||||
|
app(2); // num mappings
|
||||||
|
// file page 0 -> memory page 1
|
||||||
|
app(1); // memory page
|
||||||
|
app(1); // num pages
|
||||||
|
// file page 1 -> memory page 0
|
||||||
|
app(0); // memory page
|
||||||
|
app(1); // num pages
|
||||||
|
while (data.size() < pageSize) {
|
||||||
|
app(0);
|
||||||
|
}
|
||||||
|
while (data.size() < pageSize * 2) {
|
||||||
|
app(0x1111);
|
||||||
|
}
|
||||||
|
while (data.size() < pageSize * 3) {
|
||||||
|
app(0x2222);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = tempFileFromString(data);
|
||||||
|
JSBigFileString bigStr {fd, data.size()};
|
||||||
|
|
||||||
|
ASSERT_EQ(pageSize * 2, bigStr.size());
|
||||||
|
auto remapped = bigStr.c_str();
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < pageSize; ++i) {
|
||||||
|
ASSERT_EQ(0x22, remapped[i]);
|
||||||
|
}
|
||||||
|
for (; i < pageSize * 2; ++i) {
|
||||||
|
ASSERT_EQ(0x11, remapped[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user