2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/io/IOBuf.h>
19 #include <gflags/gflags.h>
20 #include <boost/random.hpp>
21 #include <gtest/gtest.h>
22 #include <folly/Benchmark.h>
23 #include <folly/Range.h>
24 #include <folly/io/Cursor.h>
26 DECLARE_bool(benchmark);
29 using std::unique_ptr;
30 using namespace folly::io;
32 TEST(IOBuf, RWCursor) {
33 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
35 unique_ptr<IOBuf> iobuf2(IOBuf::create(20));
38 IOBuf* iob2ptr = iobuf2.get();
39 iobuf1->prependChain(std::move(iobuf2));
41 EXPECT_TRUE(iobuf1->isChained());
43 RWPrivateCursor wcursor(iobuf1.get());
44 Cursor rcursor(iobuf1.get());
45 wcursor.writeLE((uint64_t)1);
46 wcursor.writeLE((uint64_t)1);
47 wcursor.writeLE((uint64_t)1);
48 wcursor.write((uint8_t)1);
50 EXPECT_EQ(1, rcursor.readLE<uint64_t>());
52 EXPECT_EQ(1, rcursor.readLE<uint32_t>());
54 EXPECT_EQ(0, rcursor.read<uint8_t>());
55 EXPECT_EQ(0, rcursor.read<uint8_t>());
56 EXPECT_EQ(0, rcursor.read<uint8_t>());
57 EXPECT_EQ(0, rcursor.read<uint8_t>());
58 EXPECT_EQ(1, rcursor.read<uint8_t>());
62 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
64 RWPrivateCursor wcursor(iobuf1.get());
65 wcursor.write((uint8_t)1);
66 wcursor.write((uint8_t)2);
67 Cursor cursor(iobuf1.get());
69 EXPECT_EQ(2, cursor.read<uint8_t>());
73 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
75 RWPrivateCursor wcursor(iobuf1.get());
76 wcursor.write((uint8_t)1);
77 wcursor.write((uint8_t)2);
78 wcursor.reset(iobuf1.get());
79 EXPECT_EQ(1, wcursor.read<uint8_t>());
82 TEST(IOBuf, copy_assign_convert) {
83 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
85 RWPrivateCursor wcursor(iobuf1.get());
86 RWPrivateCursor cursor2(wcursor);
87 RWPrivateCursor cursor3(iobuf1.get());
89 wcursor.write((uint8_t)1);
91 wcursor.write((uint8_t)2);
92 Cursor cursor4(wcursor);
93 RWPrivateCursor cursor5(wcursor);
94 wcursor.write((uint8_t)3);
96 EXPECT_EQ(1, cursor2.read<uint8_t>());
97 EXPECT_EQ(2, cursor3.read<uint8_t>());
98 EXPECT_EQ(3, cursor4.read<uint8_t>());
101 TEST(IOBuf, arithmetic) {
102 IOBuf iobuf1(IOBuf::CREATE, 20);
104 RWPrivateCursor wcursor(&iobuf1);
106 wcursor.write((uint8_t)1);
107 Cursor cursor(&iobuf1);
109 EXPECT_EQ(1, cursor.read<uint8_t>());
111 Cursor start(&iobuf1);
112 Cursor cursor2 = start + 9;
113 EXPECT_EQ(7, cursor2 - cursor);
114 EXPECT_NE(cursor, cursor2);
116 cursor2 = cursor2 + 1;
117 EXPECT_EQ(cursor, cursor2);
120 TEST(IOBuf, endian) {
121 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
123 RWPrivateCursor wcursor(iobuf1.get());
124 Cursor rcursor(iobuf1.get());
129 // Try a couple combinations to ensure they were generated correctly
134 EXPECT_EQ(v, rcursor.readBE<uint16_t>());
137 TEST(IOBuf, Cursor) {
138 unique_ptr<IOBuf> iobuf1(IOBuf::create(1));
140 RWPrivateCursor c(iobuf1.get());
141 c.write((uint8_t)40); // OK
143 c.write((uint8_t)10); // Bad write, checked should except.
144 EXPECT_EQ(true, false);
149 TEST(IOBuf, UnshareCursor) {
151 unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(&buf, 1));
152 unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(&buf, 1));
153 RWUnshareCursor c1(iobuf1.get());
154 RWUnshareCursor c2(iobuf2.get());
156 c1.write((uint8_t)10); // This should duplicate the two buffers.
157 uint8_t t = c2.read<uint8_t>();
160 iobuf1 = IOBuf::wrapBuffer(&buf, 1);
161 iobuf2 = IOBuf::wrapBuffer(&buf, 1);
162 RWPrivateCursor c3(iobuf1.get());
163 RWPrivateCursor c4(iobuf2.get());
165 c3.write((uint8_t)10); // This should _not_ duplicate the two buffers.
166 t = c4.read<uint8_t>();
171 void append(std::unique_ptr<IOBuf>& buf, folly::StringPiece data) {
172 EXPECT_LE(data.size(), buf->tailroom());
173 memcpy(buf->writableData(), data.data(), data.size());
174 buf->append(data.size());
177 void append(Appender& appender, folly::StringPiece data) {
178 appender.push(reinterpret_cast<const uint8_t*>(data.data()), data.size());
181 std::string toString(const IOBuf& buf) {
184 std::pair<const uint8_t*, size_t> p;
185 while ((p = cursor.peek()).second) {
186 str.append(reinterpret_cast<const char*>(p.first), p.second);
187 cursor.skip(p.second);
194 TEST(IOBuf, PullAndPeek) {
195 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
196 append(iobuf1, "he");
197 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
198 append(iobuf2, "llo ");
199 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
200 append(iobuf3, "world");
201 iobuf1->prependChain(std::move(iobuf2));
202 iobuf1->prependChain(std::move(iobuf3));
203 EXPECT_EQ(3, iobuf1->countChainElements());
204 EXPECT_EQ(11, iobuf1->computeChainDataLength());
207 memset(buf, 0, sizeof(buf));
208 Cursor(iobuf1.get()).pull(buf, 11);
209 EXPECT_EQ("hello world", std::string(buf));
211 memset(buf, 0, sizeof(buf));
212 EXPECT_EQ(11, Cursor(iobuf1.get()).pullAtMost(buf, 20));
213 EXPECT_EQ("hello world", std::string(buf));
215 EXPECT_THROW({Cursor(iobuf1.get()).pull(buf, 20);},
219 RWPrivateCursor cursor(iobuf1.get());
220 auto p = cursor.peek();
221 EXPECT_EQ("he", std::string(reinterpret_cast<const char*>(p.first),
223 cursor.skip(p.second);
225 EXPECT_EQ("llo ", std::string(reinterpret_cast<const char*>(p.first),
227 cursor.skip(p.second);
229 EXPECT_EQ("world", std::string(reinterpret_cast<const char*>(p.first),
231 cursor.skip(p.second);
232 EXPECT_EQ(3, iobuf1->countChainElements());
233 EXPECT_EQ(11, iobuf1->computeChainDataLength());
237 RWPrivateCursor cursor(iobuf1.get());
239 auto p = cursor.peek();
240 EXPECT_EQ("hello world", std::string(reinterpret_cast<const
241 char*>(p.first), p.second));
242 EXPECT_EQ(1, iobuf1->countChainElements());
243 EXPECT_EQ(11, iobuf1->computeChainDataLength());
247 TEST(IOBuf, pushCursorData) {
248 unique_ptr<IOBuf> iobuf1(IOBuf::create(20));
250 iobuf1->trimStart(5);
251 unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
252 unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
255 iobuf1->prependChain(std::move(iobuf2));
256 iobuf1->prependChain(std::move(iobuf3));
257 EXPECT_TRUE(iobuf1->isChained());
259 //write 20 bytes to the buffer chain
260 RWPrivateCursor wcursor(iobuf1.get());
261 wcursor.writeBE<uint64_t>(1);
262 wcursor.writeBE<uint64_t>(10);
263 wcursor.writeBE<uint32_t>(20);
265 // create a read buffer for the buffer chain
266 Cursor rcursor(iobuf1.get());
267 EXPECT_EQ(1, rcursor.readBE<uint64_t>());
268 EXPECT_EQ(10, rcursor.readBE<uint64_t>());
269 EXPECT_EQ(20, rcursor.readBE<uint32_t>());
270 EXPECT_EQ(0, rcursor.totalLength());
271 rcursor.reset(iobuf1.get());
272 EXPECT_EQ(20, rcursor.totalLength());
274 // create another write buffer
275 unique_ptr<IOBuf> iobuf4(IOBuf::create(30));
277 RWPrivateCursor wcursor2(iobuf4.get());
278 // write buffer chain data into it, now wcursor2 should only
279 // have 10 bytes writable space
280 wcursor2.push(rcursor, 20);
281 EXPECT_EQ(wcursor2.totalLength(), 10);
282 // write again with not enough space in rcursor
283 EXPECT_THROW(wcursor2.push(rcursor, 20), std::out_of_range);
285 // create a read cursor to check iobuf3 data back
286 Cursor rcursor2(iobuf4.get());
287 EXPECT_EQ(1, rcursor2.readBE<uint64_t>());
288 EXPECT_EQ(10, rcursor2.readBE<uint64_t>());
289 EXPECT_EQ(20, rcursor2.readBE<uint32_t>());
293 TEST(IOBuf, Gather) {
294 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
295 append(iobuf1, "he");
296 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
297 append(iobuf2, "llo ");
298 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
299 append(iobuf3, "world");
300 iobuf1->prependChain(std::move(iobuf2));
301 iobuf1->prependChain(std::move(iobuf3));
302 EXPECT_EQ(3, iobuf1->countChainElements());
303 EXPECT_EQ(11, iobuf1->computeChainDataLength());
305 // Attempting to gather() more data than available in the chain should fail.
306 // Try from the very beginning of the chain.
307 RWPrivateCursor cursor(iobuf1.get());
308 EXPECT_THROW(cursor.gather(15), std::overflow_error);
309 // Now try from the middle of the chain
311 EXPECT_THROW(cursor.gather(10), std::overflow_error);
313 // Calling gatherAtMost() should succeed, however, and just gather
315 cursor.gatherAtMost(10);
316 EXPECT_EQ(8, cursor.length());
317 EXPECT_EQ(8, cursor.totalLength());
318 EXPECT_EQ("lo world",
319 folly::StringPiece(reinterpret_cast<const char*>(cursor.data()),
321 EXPECT_EQ(2, iobuf1->countChainElements());
322 EXPECT_EQ(11, iobuf1->computeChainDataLength());
324 // Now try gather again on the chain head
325 cursor = RWPrivateCursor(iobuf1.get());
327 // Since gather() doesn't split buffers, everything should be collapsed into
328 // a single buffer now.
329 EXPECT_EQ(1, iobuf1->countChainElements());
330 EXPECT_EQ(11, iobuf1->computeChainDataLength());
331 EXPECT_EQ(11, cursor.length());
332 EXPECT_EQ(11, cursor.totalLength());
335 TEST(IOBuf, cloneAndInsert) {
336 std::unique_ptr<IOBuf> iobuf1(IOBuf::create(10));
337 append(iobuf1, "he");
338 std::unique_ptr<IOBuf> iobuf2(IOBuf::create(10));
339 append(iobuf2, "llo ");
340 std::unique_ptr<IOBuf> iobuf3(IOBuf::create(10));
341 append(iobuf3, "world");
342 iobuf1->prependChain(std::move(iobuf2));
343 iobuf1->prependChain(std::move(iobuf3));
344 EXPECT_EQ(3, iobuf1->countChainElements());
345 EXPECT_EQ(11, iobuf1->computeChainDataLength());
347 std::unique_ptr<IOBuf> cloned;
349 Cursor(iobuf1.get()).clone(cloned, 3);
350 EXPECT_EQ(2, cloned->countChainElements());
351 EXPECT_EQ(3, cloned->computeChainDataLength());
354 EXPECT_EQ(11, Cursor(iobuf1.get()).cloneAtMost(cloned, 20));
355 EXPECT_EQ(3, cloned->countChainElements());
356 EXPECT_EQ(11, cloned->computeChainDataLength());
359 EXPECT_THROW({Cursor(iobuf1.get()).clone(cloned, 20);},
363 // Check that inserting in the middle of an iobuf splits
364 RWPrivateCursor cursor(iobuf1.get());
365 Cursor(iobuf1.get()).clone(cloned, 3);
366 EXPECT_EQ(2, cloned->countChainElements());
367 EXPECT_EQ(3, cloned->computeChainDataLength());
371 cursor.insert(std::move(cloned));
372 cursor.insert(folly::IOBuf::create(0));
373 EXPECT_EQ(7, iobuf1->countChainElements());
374 EXPECT_EQ(14, iobuf1->computeChainDataLength());
375 // Check that nextBuf got set correctly to the buffer with 1 byte left
376 EXPECT_EQ(1, cursor.peek().second);
377 cursor.read<uint8_t>();
381 // Check that inserting at the end doesn't create empty buf
382 RWPrivateCursor cursor(iobuf1.get());
383 Cursor(iobuf1.get()).clone(cloned, 1);
384 EXPECT_EQ(1, cloned->countChainElements());
385 EXPECT_EQ(1, cloned->computeChainDataLength());
389 cursor.insert(std::move(cloned));
390 EXPECT_EQ(8, iobuf1->countChainElements());
391 EXPECT_EQ(15, iobuf1->computeChainDataLength());
392 // Check that nextBuf got set correctly
393 cursor.read<uint8_t>();
396 // Check that inserting at the beginning doesn't create empty buf
397 RWPrivateCursor cursor(iobuf1.get());
398 Cursor(iobuf1.get()).clone(cloned, 1);
399 EXPECT_EQ(1, cloned->countChainElements());
400 EXPECT_EQ(1, cloned->computeChainDataLength());
402 cursor.insert(std::move(cloned));
403 EXPECT_EQ(9, iobuf1->countChainElements());
404 EXPECT_EQ(16, iobuf1->computeChainDataLength());
405 // Check that nextBuf got set correctly
406 cursor.read<uint8_t>();
410 TEST(IOBuf, Appender) {
411 std::unique_ptr<IOBuf> head(IOBuf::create(10));
412 append(head, "hello");
414 Appender app(head.get(), 10);
415 uint32_t cap = head->capacity();
416 uint32_t len1 = app.length();
417 EXPECT_EQ(cap - 5, len1);
418 app.ensure(len1); // won't grow
419 EXPECT_EQ(len1, app.length());
420 app.ensure(len1 + 1); // will grow
421 EXPECT_LE(len1 + 1, app.length());
423 append(app, " world");
424 EXPECT_EQ("hello world", toString(*head));
427 TEST(IOBuf, QueueAppender) {
428 folly::IOBufQueue queue;
430 // Allocate 100 bytes at once, but don't grow past 1024
431 QueueAppender app(&queue, 100);
432 size_t n = 1024 / sizeof(uint32_t);
433 for (uint32_t i = 0; i < n; ++i) {
437 // There must be a goodMallocSize between 100 and 1024...
438 EXPECT_LT(1, queue.front()->countChainElements());
439 const IOBuf* buf = queue.front();
441 EXPECT_LE(100, buf->capacity());
443 } while (buf != queue.front());
445 Cursor cursor(queue.front());
446 for (uint32_t i = 0; i < n; ++i) {
447 EXPECT_EQ(i, cursor.readBE<uint32_t>());
450 EXPECT_THROW({cursor.readBE<uint32_t>();}, std::out_of_range);
453 TEST(IOBuf, CursorOperators) {
454 // Test operators on a single-item chain
456 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
459 Cursor curs1(chain1.get());
460 EXPECT_EQ(0, curs1 - chain1.get());
462 EXPECT_EQ(3, curs1 - chain1.get());
464 EXPECT_EQ(10, curs1 - chain1.get());
466 Cursor curs2(chain1.get());
467 EXPECT_EQ(0, curs2 - chain1.get());
468 EXPECT_EQ(10, curs1 - curs2);
469 EXPECT_THROW(curs2 - curs1, std::out_of_range);
472 // Test cross-chain operations
474 std::unique_ptr<IOBuf> chain1(IOBuf::create(20));
476 std::unique_ptr<IOBuf> chain2 = chain1->clone();
478 Cursor curs1(chain1.get());
479 Cursor curs2(chain2.get());
480 EXPECT_THROW(curs1 - curs2, std::out_of_range);
481 EXPECT_THROW(curs1 - chain2.get(), std::out_of_range);
484 // Test operations on multi-item chains
486 std::unique_ptr<IOBuf> chain(IOBuf::create(20));
488 chain->appendChain(chain->clone());
489 EXPECT_EQ(20, chain->computeChainDataLength());
491 Cursor curs1(chain.get());
493 Cursor curs2(chain.get());
495 EXPECT_EQ(2, curs1 - curs2);
496 EXPECT_EQ(5, curs1 - chain.get());
497 EXPECT_THROW(curs2 - curs1, std::out_of_range);
500 EXPECT_EQ(9, curs1 - curs2);
501 EXPECT_EQ(12, curs1 - chain.get());
502 EXPECT_THROW(curs2 - curs1, std::out_of_range);
505 EXPECT_EQ(2, curs1 - curs2);
506 EXPECT_THROW(curs2 - curs1, std::out_of_range);
510 TEST(IOBuf, StringOperations) {
511 // Test a single buffer with two null-terminated strings and an extra uint8_t
514 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
515 Appender app(chain.get(), 0);
516 app.push(reinterpret_cast<const uint8_t*>("hello\0world\0\x01"), 13);
518 Cursor curs(chain.get());
519 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
520 EXPECT_STREQ("world", curs.readTerminatedString().c_str());
521 EXPECT_EQ(1, curs.read<uint8_t>());
524 // Test multiple buffers where the first is empty and the string starts in
525 // the second buffer.
527 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
528 chain->prependChain(IOBuf::create(12));
529 Appender app(chain.get(), 0);
530 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
532 Cursor curs(chain.get());
533 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
536 // Test multiple buffers with a single null-terminated string spanning them
538 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
539 chain->prependChain(IOBuf::create(8));
541 chain->next()->append(4);
542 RWPrivateCursor rwc(chain.get());
543 rwc.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
545 Cursor curs(chain.get());
546 EXPECT_STREQ("hello world", curs.readTerminatedString().c_str());
549 // Test a reading a null-terminated string that's longer than the maximum
552 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
553 Appender app(chain.get(), 0);
554 app.push(reinterpret_cast<const uint8_t*>("hello world\0"), 12);
556 Cursor curs(chain.get());
557 EXPECT_THROW(curs.readTerminatedString('\0', 5), std::length_error);
560 // Test reading a null-terminated string from a chain with an empty buffer at
563 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
564 Appender app(buf.get(), 0);
565 app.push(reinterpret_cast<const uint8_t*>("hello\0"), 6);
566 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
567 chain->prependChain(std::move(buf));
569 Cursor curs(chain.get());
570 EXPECT_STREQ("hello", curs.readTerminatedString().c_str());
573 // Test reading a two fixed-length strings from a single buffer with an extra
574 // uint8_t at the end
576 std::unique_ptr<IOBuf> chain(IOBuf::create(16));
577 Appender app(chain.get(), 0);
578 app.push(reinterpret_cast<const uint8_t*>("helloworld\x01"), 11);
580 Cursor curs(chain.get());
581 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
582 EXPECT_STREQ("world", curs.readFixedString(5).c_str());
583 EXPECT_EQ(1, curs.read<uint8_t>());
586 // Test multiple buffers where the first is empty and a fixed-length string
587 // starts in the second buffer.
589 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
590 chain->prependChain(IOBuf::create(16));
591 Appender app(chain.get(), 0);
592 app.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
594 Cursor curs(chain.get());
595 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
598 // Test multiple buffers with a single fixed-length string spanning them
600 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
601 chain->prependChain(IOBuf::create(8));
603 chain->next()->append(4);
604 RWPrivateCursor rwc(chain.get());
605 rwc.push(reinterpret_cast<const uint8_t*>("hello world"), 11);
607 Cursor curs(chain.get());
608 EXPECT_STREQ("hello world", curs.readFixedString(11).c_str());
611 // Test reading a fixed-length string from a chain with an empty buffer at
614 std::unique_ptr<IOBuf> buf(IOBuf::create(8));
615 Appender app(buf.get(), 0);
616 app.push(reinterpret_cast<const uint8_t*>("hello"), 5);
617 std::unique_ptr<IOBuf> chain(IOBuf::create(8));
618 chain->prependChain(std::move(buf));
620 Cursor curs(chain.get());
621 EXPECT_STREQ("hello", curs.readFixedString(5).c_str());
625 int benchmark_size = 1000;
626 unique_ptr<IOBuf> iobuf_benchmark;
628 unique_ptr<IOBuf> iobuf_read_benchmark;
630 template <class CursClass>
631 void runBenchmark() {
632 CursClass c(iobuf_benchmark.get());
634 for(int i = 0; i < benchmark_size; i++) {
639 BENCHMARK(rwPrivateCursorBenchmark, iters) {
641 runBenchmark<RWPrivateCursor>();
645 BENCHMARK(rwUnshareCursorBenchmark, iters) {
647 runBenchmark<RWUnshareCursor>();
652 BENCHMARK(cursorBenchmark, iters) {
654 Cursor c(iobuf_read_benchmark.get());
655 for(int i = 0; i < benchmark_size ; i++) {
661 BENCHMARK(skipBenchmark, iters) {
664 Cursor c(iobuf_read_benchmark.get());
665 for(int i = 0; i < benchmark_size ; i++) {
673 // _bin/folly/experimental/io/test/iobuf_cursor_test -benchmark
675 // Benchmark Iters Total t t/iter iter/sec
676 // ---------------------------------------------------------------------------
677 // rwPrivateCursorBenchmark 100000 142.9 ms 1.429 us 683.5 k
678 // rwUnshareCursorBenchmark 100000 309.3 ms 3.093 us 315.7 k
679 // cursorBenchmark 100000 741.4 ms 7.414 us 131.7 k
680 // skipBenchmark 100000 738.9 ms 7.389 us 132.2 k
684 // Linux dev2159.snc6.facebook.com 2.6.33-7_fbk15_104e4d0 #1 SMP
685 // Tue Oct 19 22:40:30 PDT 2010 x86_64 x86_64 x86_64 GNU/Linux
687 // 72GB RAM, 2 CPUs (Intel(R) Xeon(R) CPU L5630 @ 2.13GHz)
688 // hyperthreading disabled
690 int main(int argc, char** argv) {
691 testing::InitGoogleTest(&argc, argv);
692 gflags::ParseCommandLineFlags(&argc, &argv, true);
694 auto ret = RUN_ALL_TESTS();
696 if (ret == 0 && FLAGS_benchmark) {
697 iobuf_benchmark = IOBuf::create(benchmark_size);
698 iobuf_benchmark->append(benchmark_size);
700 iobuf_read_benchmark = IOBuf::create(1);
701 for (int i = 0; i < benchmark_size; i++) {
702 unique_ptr<IOBuf> iobuf2(IOBuf::create(1));
704 iobuf_read_benchmark->prependChain(std::move(iobuf2));
707 folly::runBenchmarks();