1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
11 #include "rocksdb/env.h"
12 #include "test_util/testharness.h"
13 #include "test_util/testutil.h"
14 #include "util/autovector.h"
15 #include "util/string_util.h"
20 namespace ROCKSDB_NAMESPACE
{
22 class AutoVectorTest
: public testing::Test
{};
23 const unsigned long kSize
= 8;
27 void AssertAutoVectorOnlyInStack(autovector
<T
, kSize
>* vec
, bool result
) {
29 ASSERT_EQ(vec
->only_in_stack(), result
);
33 #endif // !ROCKSDB_LITE
37 TEST_F(AutoVectorTest
, PushBackAndPopBack
) {
38 autovector
<size_t, kSize
> vec
;
39 ASSERT_TRUE(vec
.empty());
40 ASSERT_EQ(0ul, vec
.size());
42 for (size_t i
= 0; i
< 1000 * kSize
; ++i
) {
44 ASSERT_TRUE(!vec
.empty());
46 AssertAutoVectorOnlyInStack(&vec
, true);
48 AssertAutoVectorOnlyInStack(&vec
, false);
50 ASSERT_EQ(i
+ 1, vec
.size());
52 ASSERT_EQ(i
, vec
.at(i
));
55 size_t size
= vec
.size();
58 // will always be in heap
59 AssertAutoVectorOnlyInStack(&vec
, false);
60 ASSERT_EQ(--size
, vec
.size());
63 ASSERT_TRUE(vec
.empty());
66 TEST_F(AutoVectorTest
, EmplaceBack
) {
67 typedef std::pair
<size_t, std::string
> ValType
;
68 autovector
<ValType
, kSize
> vec
;
70 for (size_t i
= 0; i
< 1000 * kSize
; ++i
) {
71 vec
.emplace_back(i
, ToString(i
+ 123));
72 ASSERT_TRUE(!vec
.empty());
74 AssertAutoVectorOnlyInStack(&vec
, true);
76 AssertAutoVectorOnlyInStack(&vec
, false);
79 ASSERT_EQ(i
+ 1, vec
.size());
80 ASSERT_EQ(i
, vec
[i
].first
);
81 ASSERT_EQ(ToString(i
+ 123), vec
[i
].second
);
85 ASSERT_TRUE(vec
.empty());
86 AssertAutoVectorOnlyInStack(&vec
, false);
89 TEST_F(AutoVectorTest
, Resize
) {
90 autovector
<size_t, kSize
> vec
;
93 AssertAutoVectorOnlyInStack(&vec
, true);
94 for (size_t i
= 0; i
< kSize
; ++i
) {
98 vec
.resize(kSize
* 2);
99 AssertAutoVectorOnlyInStack(&vec
, false);
100 for (size_t i
= 0; i
< kSize
; ++i
) {
101 ASSERT_EQ(vec
[i
], i
);
103 for (size_t i
= 0; i
< kSize
; ++i
) {
108 ASSERT_EQ(1U, vec
.size());
113 const autovector
<size_t, kSize
>& a
, const autovector
<size_t, kSize
>& b
) {
114 ASSERT_EQ(a
.size(), b
.size());
115 ASSERT_EQ(a
.empty(), b
.empty());
117 ASSERT_EQ(a
.only_in_stack(), b
.only_in_stack());
118 #endif // !ROCKSDB_LITE
119 for (size_t i
= 0; i
< a
.size(); ++i
) {
120 ASSERT_EQ(a
[i
], b
[i
]);
125 TEST_F(AutoVectorTest
, CopyAndAssignment
) {
126 // Test both heap-allocated and stack-allocated cases.
127 for (auto size
: { kSize
/ 2, kSize
* 1000 }) {
128 autovector
<size_t, kSize
> vec
;
129 for (size_t i
= 0; i
< size
; ++i
) {
134 autovector
<size_t, kSize
> other
;
136 AssertEqual(other
, vec
);
140 autovector
<size_t, kSize
> other(vec
);
141 AssertEqual(other
, vec
);
146 TEST_F(AutoVectorTest
, Iterators
) {
147 autovector
<std::string
, kSize
> vec
;
148 for (size_t i
= 0; i
< kSize
* 1000; ++i
) {
149 vec
.push_back(ToString(i
));
152 // basic operator test
153 ASSERT_EQ(vec
.front(), *vec
.begin());
154 ASSERT_EQ(vec
.back(), *(vec
.end() - 1));
155 ASSERT_TRUE(vec
.begin() < vec
.end());
157 // non-const iterator
159 for (const auto& item
: vec
) {
160 ASSERT_EQ(vec
[index
++], item
);
163 index
= vec
.size() - 1;
164 for (auto pos
= vec
.rbegin(); pos
!= vec
.rend(); ++pos
) {
165 ASSERT_EQ(vec
[index
--], *pos
);
169 const auto& cvec
= vec
;
171 for (const auto& item
: cvec
) {
172 ASSERT_EQ(cvec
[index
++], item
);
175 index
= vec
.size() - 1;
176 for (auto pos
= cvec
.rbegin(); pos
!= cvec
.rend(); ++pos
) {
177 ASSERT_EQ(cvec
[index
--], *pos
);
180 // forward and backward
181 auto pos
= vec
.begin();
182 while (pos
!= vec
.end()) {
185 // HACK: make sure -> works
186 ASSERT_TRUE(!old
->empty());
187 ASSERT_EQ(old_val
, *old
);
188 ASSERT_TRUE(pos
== vec
.end() || old_val
!= *pos
);
192 for (size_t i
= 0; i
< vec
.size(); i
+= 2) {
193 // Cannot use ASSERT_EQ since that macro depends on iostream serialization
194 ASSERT_TRUE(pos
+ 2 - 2 == pos
);
196 ASSERT_TRUE(pos
>= vec
.begin());
197 ASSERT_TRUE(pos
<= vec
.end());
199 size_t diff
= static_cast<size_t>(pos
- vec
.begin());
200 ASSERT_EQ(i
+ 2, diff
);
205 std::vector
<std::string
> GetTestKeys(size_t size
) {
206 std::vector
<std::string
> keys
;
210 for (auto& key
: keys
) {
211 key
= "item-" + ROCKSDB_NAMESPACE::ToString(index
++);
217 template <class TVector
>
218 void BenchmarkVectorCreationAndInsertion(
219 std::string name
, size_t ops
, size_t item_size
,
220 const std::vector
<typename
TVector::value_type
>& items
) {
221 auto env
= Env::Default();
224 auto start_time
= env
->NowNanos();
225 auto ops_remaining
= ops
;
226 while(ops_remaining
--) {
228 for (size_t i
= 0; i
< item_size
; ++i
) {
229 v
.push_back(items
[index
++]);
232 auto elapsed
= env
->NowNanos() - start_time
;
233 cout
<< "created " << ops
<< " " << name
<< " instances:\n\t"
234 << "each was inserted with " << item_size
<< " elements\n\t"
235 << "total time elapsed: " << elapsed
<< " (ns)" << endl
;
238 template <class TVector
>
239 size_t BenchmarkSequenceAccess(std::string name
, size_t ops
, size_t elem_size
) {
241 for (const auto& item
: GetTestKeys(elem_size
)) {
244 auto env
= Env::Default();
246 auto ops_remaining
= ops
;
247 auto start_time
= env
->NowNanos();
249 while (ops_remaining
--) {
251 for (auto pos
= v
.begin(); pos
!= end
; ++pos
) {
252 total
+= pos
->size();
255 auto elapsed
= env
->NowNanos() - start_time
;
256 cout
<< "performed " << ops
<< " sequence access against " << name
<< "\n\t"
257 << "size: " << elem_size
<< "\n\t"
258 << "total time elapsed: " << elapsed
<< " (ns)" << endl
;
259 // HACK avoid compiler's optimization to ignore total
263 // This test case only reports the performance between std::vector<std::string>
264 // and autovector<std::string>. We chose string for comparison because in most
265 // of our use cases we used std::vector<std::string>.
266 TEST_F(AutoVectorTest
, PerfBench
) {
267 // We run same operations for kOps times in order to get a more fair result.
268 size_t kOps
= 100000;
270 // Creation and insertion test
271 // Test the case when there is:
272 // * no element inserted: internal array of std::vector may not really get
274 // * one element inserted: internal array of std::vector must have
276 // * kSize elements inserted. This shows the most time we'll spend if we
277 // keep everything in stack.
278 // * 2 * kSize elements inserted. The internal vector of
279 // autovector must have been initialized.
280 cout
<< "=====================================================" << endl
;
281 cout
<< "Creation and Insertion Test (value type: std::string)" << endl
;
282 cout
<< "=====================================================" << endl
;
284 // pre-generated unique keys
285 auto string_keys
= GetTestKeys(kOps
* 2 * kSize
);
286 for (auto insertions
: { 0ul, 1ul, kSize
/ 2, kSize
, 2 * kSize
}) {
287 BenchmarkVectorCreationAndInsertion
<std::vector
<std::string
>>(
288 "std::vector<std::string>", kOps
, insertions
, string_keys
);
289 BenchmarkVectorCreationAndInsertion
<autovector
<std::string
, kSize
>>(
290 "autovector<std::string>", kOps
, insertions
, string_keys
);
291 cout
<< "-----------------------------------" << endl
;
294 cout
<< "=====================================================" << endl
;
295 cout
<< "Creation and Insertion Test (value type: uint64_t)" << endl
;
296 cout
<< "=====================================================" << endl
;
298 // pre-generated unique keys
299 std::vector
<uint64_t> int_keys(kOps
* 2 * kSize
);
300 for (size_t i
= 0; i
< kOps
* 2 * kSize
; ++i
) {
303 for (auto insertions
: { 0ul, 1ul, kSize
/ 2, kSize
, 2 * kSize
}) {
304 BenchmarkVectorCreationAndInsertion
<std::vector
<uint64_t>>(
305 "std::vector<uint64_t>", kOps
, insertions
, int_keys
);
306 BenchmarkVectorCreationAndInsertion
<autovector
<uint64_t, kSize
>>(
307 "autovector<uint64_t>", kOps
, insertions
, int_keys
309 cout
<< "-----------------------------------" << endl
;
312 // Sequence Access Test
313 cout
<< "=====================================================" << endl
;
314 cout
<< "Sequence Access Test" << endl
;
315 cout
<< "=====================================================" << endl
;
316 for (auto elem_size
: { kSize
/ 2, kSize
, 2 * kSize
}) {
317 BenchmarkSequenceAccess
<std::vector
<std::string
>>("std::vector", kOps
,
319 BenchmarkSequenceAccess
<autovector
<std::string
, kSize
>>("autovector", kOps
,
321 cout
<< "-----------------------------------" << endl
;
325 } // namespace ROCKSDB_NAMESPACE
327 int main(int argc
, char** argv
) {
328 ::testing::InitGoogleTest(&argc
, argv
);
329 return RUN_ALL_TESTS();