proxygen
MemoryMappingTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cstdlib>
18 
19 #include <folly/FileUtil.h>
20 #include <folly/Random.h>
24 
25 static constexpr double kSomeDouble = 3.14;
26 
27 namespace folly {
28 
31  {
32  MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
33  double* d = m.asWritableRange<double>().data();
34  *d = 37 * kSomeDouble;
35  }
36  {
37  MemoryMapping m(File(f.fd()), 0, 3);
38  EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
39  }
40  {
41  MemoryMapping m(File(f.fd()), 0, sizeof(double));
42  const double* d = m.asRange<double>().data();
43  EXPECT_EQ(*d, 37 * kSomeDouble);
44  }
45 }
46 
49  {
51  File(f.fd()), 0, sizeof(double) * 2, MemoryMapping::writable());
52  double* d = m.asWritableRange<double>().data();
53  d[0] = 37 * kSomeDouble;
55  double* d2 = m2.asWritableRange<double>().data();
56  d2[1] = 39 * kSomeDouble;
57  }
58  {
59  MemoryMapping m(File(f.fd()), 0, sizeof(double));
60  const double* d = m.asRange<double>().data();
61  EXPECT_EQ(d[0], 37 * kSomeDouble);
63  const double* d2 = m2.asRange<double>().data();
64  EXPECT_EQ(d2[1], 39 * kSomeDouble);
65  }
66 }
67 
68 TEST(MemoryMapping, DoublyMapped) {
70  // two mappings of the same memory, different addresses.
71  MemoryMapping mw(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
72  MemoryMapping mr(File(f.fd()), 0, sizeof(double));
73 
74  double* dw = mw.asWritableRange<double>().data();
75  const double* dr = mr.asRange<double>().data();
76 
77  // Show that it's truly the same value, even though the pointers differ
78  EXPECT_NE(dw, dr);
79  *dw = 42 * kSomeDouble;
80  EXPECT_EQ(*dr, 42 * kSomeDouble);
81  *dw = 43 * kSomeDouble;
82  EXPECT_EQ(*dr, 43 * kSomeDouble);
83 }
84 
85 namespace {
86 
87 void writeStringToFileOrDie(const std::string& str, int fd) {
88  const char* b = str.c_str();
89  size_t count = str.size();
90  ssize_t total_bytes = 0;
91  ssize_t r;
92  do {
93  r = write(fd, b, count);
94  if (r == -1) {
95  if (errno == EINTR) {
96  continue;
97  }
98  PCHECK(r) << "write";
99  }
100 
101  total_bytes += r;
102  b += r;
103  count -= r;
104  } while (r != 0 && count);
105 }
106 
107 } // namespace
108 
109 TEST(MemoryMapping, Simple) {
110  File f = File::temporary();
111  writeStringToFileOrDie("hello", f.fd());
112 
113  {
114  MemoryMapping m(File(f.fd()));
115  EXPECT_EQ("hello", m.data());
116  }
117  {
118  MemoryMapping m(File(f.fd()), 1, 2);
119  EXPECT_EQ("el", m.data());
120  }
121 }
122 
123 TEST(MemoryMapping, LargeFile) {
124  std::string fileData;
125  size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
126  fileData.reserve(fileSize);
127  for (size_t i = 0; i < fileSize; i++) {
128  fileData.push_back(0xff & Random::rand32());
129  }
130 
131  File f = File::temporary();
132  writeStringToFileOrDie(fileData, f.fd());
133 
134  {
135  MemoryMapping m(File(f.fd()));
136  EXPECT_EQ(fileData, m.data());
137  }
138  {
139  size_t size = sysconf(_SC_PAGESIZE) * 2;
140  StringPiece s(fileData.data() + 9, size - 9);
141  MemoryMapping m(File(f.fd()), 9, size - 9);
142  EXPECT_EQ(s.toString(), m.data());
143  }
144 }
145 
146 TEST(MemoryMapping, ZeroLength) {
147  File f = File::temporary();
148  MemoryMapping m(File(f.fd()));
150  EXPECT_TRUE(m.mlocked());
151  EXPECT_EQ(0, m.data().size());
152 }
153 
154 TEST(MemoryMapping, Advise) {
155  File f = File::temporary();
156  size_t kPageSize = 4096;
157  size_t size = kPageSize + 10; // unaligned file size
158  PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
159 
160  MemoryMapping m(File(f.fd()));
161 
162  // NOTE: advise crashes on bad input.
163 
164  m.advise(MADV_NORMAL, 0, kPageSize);
165  m.advise(MADV_NORMAL, 1, kPageSize);
166  m.advise(MADV_NORMAL, 0, 2);
167  m.advise(MADV_NORMAL, 1, 2);
168 
169  m.advise(MADV_NORMAL, kPageSize, 0);
170  m.advise(MADV_NORMAL, kPageSize, 1);
171  m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
172 
173  auto off = kPageSize + 1;
174  m.advise(MADV_NORMAL, off, size - off);
175 
176  EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
177 }
178 
179 } // namespace folly
auto f
void write(const T &in, folly::io::Appender &appender)
Definition: Types-inl.h:112
char b
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
constexpr size_type size() const
Definition: Range.h:431
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
bool mlock(LockMode lock)
static constexpr double kSomeDouble
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
int fd() const
Definition: File.h:85
Range< T * > asWritableRange() const
constexpr auto data(C &c) -> decltype(c.data())
Definition: Access.h:71
void advise(int advice) const
static map< string, int > m
static Options writable()
const size_t kPageSize
Definition: RangeTest.cpp:1000
Range< const T * > asRange() const
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
bool mlocked() const
const char * string
Definition: Conv.cpp:212
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static set< string > s
int ftruncateNoInt(int fd, off_t len)
Definition: FileUtil.cpp:86
static File temporary()
Definition: File.cpp:75
static uint32_t rand32()
Definition: Random.h:213
StringPiece data() const
TEST(SequencedExecutor, CPUThreadPoolExecutor)