1 #include <gtest/gtest.h>
2 #include <android/sync.h>
3 #include <sw_sync.h>
4 #include <fcntl.h>
5 #include <vector>
6 #include <string>
7 #include <cassert>
8 #include <iostream>
9 #include <unistd.h>
10 #include <thread>
11 #include <poll.h>
12 #include <mutex>
13 #include <algorithm>
14 #include <tuple>
15 #include <random>
16 #include <unordered_map>
17
18 /* These deprecated declarations were in the legacy android/sync.h. They've been removed to
19 * encourage code to move to the modern equivalents. But they are still implemented in libsync.so
20 * to avoid breaking existing binaries; as long as that's true we should keep testing them here.
21 * That means making local copies of the declarations.
22 */
23 extern "C" {
24
25 struct sync_fence_info_data {
26 uint32_t len;
27 char name[32];
28 int32_t status;
29 uint8_t pt_info[0];
30 };
31
32 struct sync_pt_info {
33 uint32_t len;
34 char obj_name[32];
35 char driver_name[32];
36 int32_t status;
37 uint64_t timestamp_ns;
38 uint8_t driver_data[0];
39 };
40
41 struct sync_fence_info_data* sync_fence_info(int fd);
42 struct sync_pt_info* sync_pt_info(struct sync_fence_info_data* info, struct sync_pt_info* itr);
43 void sync_fence_info_free(struct sync_fence_info_data* info);
44
45 } // extern "C"
46
47 // TODO: better stress tests?
48 // Handle more than 64 fd's simultaneously, i.e. fix sync_fence_info's 4k limit.
49 // Handle wraparound in timelines like nvidia.
50
51 using namespace std;
52
53 namespace {
54
55 // C++ wrapper class for sync timeline.
56 class SyncTimeline {
57 int m_fd = -1;
58 bool m_fdInitialized = false;
59 public:
60 SyncTimeline(const SyncTimeline &) = delete;
61 SyncTimeline& operator=(SyncTimeline&) = delete;
SyncTimeline()62 SyncTimeline() noexcept {
63 int fd = sw_sync_timeline_create();
64 if (fd == -1)
65 return;
66 m_fdInitialized = true;
67 m_fd = fd;
68 }
destroy()69 void destroy() {
70 if (m_fdInitialized) {
71 close(m_fd);
72 m_fd = -1;
73 m_fdInitialized = false;
74 }
75 }
~SyncTimeline()76 ~SyncTimeline() {
77 destroy();
78 }
isValid() const79 bool isValid() const {
80 if (m_fdInitialized) {
81 int status = fcntl(m_fd, F_GETFD, 0);
82 if (status >= 0)
83 return true;
84 else
85 return false;
86 }
87 else {
88 return false;
89 }
90 }
getFd() const91 int getFd() const {
92 return m_fd;
93 }
inc(int val=1)94 int inc(int val = 1) {
95 return sw_sync_timeline_inc(m_fd, val);
96 }
97 };
98
99 struct SyncPointInfo {
100 std::string driverName;
101 std::string objectName;
102 uint64_t timeStampNs;
103 int status; // 1 sig, 0 active, neg is err
104 };
105
106 // Wrapper class for sync fence.
107 class SyncFence {
108 int m_fd = -1;
109 bool m_fdInitialized = false;
110 static int s_fenceCount;
111
setFd(int fd)112 void setFd(int fd) {
113 m_fd = fd;
114 m_fdInitialized = true;
115 }
clearFd()116 void clearFd() {
117 m_fd = -1;
118 m_fdInitialized = false;
119 }
120 public:
isValid() const121 bool isValid() const {
122 if (m_fdInitialized) {
123 int status = fcntl(m_fd, F_GETFD, 0);
124 if (status >= 0)
125 return true;
126 else
127 return false;
128 }
129 else {
130 return false;
131 }
132 }
operator =(SyncFence && rhs)133 SyncFence& operator=(SyncFence &&rhs) noexcept {
134 destroy();
135 if (rhs.isValid()) {
136 setFd(rhs.getFd());
137 rhs.clearFd();
138 }
139 return *this;
140 }
SyncFence(SyncFence && fence)141 SyncFence(SyncFence &&fence) noexcept {
142 if (fence.isValid()) {
143 setFd(fence.getFd());
144 fence.clearFd();
145 }
146 }
SyncFence(const SyncFence & fence)147 SyncFence(const SyncFence &fence) noexcept {
148 // This is ok, as sync fences are immutable after construction, so a dup
149 // is basically the same thing as a copy.
150 if (fence.isValid()) {
151 int fd = dup(fence.getFd());
152 if (fd == -1)
153 return;
154 setFd(fd);
155 }
156 }
SyncFence(const SyncTimeline & timeline,int value,const char * name=nullptr)157 SyncFence(const SyncTimeline &timeline,
158 int value,
159 const char *name = nullptr) noexcept {
160 std::string autoName = "allocFence";
161 autoName += s_fenceCount;
162 s_fenceCount++;
163 int fd = sw_sync_fence_create(timeline.getFd(), name ? name : autoName.c_str(), value);
164 if (fd == -1)
165 return;
166 setFd(fd);
167 }
SyncFence(const SyncFence & a,const SyncFence & b,const char * name=nullptr)168 SyncFence(const SyncFence &a, const SyncFence &b, const char *name = nullptr) noexcept {
169 std::string autoName = "mergeFence";
170 autoName += s_fenceCount;
171 s_fenceCount++;
172 int fd = sync_merge(name ? name : autoName.c_str(), a.getFd(), b.getFd());
173 if (fd == -1)
174 return;
175 setFd(fd);
176 }
SyncFence(const vector<SyncFence> & sources)177 SyncFence(const vector<SyncFence> &sources) noexcept {
178 assert(sources.size());
179 SyncFence temp(*begin(sources));
180 for (auto itr = ++begin(sources); itr != end(sources); ++itr) {
181 temp = SyncFence(*itr, temp);
182 }
183 if (temp.isValid()) {
184 setFd(temp.getFd());
185 temp.clearFd();
186 }
187 }
destroy()188 void destroy() {
189 if (isValid()) {
190 close(m_fd);
191 clearFd();
192 }
193 }
~SyncFence()194 ~SyncFence() {
195 destroy();
196 }
getFd() const197 int getFd() const {
198 return m_fd;
199 }
wait(int timeout=-1)200 int wait(int timeout = -1) {
201 return sync_wait(m_fd, timeout);
202 }
getInfo() const203 vector<SyncPointInfo> getInfo() const {
204 vector<SyncPointInfo> fenceInfo;
205 struct sync_file_info *info = sync_file_info(getFd());
206 if (!info) {
207 return fenceInfo;
208 }
209 const auto fences = sync_get_fence_info(info);
210 for (uint32_t i = 0; i < info->num_fences; i++) {
211 fenceInfo.push_back(SyncPointInfo{
212 fences[i].driver_name,
213 fences[i].obj_name,
214 fences[i].timestamp_ns,
215 fences[i].status});
216 }
217 sync_file_info_free(info);
218 return fenceInfo;
219 }
getSize() const220 int getSize() const {
221 return getInfo().size();
222 }
getSignaledCount() const223 int getSignaledCount() const {
224 return countWithStatus(1);
225 }
getActiveCount() const226 int getActiveCount() const {
227 return countWithStatus(0);
228 }
getErrorCount() const229 int getErrorCount() const {
230 return countWithStatus(-1);
231 }
232 private:
countWithStatus(int status) const233 int countWithStatus(int status) const {
234 int count = 0;
235 for (auto &info : getInfo()) {
236 if (info.status == status) {
237 count++;
238 }
239 }
240 return count;
241 }
242 };
243
CheckModernLegacyInfoMatch(const SyncFence & f)244 static void CheckModernLegacyInfoMatch(const SyncFence& f) {
245 struct sync_file_info* modern = sync_file_info(f.getFd());
246 struct sync_fence_info_data* legacy = sync_fence_info(f.getFd());
247
248 ASSERT_TRUE(modern != NULL);
249 ASSERT_TRUE(legacy != NULL);
250
251 EXPECT_STREQ(modern->name, legacy->name);
252 EXPECT_EQ(modern->status, legacy->status);
253
254 uint32_t fenceIdx = 0;
255 struct sync_pt_info* pt = sync_pt_info(legacy, NULL);
256 const struct sync_fence_info* fences = sync_get_fence_info(modern);
257 while (fenceIdx < modern->num_fences && pt != NULL) {
258 EXPECT_STREQ(fences[fenceIdx].obj_name, pt->obj_name);
259 EXPECT_STREQ(fences[fenceIdx].driver_name, pt->driver_name);
260 EXPECT_EQ(fences[fenceIdx].status, pt->status);
261 EXPECT_EQ(fences[fenceIdx].timestamp_ns, pt->timestamp_ns);
262
263 fenceIdx++;
264 pt = sync_pt_info(legacy, pt);
265 }
266 EXPECT_EQ(fenceIdx, modern->num_fences);
267 EXPECT_EQ(NULL, pt);
268 }
269
270 int SyncFence::s_fenceCount = 0;
271
TEST(AllocTest,Timeline)272 TEST(AllocTest, Timeline) {
273 SyncTimeline timeline;
274 ASSERT_TRUE(timeline.isValid());
275 }
276
TEST(AllocTest,Fence)277 TEST(AllocTest, Fence) {
278 SyncTimeline timeline;
279 ASSERT_TRUE(timeline.isValid());
280
281 SyncFence fence(timeline, 1);
282 ASSERT_TRUE(fence.isValid());
283 CheckModernLegacyInfoMatch(fence);
284 }
285
TEST(AllocTest,FenceNegative)286 TEST(AllocTest, FenceNegative) {
287 int timeline = sw_sync_timeline_create();
288 ASSERT_GT(timeline, 0);
289
290 // bad fd.
291 ASSERT_LT(sw_sync_fence_create(-1, "fence", 1), 0);
292
293 // No name - segfaults in user space.
294 // Maybe we should be friendlier here?
295 /*
296 ASSERT_LT(sw_sync_fence_create(timeline, nullptr, 1), 0);
297 */
298 close(timeline);
299 }
300
TEST(FenceTest,OneTimelineWait)301 TEST(FenceTest, OneTimelineWait) {
302 SyncTimeline timeline;
303 ASSERT_TRUE(timeline.isValid());
304
305 SyncFence fence(timeline, 5);
306 ASSERT_TRUE(fence.isValid());
307
308 // Wait on fence until timeout.
309 ASSERT_EQ(fence.wait(0), -1);
310 ASSERT_EQ(errno, ETIME);
311
312 // Advance timeline from 0 -> 1
313 ASSERT_EQ(timeline.inc(1), 0);
314
315 // Wait on fence until timeout.
316 ASSERT_EQ(fence.wait(0), -1);
317 ASSERT_EQ(errno, ETIME);
318
319 // Signal the fence.
320 ASSERT_EQ(timeline.inc(4), 0);
321
322 // Wait successfully.
323 ASSERT_EQ(fence.wait(0), 0);
324
325 // Go even futher, and confirm wait still succeeds.
326 ASSERT_EQ(timeline.inc(10), 0);
327 ASSERT_EQ(fence.wait(0), 0);
328 }
329
TEST(FenceTest,OneTimelinePoll)330 TEST(FenceTest, OneTimelinePoll) {
331 SyncTimeline timeline;
332 ASSERT_TRUE(timeline.isValid());
333
334 SyncFence fence(timeline, 100);
335 ASSERT_TRUE(fence.isValid());
336
337 fd_set set;
338 FD_ZERO(&set);
339 FD_SET(fence.getFd(), &set);
340
341 // Poll the fence, and wait till timeout.
342 timeval time = {0};
343 ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 0);
344
345 // Advance the timeline.
346 timeline.inc(100);
347 timeline.inc(100);
348
349 // Select should return that the fd is read for reading.
350 FD_ZERO(&set);
351 FD_SET(fence.getFd(), &set);
352
353 ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 1);
354 ASSERT_TRUE(FD_ISSET(fence.getFd(), &set));
355 }
356
TEST(FenceTest,OneTimelineMerge)357 TEST(FenceTest, OneTimelineMerge) {
358 SyncTimeline timeline;
359 ASSERT_TRUE(timeline.isValid());
360
361 // create fence a,b,c and then merge them all into fence d.
362 SyncFence a(timeline, 1), b(timeline, 2), c(timeline, 3);
363 ASSERT_TRUE(a.isValid());
364 ASSERT_TRUE(b.isValid());
365 ASSERT_TRUE(c.isValid());
366
367 SyncFence d({a,b,c});
368 ASSERT_TRUE(d.isValid());
369
370 // confirm all fences have one active point (even d).
371 ASSERT_EQ(a.getActiveCount(), 1);
372 ASSERT_EQ(b.getActiveCount(), 1);
373 ASSERT_EQ(c.getActiveCount(), 1);
374 ASSERT_EQ(d.getActiveCount(), 1);
375
376 // confirm that d is not signaled until the max of a,b,c
377 timeline.inc(1);
378 ASSERT_EQ(a.getSignaledCount(), 1);
379 ASSERT_EQ(d.getActiveCount(), 1);
380 CheckModernLegacyInfoMatch(a);
381 CheckModernLegacyInfoMatch(d);
382
383 timeline.inc(1);
384 ASSERT_EQ(b.getSignaledCount(), 1);
385 ASSERT_EQ(d.getActiveCount(), 1);
386 CheckModernLegacyInfoMatch(b);
387 CheckModernLegacyInfoMatch(d);
388
389 timeline.inc(1);
390 ASSERT_EQ(c.getSignaledCount(), 1);
391 ASSERT_EQ(d.getActiveCount(), 0);
392 ASSERT_EQ(d.getSignaledCount(), 1);
393 CheckModernLegacyInfoMatch(c);
394 CheckModernLegacyInfoMatch(d);
395 }
396
TEST(FenceTest,MergeSameFence)397 TEST(FenceTest, MergeSameFence) {
398 SyncTimeline timeline;
399 ASSERT_TRUE(timeline.isValid());
400
401 SyncFence fence(timeline, 5);
402 ASSERT_TRUE(fence.isValid());
403
404 SyncFence selfMergeFence(fence, fence);
405 ASSERT_TRUE(selfMergeFence.isValid());
406
407 ASSERT_EQ(selfMergeFence.getSignaledCount(), 0);
408 CheckModernLegacyInfoMatch(selfMergeFence);
409
410 timeline.inc(5);
411 ASSERT_EQ(selfMergeFence.getSignaledCount(), 1);
412 CheckModernLegacyInfoMatch(selfMergeFence);
413 }
414
TEST(FenceTest,PollOnDestroyedTimeline)415 TEST(FenceTest, PollOnDestroyedTimeline) {
416 SyncTimeline timeline;
417 ASSERT_TRUE(timeline.isValid());
418
419 SyncFence fenceSig(timeline, 100);
420 SyncFence fenceKill(timeline, 200);
421
422 // Spawn a thread to wait on a fence when the timeline is killed.
423 thread waitThread{
424 [&]() {
425 ASSERT_EQ(timeline.inc(100), 0);
426
427 // Wait on the fd.
428 struct pollfd fds;
429 fds.fd = fenceKill.getFd();
430 fds.events = POLLIN | POLLERR;
431 ASSERT_EQ(poll(&fds, 1, 0), 0);
432 }
433 };
434
435 // Wait for the thread to spool up.
436 fenceSig.wait();
437
438 // Kill the timeline.
439 timeline.destroy();
440
441 // wait for the thread to clean up.
442 waitThread.join();
443 }
444
TEST(FenceTest,MultiTimelineWait)445 TEST(FenceTest, MultiTimelineWait) {
446 SyncTimeline timelineA, timelineB, timelineC;
447
448 SyncFence fenceA(timelineA, 5);
449 SyncFence fenceB(timelineB, 5);
450 SyncFence fenceC(timelineC, 5);
451
452 // Make a larger fence using 3 other fences from different timelines.
453 SyncFence mergedFence({fenceA, fenceB, fenceC});
454 ASSERT_TRUE(mergedFence.isValid());
455
456 // Confirm fence isn't signaled
457 ASSERT_EQ(mergedFence.getActiveCount(), 3);
458 ASSERT_EQ(mergedFence.wait(0), -1);
459 ASSERT_EQ(errno, ETIME);
460
461 timelineA.inc(5);
462 ASSERT_EQ(mergedFence.getActiveCount(), 2);
463 ASSERT_EQ(mergedFence.getSignaledCount(), 1);
464 CheckModernLegacyInfoMatch(mergedFence);
465
466 timelineB.inc(5);
467 ASSERT_EQ(mergedFence.getActiveCount(), 1);
468 ASSERT_EQ(mergedFence.getSignaledCount(), 2);
469 CheckModernLegacyInfoMatch(mergedFence);
470
471 timelineC.inc(5);
472 ASSERT_EQ(mergedFence.getActiveCount(), 0);
473 ASSERT_EQ(mergedFence.getSignaledCount(), 3);
474 CheckModernLegacyInfoMatch(mergedFence);
475
476 // confirm you can successfully wait.
477 ASSERT_EQ(mergedFence.wait(100), 0);
478 }
479
TEST(FenceTest,GetInfoActive)480 TEST(FenceTest, GetInfoActive) {
481 SyncTimeline timeline;
482 ASSERT_TRUE(timeline.isValid());
483
484 SyncFence fence(timeline, 1);
485 ASSERT_TRUE(fence.isValid());
486
487 vector<SyncPointInfo> info = fence.getInfo();
488 ASSERT_EQ(info.size(), 1);
489
490 ASSERT_FALSE(info[0].driverName.empty());
491 ASSERT_FALSE(info[0].objectName.empty());
492 ASSERT_EQ(info[0].timeStampNs, 0);
493 ASSERT_EQ(info[0].status, 0);
494 }
495
TEST(FenceTest,GetInfoSignaled)496 TEST(FenceTest, GetInfoSignaled) {
497 SyncTimeline timeline;
498 ASSERT_TRUE(timeline.isValid());
499
500 SyncFence fence(timeline, 1);
501 ASSERT_TRUE(fence.isValid());
502
503 ASSERT_EQ(timeline.inc(1), 0);
504 ASSERT_EQ(fence.wait(), 0);
505
506 vector<SyncPointInfo> info = fence.getInfo();
507 ASSERT_EQ(info.size(), 1);
508
509 ASSERT_FALSE(info[0].driverName.empty());
510 ASSERT_FALSE(info[0].objectName.empty());
511 ASSERT_GT(info[0].timeStampNs, 0);
512 ASSERT_EQ(info[0].status, 1);
513 }
514
TEST(StressTest,TwoThreadsSharedTimeline)515 TEST(StressTest, TwoThreadsSharedTimeline) {
516 const int iterations = 1 << 16;
517 int counter = 0;
518 SyncTimeline timeline;
519 ASSERT_TRUE(timeline.isValid());
520
521 // Use a single timeline to synchronize two threads
522 // hammmering on the same counter.
523 auto threadMain = [&](int threadId) {
524 for (int i = 0; i < iterations; i++) {
525 SyncFence fence(timeline, i * 2 + threadId);
526 ASSERT_TRUE(fence.isValid());
527
528 // Wait on the prior thread to complete.
529 ASSERT_EQ(fence.wait(), 0);
530
531 // Confirm the previous thread's writes are visible and then inc.
532 ASSERT_EQ(counter, i * 2 + threadId);
533 counter++;
534
535 // Kick off the other thread.
536 ASSERT_EQ(timeline.inc(), 0);
537 }
538 };
539
540 thread a{threadMain, 0};
541 thread b{threadMain, 1};
542 a.join();
543 b.join();
544
545 // make sure the threads did not trample on one another.
546 ASSERT_EQ(counter, iterations * 2);
547 }
548
549 class ConsumerStressTest : public ::testing::TestWithParam<int> {};
550
TEST_P(ConsumerStressTest,MultiProducerSingleConsumer)551 TEST_P(ConsumerStressTest, MultiProducerSingleConsumer) {
552 mutex lock;
553 int counter = 0;
554 int iterations = 1 << 12;
555
556 vector<SyncTimeline> producerTimelines(GetParam());
557 vector<thread> threads;
558 SyncTimeline consumerTimeline;
559
560 // Producer threads run this lambda.
561 auto threadMain = [&](int threadId) {
562 for (int i = 0; i < iterations; i++) {
563 SyncFence fence(consumerTimeline, i);
564 ASSERT_TRUE(fence.isValid());
565
566 // Wait for the consumer to finish. Use alternate
567 // means of waiting on the fence.
568 if ((iterations + threadId) % 8 != 0) {
569 ASSERT_EQ(fence.wait(), 0);
570 }
571 else {
572 while (fence.getSignaledCount() != 1) {
573 ASSERT_EQ(fence.getErrorCount(), 0);
574 }
575 }
576
577 // Every producer increments the counter, the consumer checks + erases it.
578 lock.lock();
579 counter++;
580 lock.unlock();
581
582 ASSERT_EQ(producerTimelines[threadId].inc(), 0);
583 }
584 };
585
586 for (int i = 0; i < GetParam(); i++) {
587 threads.push_back(thread{threadMain, i});
588 }
589
590 // Consumer thread runs this loop.
591 for (int i = 1; i <= iterations; i++) {
592 // Create a fence representing all producers final timelines.
593 vector<SyncFence> fences;
594 for (auto& timeline : producerTimelines) {
595 fences.push_back(SyncFence(timeline, i));
596 }
597 SyncFence mergeFence(fences);
598 ASSERT_TRUE(mergeFence.isValid());
599
600 // Make sure we see an increment from every producer thread. Vary
601 // the means by which we wait.
602 if (iterations % 8 != 0) {
603 ASSERT_EQ(mergeFence.wait(), 0);
604 }
605 else {
606 while (mergeFence.getSignaledCount() != mergeFence.getSize()) {
607 ASSERT_EQ(mergeFence.getErrorCount(), 0);
608 }
609 }
610 ASSERT_EQ(counter, GetParam()*i);
611
612 // Release the producer threads.
613 ASSERT_EQ(consumerTimeline.inc(), 0);
614 }
615
616 for_each(begin(threads), end(threads), [](thread& thread) { thread.join(); });
617 }
618 INSTANTIATE_TEST_CASE_P(
619 ParameterizedStressTest,
620 ConsumerStressTest,
621 ::testing::Values(2,4,16));
622
623 class MergeStressTest : public ::testing::TestWithParam<tuple<int, int>> {};
624
625 template <typename K, typename V> using dict = unordered_map<K,V>;
626
TEST_P(MergeStressTest,RandomMerge)627 TEST_P(MergeStressTest, RandomMerge) {
628 int timelineCount = get<0>(GetParam());
629 int mergeCount = get<1>(GetParam());
630
631 vector<SyncTimeline> timelines(timelineCount);
632
633 default_random_engine generator;
634 uniform_int_distribution<int> timelineDist(0, timelines.size()-1);
635 uniform_int_distribution<int> syncPointDist(0, numeric_limits<int>::max());
636
637 SyncFence fence(timelines[0], 0);
638 ASSERT_TRUE(fence.isValid());
639
640 unordered_map<int, int> fenceMap;
641 fenceMap.insert(make_pair(0, 0));
642
643 // Randomly create syncpoints out of a fixed set of timelines, and merge them together.
644 for (int i = 0; i < mergeCount; i++) {
645
646 // Generate syncpoint.
647 int timelineOffset = timelineDist(generator);
648 const SyncTimeline& timeline = timelines[timelineOffset];
649 int syncPoint = syncPointDist(generator);
650
651 // Keep track of the latest syncpoint in each timeline.
652 auto itr = fenceMap.find(timelineOffset);
653 if (itr == end(fenceMap)) {
654 fenceMap.insert(make_pair(timelineOffset, syncPoint));
655 }
656 else {
657 int oldSyncPoint = itr->second;
658 fenceMap.erase(itr);
659 fenceMap.insert(make_pair(timelineOffset, max(syncPoint, oldSyncPoint)));
660 }
661
662 // Merge.
663 fence = SyncFence(fence, SyncFence(timeline, syncPoint));
664 ASSERT_TRUE(fence.isValid());
665 CheckModernLegacyInfoMatch(fence);
666 }
667
668 // Confirm our map matches the fence.
669 ASSERT_EQ(fence.getSize(), fenceMap.size());
670
671 // Trigger the merged fence.
672 for (auto& item: fenceMap) {
673 ASSERT_EQ(fence.wait(0), -1);
674 ASSERT_EQ(errno, ETIME);
675
676 // Increment the timeline to the last syncpoint.
677 timelines[item.first].inc(item.second);
678 }
679
680 // Check that the fence is triggered.
681 ASSERT_EQ(fence.wait(0), 0);
682 }
683
684 INSTANTIATE_TEST_CASE_P(
685 ParameterizedMergeStressTest,
686 MergeStressTest,
687 ::testing::Combine(::testing::Values(16,32), ::testing::Values(32, 1024, 1024*32)));
688
689 }
690
691