• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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