AllocatorTest.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // AllocatorTest.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "dxc/Support/WinIncludes.h"
  11. #ifdef _WIN32
  12. #include "WexTestClass.h"
  13. #endif
  14. #include "dxc/Test/HlslTestUtils.h"
  15. #include "dxc/HLSL/DxilSpanAllocator.h"
  16. #include <cstdlib>
  17. #include <random>
  18. #include <algorithm>
  19. #include <iterator>
  20. #include <vector>
  21. #include <set>
  22. #include <map>
  23. using namespace hlsl;
  24. /* Test Case Breakdown:
  25. Dimensions:
  26. 1. Allocator (min, max)
  27. Success cases
  28. - 0, 10
  29. - 0, 0
  30. - 0, UINT_MAX
  31. - UINT_MAX, UINT_MAX
  32. Failure cases
  33. - 10, 9
  34. - 1, 0
  35. - UINT_MAX, 0
  36. - UINT_MAX, UINT_MAX - 1
  37. 2. Span scenarios
  38. Generate some legal spans first:
  39. - randomly choose whether to reserve space at end for unbounded, reduce range by this value
  40. - few:
  41. set num = 5;
  42. add spans in order with random offsets from previous begin/end until full or num reached:
  43. offset = rand(1, space left)
  44. - lots:
  45. set num = min(range, 1000)
  46. add spans in order with random offsets from previous begin/end until full or num reached:
  47. offset = rand(1, min(space left, max(1, range / num)))
  48. Copy and shuffle spans
  49. Add spans to allocator, expect all success
  50. - randomly choose whether to attempt to add unbounded
  51. Should pass if space avail, fail if space filled
  52. Select starting and ending spans (one and two):
  53. - gather unique span cases:
  54. one = two = first
  55. one = two = second
  56. one = two = random
  57. one = two = last - 1
  58. one = two = last
  59. - add these if one < two:
  60. one = first, two = second
  61. one = first, two = last-1
  62. one = first, two = last
  63. one = first, two = random
  64. one = random, two = random
  65. one = random, two = last
  66. one = second, two = last-1
  67. one = second, two = last
  68. Add overlapping span, with start and end scenarios as follows:
  69. should have (one <= conflict && conflict <= two)
  70. for start:
  71. if prev = span before one:
  72. - prev.end < start, start < one.start
  73. else:
  74. - Min <= start, start < one.start
  75. - start == one.start
  76. - start > one.start, start < one.end
  77. - start == one.end
  78. for end (when start <= end, and unique from other cases):
  79. - end == max(start, two.start)
  80. - end > two.start, end < two.end
  81. - end == two.end
  82. if next = span after two:
  83. - end > two.end, end < next.start
  84. else:
  85. - end > two.end, end <= Max
  86. */
  87. // Modifies input pos and returns false on overflow, or exceeds max
  88. bool Align(unsigned &pos, unsigned end, unsigned align) {
  89. if (end < pos)
  90. return false;
  91. unsigned original = pos;
  92. unsigned rem = (1 < align) ? pos % align : 0;
  93. pos = rem ? pos + (align - rem) : pos;
  94. return original <= pos && pos <= end;
  95. }
  96. struct Element {
  97. Element(unsigned id, unsigned start, unsigned end) : id(id), start(start), end(end) {}
  98. bool operator<(const Element &other) { return id < other.id; }
  99. unsigned id; // index in original ordered vector
  100. unsigned start, end;
  101. };
  102. typedef std::vector<Element> ElementVector;
  103. typedef SpanAllocator<unsigned, Element> Allocator;
  104. struct IntersectionTestCase
  105. {
  106. IntersectionTestCase(unsigned one, unsigned two, unsigned start, unsigned end)
  107. : idOne(one), idTwo(two), element(UINT_MAX, start, end) {
  108. DXASSERT_NOMSG(one <= two && start <= end);
  109. }
  110. unsigned idOne, idTwo;
  111. Element element;
  112. bool operator<(const IntersectionTestCase &other) const {
  113. if (element.start < other.element.start)
  114. return true;
  115. else if (other.element.start < element.start)
  116. return false;
  117. if (element.end < other.element.end)
  118. return true;
  119. else if (other.element.end < element.end)
  120. return false;
  121. return false;
  122. }
  123. };
  124. typedef std::set<IntersectionTestCase> IntersectionSet;
  125. struct Gap {
  126. Gap(unsigned start, unsigned end, const Element *eBefore, const Element *eAfter)
  127. : start(start), end(end), sizeLess1(end-start), eBefore(eBefore), eAfter(eAfter) {
  128. }
  129. unsigned start, end;
  130. unsigned sizeLess1;
  131. const Element *eBefore = nullptr;
  132. const Element *eAfter = nullptr;
  133. };
  134. typedef std::vector<Gap> GapVector;
  135. const Gap* GetGapBeforeFirst(const GapVector &G) {
  136. if (!G.empty() && !G.front().eBefore)
  137. return &G.front();
  138. return nullptr;
  139. }
  140. const Gap* GetGapBetweenFirstAndSecond(const GapVector &G) {
  141. for (auto &gap : G) {
  142. if (gap.eBefore) {
  143. if (gap.eAfter)
  144. return &gap;
  145. break;
  146. }
  147. }
  148. return nullptr;
  149. }
  150. const Gap* GetGapBetweenLastAndSecondLast(const GapVector &G) {
  151. if (!G.empty()) {
  152. auto it = G.end();
  153. for (--it; it != G.begin(); --it) {
  154. const Gap &gap = *it;
  155. if (gap.eAfter) {
  156. if (gap.eBefore)
  157. return &gap;
  158. break;
  159. }
  160. }
  161. }
  162. return nullptr;
  163. }
  164. const Gap* GetGapAfterLast(const GapVector &G) {
  165. if (!G.empty() && !G.back().eAfter)
  166. return &G.back();
  167. return nullptr;
  168. }
  169. void GatherGaps(GapVector &gaps, const ElementVector &spans, unsigned Min, unsigned Max, unsigned alignment = 1) {
  170. unsigned start, end;
  171. const Element *eBefore = nullptr;
  172. const Element *eAfter = nullptr;
  173. // Gather gaps
  174. eBefore = nullptr;
  175. for (auto &&span : spans) {
  176. eAfter = &span;
  177. if (!eBefore) {
  178. start = Min;
  179. if (start < span.start) {
  180. end = span.start - 1; // can underflow, this is the first span, so guarded by if
  181. if (Align(start, end, alignment))
  182. gaps.emplace_back(start, end, eBefore, eAfter);
  183. }
  184. } else {
  185. start = eBefore->end + 1;
  186. end = span.start - 1; // can't underflow, this is the second span
  187. if (Align(start, end, alignment))
  188. gaps.emplace_back(start, end, eBefore, eAfter);
  189. }
  190. eBefore = &span;
  191. }
  192. eAfter = nullptr;
  193. if (!eBefore) {
  194. // No spans
  195. start = Min; end = Max;
  196. if (Align(start, end, alignment))
  197. gaps.emplace_back(start, end, eBefore, eAfter);
  198. } else if (eBefore->end < Max) {
  199. // gap at end
  200. start = eBefore->end + 1;
  201. end = Max;
  202. if (start <= end) {
  203. if (Align(start, end, alignment))
  204. gaps.emplace_back(start, end, eBefore, eAfter);
  205. }
  206. }
  207. }
  208. void GetGapExtremes(const GapVector &gaps, const Gap *&largest, const Gap *&smallest)
  209. {
  210. largest = nullptr;
  211. smallest = nullptr;
  212. for (auto &gap : gaps) {
  213. if (!largest || largest->sizeLess1 < gap.sizeLess1) {
  214. largest = &gap;
  215. }
  216. if (!smallest || smallest->sizeLess1 > gap.sizeLess1) {
  217. smallest = &gap;
  218. }
  219. }
  220. }
  221. const Gap *FindGap(const GapVector &gaps, unsigned sizeLess1) {
  222. if (sizeLess1 == UINT_MAX) {
  223. return GetGapAfterLast(gaps);
  224. } else {
  225. for (auto &gap : gaps) {
  226. if (gap.sizeLess1 >= sizeLess1)
  227. return &gap;
  228. }
  229. }
  230. return nullptr;
  231. }
  232. const Gap *NextGap(const GapVector &gaps, unsigned pos) {
  233. for (auto &gap : gaps) {
  234. if (gap.end < pos)
  235. continue;
  236. return &gap;
  237. }
  238. return nullptr;
  239. }
  240. // if rand() only uses 15 bits:
  241. //unsigned rand32() { return (rand() << 30) ^ (rand() << 15) ^ rand(); }
  242. struct Scenario {
  243. Scenario(unsigned Min, unsigned Max, unsigned MaxSpans, bool SpaceAtEnd, unsigned Seed)
  244. : Min(Min), Max(Max), randGen(Seed) {
  245. if (!MaxSpans || (SpaceAtEnd && Min == Max))
  246. return;
  247. spans.reserve(MaxSpans);
  248. {
  249. unsigned last = SpaceAtEnd ? Max - 1 : Max;
  250. unsigned next = Min;
  251. unsigned max_size = std::max((unsigned)(((int64_t)(last - next) + 1) / MaxSpans), (unsigned)1);
  252. unsigned offset;
  253. while (spans.size() < MaxSpans && next <= last) {
  254. if ((randGen() & 3) == 3) // 1 in 4 chance for adjacent span
  255. offset = 0;
  256. else
  257. offset = randGen() % max_size;
  258. unsigned start = next + offset;
  259. if (start > last || start < next) // overflow
  260. start = last;
  261. if ((randGen() & 3) == 3) // 1 in 4 chance for size 1 (start == end)
  262. offset = 0;
  263. else
  264. offset = randGen() % max_size;
  265. unsigned end = start + offset;
  266. if (end >= last || end < start) // overflow
  267. end = next = last;
  268. else
  269. next = end + 1;
  270. spans.emplace_back(spans.size(), start, end);
  271. if (end == last)
  272. break;
  273. }
  274. }
  275. if (spans.empty())
  276. return;
  277. shuffledSpans = spans;
  278. std::shuffle(shuffledSpans.begin(), shuffledSpans.end(), randGen);
  279. // Create conflict spans
  280. typedef std::pair<unsigned, unsigned> Test;
  281. // These are pairs of element indexes to construct intersecting spans from
  282. std::set<Test> pairs;
  283. unsigned maxIdx = spans.size() - 1;
  284. // - gather unique span cases:
  285. // one = two = first
  286. pairs.insert(Test(0, 0));
  287. // one = two = second
  288. if (maxIdx > 0) {
  289. pairs.insert(Test(1, 1));
  290. }
  291. // one = two = random
  292. if (maxIdx > 2) {
  293. unsigned randIdx = 1 + (randGen() % (maxIdx - 2));
  294. unsigned one = std::min(randIdx, maxIdx);
  295. pairs.insert(Test(one, one));
  296. }
  297. // one = two = last - 1
  298. if (maxIdx > 1) {
  299. pairs.insert(Test(maxIdx - 1, maxIdx - 1));
  300. }
  301. // one = two = last
  302. pairs.insert(Test(maxIdx, maxIdx));
  303. // - add these if one < two:
  304. // one = first, two = second
  305. if (maxIdx > 0) {
  306. pairs.insert(Test(0, 1));
  307. }
  308. // one = first, two = last-1
  309. if (maxIdx > 1) {
  310. pairs.insert(Test(0, maxIdx - 1));
  311. }
  312. // one = first, two = last
  313. if (maxIdx > 1) {
  314. pairs.insert(Test(0, maxIdx));
  315. }
  316. // one = first, two = random
  317. if (maxIdx > 3) {
  318. unsigned randIdx = 1 + (randGen() % (maxIdx - 2));
  319. unsigned two = std::min(randIdx, maxIdx);
  320. pairs.insert(Test(0, two));
  321. }
  322. // one = random, two = random
  323. if (maxIdx > 4) {
  324. unsigned randIdx = 1 + (randGen() % (maxIdx - 3));
  325. unsigned one = std::min(randIdx, maxIdx);
  326. randIdx = one + 1 + (randGen() % (maxIdx - (one + 1)));
  327. unsigned two = std::min(randIdx, maxIdx);
  328. pairs.insert(Test(one, two));
  329. }
  330. // one = random, two = last
  331. if (maxIdx > 3) {
  332. unsigned randIdx = 1 + (randGen() % (maxIdx - 2));
  333. unsigned one = std::min(randIdx, maxIdx);
  334. pairs.insert(Test(one, maxIdx));
  335. }
  336. // one = second, two = last-1
  337. if (maxIdx > 1) {
  338. pairs.insert(Test(1, maxIdx - 1));
  339. }
  340. // one = second, two = last
  341. if (maxIdx > 1) {
  342. pairs.insert(Test(1, maxIdx));
  343. }
  344. // These are start/end pairs that represent the intersecting spans that we will construct
  345. for (auto &&test : pairs) {
  346. // prev -> one -> ... -> two -> next
  347. // Where one and two are indexes into spans where one <= two
  348. // Where prev and next are only set if they exist
  349. const Element *prev = test.first ? &spans[test.first - 1] : nullptr;
  350. const Element *one = &spans[test.first];
  351. const Element *two = &spans[test.second];
  352. const Element *next = (test.second < spans.size() - 1) ? &spans[test.second + 1] : nullptr;
  353. unsigned start = 0;
  354. unsigned space = 0;
  355. // Function to add intersection tests, given start
  356. auto AddEnds = [&]() {
  357. // for end (when start <= end, and unique from other cases):
  358. // - end == max(start, two.start)
  359. unsigned end = std::max(start, two->start);
  360. intersectionTests.emplace(test.first, test.second, start, end);
  361. // - end > two.start, end < two.end
  362. if (end < two->end) {
  363. ++end;
  364. space = two->end - end;
  365. if (space > 1)
  366. end += randGen() % space;
  367. if (start <= end)
  368. intersectionTests.emplace(test.first, test.second, start, end);
  369. }
  370. // - end == two.end
  371. end = two->end;
  372. if (start <= end)
  373. intersectionTests.emplace(test.first, test.second, start, end);
  374. // if next = span after two:
  375. // - end > two.end, end < next.start
  376. // else:
  377. // - end > two.end, end <= Max
  378. space = (next ? next->start - 1 : Max) - two->end;
  379. if (space) {
  380. end = two->end + 1 + randGen() % space;
  381. if (start <= end)
  382. intersectionTests.emplace(test.first, test.second, start, end);
  383. }
  384. };
  385. // Add overlapping span, with start and end scenarios as follows:
  386. // should have (one <= conflict && conflict <= two)
  387. // for start:
  388. // if prev = span before one:
  389. // - prev.end < start, start < one.start
  390. // else:
  391. // - Min <= start, start < one.start
  392. if (prev)
  393. start = prev->end + 1;
  394. else
  395. start = Min;
  396. if (start < one->start) {
  397. space = one->start - start;
  398. if (space > 1)
  399. start += randGen() % space;
  400. AddEnds();
  401. }
  402. // - start == one.start
  403. start = one->start;
  404. AddEnds();
  405. // - start > one.start, start < one.end
  406. if (one->start < Max && one->start + 1 < one->end) {
  407. start = one->start + 1;
  408. AddEnds();
  409. }
  410. // - start == one.end
  411. start = one->end;
  412. AddEnds();
  413. }
  414. }
  415. void CreateGaps() {
  416. GatherGaps(gaps[1], spans, Min, Max, 1);
  417. GetGapExtremes(gaps[1], gapLargest[1], gapSmallest[1]);
  418. GatherGaps(gaps[4], spans, Min, Max, 4);
  419. GetGapExtremes(gaps[4], gapLargest[4], gapSmallest[4]);
  420. }
  421. bool InsertSpans(Allocator &alloc) {
  422. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  423. for (auto &it : shuffledSpans) {
  424. const Element *e = &it;
  425. const Element *conflict = alloc.Insert(e, e->start, e->end);
  426. VERIFY_ARE_EQUAL(conflict, nullptr);
  427. }
  428. return true;
  429. }
  430. bool VerifySpans(Allocator &alloc) {
  431. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  432. unsigned index = 0;
  433. unsigned last = Min;
  434. bool first = true;
  435. bool full = !alloc.GetSpans().empty();
  436. unsigned firstFree = Min;
  437. for (auto &span : alloc.GetSpans()) {
  438. VERIFY_IS_TRUE(Min <= span.start && span.start <= span.end && span.end <= Max);
  439. if (!first)
  440. ++last;
  441. VERIFY_IS_TRUE(last <= span.start);
  442. if (full && last < span.start) {
  443. full = false;
  444. firstFree = last;
  445. }
  446. // id == index in spans for original inserted elements only,
  447. // so skip test elements with UINT_MAX id
  448. if (span.element->id != UINT_MAX) {
  449. VERIFY_IS_TRUE(index == span.element->id);
  450. ++index;
  451. }
  452. VERIFY_IS_TRUE(span.start == span.element->start);
  453. VERIFY_IS_TRUE(span.end == span.element->end);
  454. last = span.end;
  455. first = false;
  456. }
  457. if (full && last < Max) {
  458. full = false;
  459. firstFree = last + 1;
  460. }
  461. if (full) {
  462. VERIFY_IS_TRUE(alloc.IsFull());
  463. } else {
  464. VERIFY_IS_FALSE(alloc.IsFull());
  465. VERIFY_IS_TRUE(alloc.GetFirstFree() == firstFree);
  466. }
  467. return true;
  468. }
  469. unsigned Min, Max;
  470. ElementVector spans;
  471. ElementVector shuffledSpans;
  472. IntersectionSet intersectionTests;
  473. // Gaps by alignment
  474. std::map<unsigned, GapVector> gaps;
  475. // Smallest gap by alignment
  476. std::map<unsigned, const Gap*> gapSmallest;
  477. // Largest gap by alignment
  478. std::map<unsigned, const Gap*> gapLargest;
  479. std::mt19937 randGen;
  480. };
  481. // The test fixture.
  482. #ifdef _WIN32
  483. class AllocatorTest {
  484. #else
  485. class AllocatorTest : public ::testing::Test {
  486. protected:
  487. #endif
  488. std::vector<Scenario> m_Scenarios;
  489. public:
  490. BEGIN_TEST_CLASS(AllocatorTest)
  491. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  492. TEST_METHOD_PROPERTY(L"Priority", L"0")
  493. END_TEST_CLASS()
  494. TEST_CLASS_SETUP(AllocatorTestSetup);
  495. TEST_METHOD(Intersections)
  496. TEST_METHOD(GapFilling)
  497. TEST_METHOD(Allocate)
  498. void InitScenarios() {
  499. struct P {
  500. unsigned Min, Max, MaxSpans;
  501. bool SpaceAtEnd;
  502. unsigned SeedOffset;
  503. };
  504. static const P params[] = {
  505. // Min, Max, MaxSpans, SpaceAtEnd, Seed
  506. // - 0, 0
  507. {0, 0, 1, false, 0},
  508. {0, 0, 1, true, 0},
  509. // - UINT_MAX, UINT_MAX
  510. {UINT_MAX, UINT_MAX, 1, false, 0},
  511. {UINT_MAX, UINT_MAX, 1, true, 0},
  512. // - small, small
  513. {0, 20, 5, false, 0},
  514. {0, 20, 5, true, 0},
  515. {21, 96, 5, false, 0},
  516. {21, 96, 5, true, 0},
  517. // - 0, UINT_MAX
  518. {0, UINT_MAX, 0, false, 0},
  519. {0, UINT_MAX, 10, false, 0},
  520. {0, UINT_MAX, 10, true, 0},
  521. {0, UINT_MAX, 100, false, 0},
  522. {0, UINT_MAX, 100, true, 0},
  523. };
  524. static const unsigned count = _countof(params);
  525. m_Scenarios.reserve(count);
  526. for (unsigned i = 0; i < count; ++i) {
  527. const P &p = params[i];
  528. m_Scenarios.emplace_back(p.Min, p.Max, p.MaxSpans, p.SpaceAtEnd, i + p.SeedOffset);
  529. m_Scenarios.back().CreateGaps();
  530. }
  531. }
  532. };
  533. bool AllocatorTest::AllocatorTestSetup() {
  534. InitScenarios();
  535. return true;
  536. }
  537. TEST_F(AllocatorTest, Intersections) {
  538. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  539. for (auto &&scenario : m_Scenarios) {
  540. Allocator alloc(scenario.Min, scenario.Max);
  541. VERIFY_IS_TRUE(scenario.InsertSpans(alloc));
  542. for (auto &&test : scenario.intersectionTests) {
  543. const Element &e = test.element;
  544. const Element *conflict = alloc.Insert(&e, e.start, e.end);
  545. VERIFY_IS_TRUE(conflict != nullptr);
  546. if (conflict) {
  547. VERIFY_IS_TRUE(conflict->id >= test.idOne);
  548. VERIFY_IS_TRUE(conflict->id <= test.idTwo);
  549. }
  550. }
  551. VERIFY_IS_TRUE(scenario.VerifySpans(alloc));
  552. }
  553. }
  554. TEST_F(AllocatorTest, GapFilling) {
  555. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  556. for (auto &&scenario : m_Scenarios) {
  557. // Fill all gaps with Insert, no alignment, verify first free advances and container is full at the end
  558. {
  559. //WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  560. Allocator alloc(scenario.Min, scenario.Max);
  561. VERIFY_IS_TRUE(scenario.InsertSpans(alloc));
  562. GapVector &gaps = scenario.gaps[1];
  563. for (auto &gap : gaps) {
  564. VERIFY_IS_FALSE(alloc.IsFull());
  565. VERIFY_ARE_EQUAL(alloc.GetFirstFree(), gap.start);
  566. Element e(UINT_MAX, gap.start, gap.end);
  567. VERIFY_IS_NULL(alloc.Insert(&e, gap.start, gap.end));
  568. }
  569. VERIFY_IS_TRUE(alloc.IsFull());
  570. }
  571. bool InsertSucceeded = true;
  572. VERIFY_IS_TRUE(InsertSucceeded);
  573. // Fill all gaps with Allocate, no alignment, verify first free advances and container is full at the end
  574. {
  575. //WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  576. Allocator alloc(scenario.Min, scenario.Max);
  577. VERIFY_IS_TRUE(scenario.InsertSpans(alloc));
  578. GapVector &gaps = scenario.gaps[1];
  579. for (auto &gap : gaps) {
  580. unsigned start = gap.start;
  581. unsigned end = gap.end;
  582. VERIFY_IS_FALSE(alloc.IsFull());
  583. VERIFY_ARE_EQUAL(alloc.GetFirstFree(), start);
  584. Element e(UINT_MAX, start, end);
  585. unsigned pos = 0xFEFEFEFE;
  586. if (gap.sizeLess1 < UINT_MAX) {
  587. VERIFY_IS_TRUE(alloc.Allocate(&e, gap.sizeLess1 + 1, pos));
  588. } else {
  589. const Element *unbounded = &e;
  590. VERIFY_IS_TRUE(alloc.AllocateUnbounded(unbounded, pos));
  591. VERIFY_ARE_EQUAL(alloc.GetUnbounded(), unbounded);
  592. }
  593. VERIFY_ARE_EQUAL(start, pos);
  594. }
  595. VERIFY_IS_TRUE(alloc.IsFull());
  596. }
  597. bool AllocSucceeded = true;
  598. VERIFY_IS_TRUE(AllocSucceeded);
  599. }
  600. }
  601. TEST_F(AllocatorTest, Allocate) {
  602. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  603. for (auto &&scenario : m_Scenarios) {
  604. // Test for alignment 1 (no alignment), then alignment 4
  605. unsigned alignment = 1;
  606. const GapVector *pGaps = &scenario.gaps[alignment];
  607. const Gap *largestGap = scenario.gapLargest[alignment];
  608. const Gap *smallestGap = scenario.gapSmallest[alignment];
  609. // Test a particular allocation size with some alignment
  610. auto TestFn = [&](unsigned sizeLess1){
  611. DXASSERT_NOMSG(pGaps);
  612. const Gap* pEndGap = GetGapAfterLast(*pGaps);
  613. Allocator alloc(scenario.Min, scenario.Max);
  614. VERIFY_IS_TRUE(scenario.InsertSpans(alloc));
  615. if (!largestGap || // no gaps
  616. (sizeLess1 < UINT_MAX && sizeLess1 > largestGap->sizeLess1) || // not unbounded and size too large
  617. (sizeLess1 == UINT_MAX && !pEndGap)) { // unbounded and no end gap
  618. // no large enough gap, should fail to allocate
  619. Element e(UINT_MAX, 0, 0);
  620. unsigned pos = 0xFEFEFEFE;
  621. if (sizeLess1 == UINT_MAX) {
  622. VERIFY_IS_FALSE(alloc.AllocateUnbounded(&e, pos, alignment));
  623. } else {
  624. VERIFY_IS_FALSE(alloc.Allocate(&e, sizeLess1 + 1, pos, alignment));
  625. }
  626. } else {
  627. // large enough gap to allocate, verify:
  628. // - allocation occurs where expected
  629. // - firstFree is advanced if necessary
  630. // - container is marked full if necessary (VerifySpans should do this)
  631. unsigned firstFree = alloc.GetFirstFree();
  632. const Gap *expectedGap = FindGap(*pGaps, sizeLess1);
  633. DXASSERT_NOMSG(expectedGap);
  634. unsigned start = expectedGap->start;
  635. unsigned end = expectedGap->start + sizeLess1;
  636. Element e(UINT_MAX, start, end);
  637. unsigned pos = 0xFEFEFEFE;
  638. if (sizeLess1 == UINT_MAX) {
  639. e.end = expectedGap->end;
  640. VERIFY_IS_TRUE(alloc.AllocateUnbounded(&e, pos, alignment));
  641. } else {
  642. VERIFY_IS_TRUE(alloc.Allocate(&e, sizeLess1 + 1, pos, alignment));
  643. }
  644. VERIFY_IS_TRUE(pos == start);
  645. if (start <= firstFree && firstFree <= end) {
  646. if (end < expectedGap->end) {
  647. VERIFY_IS_FALSE(alloc.IsFull());
  648. VERIFY_IS_TRUE(alloc.GetFirstFree() == end + 1);
  649. }
  650. }
  651. }
  652. VERIFY_IS_TRUE(scenario.VerifySpans(alloc));
  653. };
  654. auto TestSizesFn = [&] {
  655. DXASSERT_NOMSG(pGaps);
  656. const Gap* pStartGap = GetGapBeforeFirst(*pGaps);
  657. const Gap* pGap1 = GetGapBetweenFirstAndSecond(*pGaps);
  658. // pass/fail based on fit
  659. // allocate different sizes (in sizeLess1, UINT_MAX means unbounded):
  660. std::set<unsigned> sizes;
  661. // - size 1
  662. sizes.insert(0);
  663. // - size 2
  664. sizes.insert(1);
  665. // - Unbounded
  666. sizes.insert(UINT_MAX);
  667. // - size == smallest gap
  668. if (smallestGap)
  669. sizes.insert(smallestGap->sizeLess1);
  670. // - size == largest gap
  671. if (largestGap && largestGap->sizeLess1 < UINT_MAX)
  672. sizes.insert(largestGap->sizeLess1);
  673. // - size == largest gap + 1
  674. if (largestGap && largestGap->sizeLess1 < UINT_MAX - 1)
  675. sizes.insert(largestGap->sizeLess1 + 1);
  676. // - size > gap before first span if largest gap is large enough
  677. if (pStartGap && pStartGap->sizeLess1 < largestGap->sizeLess1)
  678. sizes.insert(pStartGap->sizeLess1 + 1);
  679. // - size > gap before first span and size > first gap between spans if largest gap is large enough
  680. if (pStartGap && pStartGap->sizeLess1 < largestGap->sizeLess1 &&
  681. pGap1 && pGap1->sizeLess1 < largestGap->sizeLess1)
  682. sizes.insert(std::max(pStartGap->sizeLess1, pGap1->sizeLess1) + 1);
  683. for (auto &size : sizes) {
  684. TestFn(size);
  685. }
  686. };
  687. // Test without alignment
  688. TestSizesFn();
  689. // again with alignment
  690. alignment = 4;
  691. pGaps = &scenario.gaps[alignment];
  692. largestGap = scenario.gapLargest[alignment];
  693. smallestGap = scenario.gapSmallest[alignment];
  694. TestSizesFn();
  695. }
  696. }