No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NativeListTests_JobDebugger.cs 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. using UnityEngine;
  2. using NUnit.Framework;
  3. using System;
  4. using Unity.Jobs;
  5. using Unity.Burst;
  6. using Unity.Collections;
  7. using Unity.Collections.NotBurstCompatible;
  8. using Unity.Collections.Tests;
  9. #pragma warning disable 0219
  10. #pragma warning disable 0414
  11. internal class NativeListJobDebuggerTests : CollectionsTestFixture
  12. {
  13. [BurstCompile(CompileSynchronously = true)]
  14. struct NativeListAddJob : IJob
  15. {
  16. NativeList<int> list;
  17. public NativeListAddJob(NativeList<int> list) { this.list = list; }
  18. public void Execute()
  19. {
  20. list.Add(1);
  21. }
  22. }
  23. [BurstCompile(CompileSynchronously = true)]
  24. struct NativeArrayTest : IJob
  25. {
  26. NativeArray<int> array;
  27. public NativeArrayTest(NativeArray<int> array) { this.array = array; }
  28. public void Execute()
  29. {
  30. }
  31. }
  32. [Test]
  33. public void AddElementToListFromJobInvalidatesArray()
  34. {
  35. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  36. list.Add(0);
  37. NativeArray<int> arrayBeforeSchedule = list;
  38. Assert.AreEqual(list.Length, 1);
  39. var jobData = new NativeListAddJob(list);
  40. var job = jobData.Schedule();
  41. Assert.Throws<ObjectDisposedException>(
  42. () => {
  43. int readVal = arrayBeforeSchedule[0];
  44. });
  45. Assert.Throws<InvalidOperationException>(() => { NativeArray<int> array = list; Debug.Log(array.Length); });
  46. Assert.Throws<InvalidOperationException>(() => { int readVal = list.Capacity; });
  47. Assert.Throws<InvalidOperationException>(() => { list.Dispose(); });
  48. Assert.Throws<InvalidOperationException>(() => { int readVal = list[0]; });
  49. job.Complete();
  50. // Assert.AreEqual(1, arrayBeforeSchedule.Length); - temporarily commenting out updated assert checks to ensure editor version promotion succeeds
  51. Assert.Throws<ObjectDisposedException>(
  52. () => {
  53. int readVal = arrayBeforeSchedule[0];
  54. });
  55. Assert.AreEqual(2, list.Length);
  56. Assert.AreEqual(0, list[0]);
  57. Assert.AreEqual(1, list[1]);
  58. NativeArray<int> arrayAfter = list;
  59. Assert.AreEqual(2, arrayAfter.Length);
  60. Assert.AreEqual(0, arrayAfter[0]);
  61. Assert.AreEqual(1, arrayAfter[1]);
  62. list.Dispose();
  63. }
  64. [Test]
  65. public void AccessBefore()
  66. {
  67. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  68. var jobHandle = new NativeListAddJob(list).Schedule();
  69. Assert.Throws<InvalidOperationException>(() =>
  70. {
  71. list.AsArray();
  72. });
  73. jobHandle.Complete();
  74. list.Dispose();
  75. }
  76. [Test]
  77. public void AccessAfter()
  78. {
  79. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  80. var array = list.AsArray();
  81. var jobHandle = new NativeListAddJob(list).Schedule();
  82. Assert.Throws<InvalidOperationException>(() =>
  83. {
  84. new NativeArrayTest(array).Schedule(jobHandle);
  85. });
  86. jobHandle.Complete();
  87. list.Dispose();
  88. }
  89. [Test]
  90. public void ScheduleDerivedArrayAllowDerivingArrayAgain()
  91. {
  92. var list = new NativeList<int>(1, Allocator.Persistent);
  93. // The scheduled job only receives a NativeArray thus it can't be resized
  94. var writeJobHandle = new NativeArrayTest(list).Schedule();
  95. // For that reason casting here is legal, as opposed to AddElementToListFromJobInvalidatesArray case where it is not legal
  96. // Since we NativeList is passed to the job
  97. #pragma warning disable 0219 // assigned but its value is never used
  98. NativeArray<int> array = list;
  99. #pragma warning restore 0219
  100. list.Dispose(writeJobHandle);
  101. }
  102. [Test]
  103. public void ScheduleDerivedArrayExceptions()
  104. {
  105. var list = new NativeList<int>(1, Allocator.Persistent);
  106. var addListJobHandle = new NativeListAddJob(list).Schedule();
  107. #pragma warning disable 0219 // assigned but its value is never used
  108. Assert.Throws<InvalidOperationException>(() => { NativeArray<int> array = list; });
  109. #pragma warning restore 0219
  110. addListJobHandle.Complete();
  111. list.Dispose();
  112. }
  113. [Test]
  114. public void ScheduleDerivedArrayExceptions2()
  115. {
  116. var list = new NativeList<int>(1, Allocator.Persistent);
  117. NativeArray<int> array = list;
  118. var addListJobHandle = new NativeListAddJob(list).Schedule();
  119. // The array previously cast should become invalid
  120. // as soon as the job is scheduled, since we can't predict if an element will be added or not
  121. Assert.Throws<InvalidOperationException>(() => { new NativeArrayTest(array).Schedule(); });
  122. addListJobHandle.Complete();
  123. list.Dispose();
  124. }
  125. [BurstCompile(CompileSynchronously = true)]
  126. struct ReadOnlyListAccess : IJob
  127. {
  128. [ReadOnly]
  129. NativeList<int> list;
  130. public ReadOnlyListAccess(NativeList<int> list) { this.list = list; }
  131. public void Execute()
  132. {
  133. }
  134. }
  135. [Test]
  136. public void ReadOnlyListInJobKeepsAsArrayValid()
  137. {
  138. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  139. list.Add(0);
  140. var arrayBeforeSchedule = list.AsArray();
  141. var jobData = new ReadOnlyListAccess(list);
  142. var job = jobData.Schedule();
  143. job.Complete();
  144. Assert.AreEqual(0, arrayBeforeSchedule[0]);
  145. list.Dispose();
  146. }
  147. [Test]
  148. public void AsArrayJobKeepsAsArrayValid()
  149. {
  150. var list = new NativeList<int>(CommonRwdAllocator.Handle);
  151. list.Add(0);
  152. var arrayBeforeSchedule = list.AsArray();
  153. var jobData = new NativeArrayTest(list);
  154. var job = jobData.Schedule();
  155. job.Complete();
  156. Assert.AreEqual(0, arrayBeforeSchedule[0]);
  157. list.Dispose();
  158. }
  159. [BurstCompile(CompileSynchronously = true)]
  160. struct NativeListToArrayConversionFromJob : IJob
  161. {
  162. public NativeList<int> list;
  163. public void Execute()
  164. {
  165. list.Add(0);
  166. list.Add(0);
  167. NativeArray<int> arr = list;
  168. arr[0] = 1;
  169. arr[1] = 2;
  170. }
  171. }
  172. [Test]
  173. public void CastListToArrayInsideJob()
  174. {
  175. var jobData = new NativeListToArrayConversionFromJob();
  176. jobData.list = new NativeList<int>(1, Allocator.Persistent);
  177. jobData.Schedule().Complete();
  178. Assert.AreEqual(new int[] { 1, 2 }, jobData.list.ToArrayNBC());
  179. jobData.list.Dispose();
  180. }
  181. [BurstCompile(CompileSynchronously = true)]
  182. struct WriteJob : IJobParallelFor
  183. {
  184. public NativeArray<float> output;
  185. public void Execute(int i)
  186. {
  187. output[i] = i;
  188. }
  189. }
  190. [Test]
  191. public void WriteToArrayFromJobThenReadListFromMainThread()
  192. {
  193. var list = new NativeList<float>(1, Allocator.Persistent);
  194. list.Add(0);
  195. list.Add(1);
  196. for (int i = 0; i < 2; i++)
  197. {
  198. var writeJob = new WriteJob();
  199. writeJob.output = list;
  200. var writeJobHandle = writeJob.Schedule(list.Length, 1);
  201. Assert.Throws<InvalidOperationException>(() => { float val = writeJob.output[0]; });
  202. writeJobHandle.Complete();
  203. }
  204. list.Dispose();
  205. }
  206. [Test]
  207. public void NativeList_DisposeJob()
  208. {
  209. var list = new NativeList<int>(Allocator.Persistent);
  210. var deps = new NativeListAddJob(list).Schedule();
  211. deps = list.Dispose(deps);
  212. Assert.IsFalse(list.IsCreated);
  213. deps.Complete();
  214. }
  215. [Test]
  216. public void NativeList_DisposeJobWithMissingDependencyThrows()
  217. {
  218. var list = new NativeList<int>(Allocator.Persistent);
  219. var deps = new NativeListAddJob(list).Schedule();
  220. Assert.Throws<InvalidOperationException>(() => { list.Dispose(default); });
  221. deps.Complete();
  222. list.Dispose();
  223. }
  224. [Test]
  225. public void NativeList_DisposeJobCantBeScheduled()
  226. {
  227. var list = new NativeList<int>(Allocator.Persistent);
  228. var deps = list.Dispose(default);
  229. Assert.Throws<InvalidOperationException>(() => { new NativeListAddJob(list).Schedule(deps); });
  230. deps.Complete();
  231. }
  232. // error BC1071: Unsupported assert type
  233. // [BurstCompile(CompileSynchronously = true)]
  234. struct InvalidArrayAccessFromListJob : IJob
  235. {
  236. public NativeList<int> list;
  237. public void Execute()
  238. {
  239. list.Add(1);
  240. NativeArray<int> array = list;
  241. list.Add(2);
  242. // Assert.Throws<InvalidOperationException>(() => { array[0] = 5; }); - temporarily commenting out updated assert checks to ensure editor version promotion succeeds
  243. }
  244. }
  245. [Test]
  246. public void InvalidatedArrayAccessFromListThrowsInsideJob()
  247. {
  248. var job = new InvalidArrayAccessFromListJob { list = new NativeList<int>(CommonRwdAllocator.Handle) };
  249. job.Schedule().Complete();
  250. job.list.Dispose();
  251. }
  252. [Test]
  253. public void DisposeAliasedArrayDoesNotThrow()
  254. {
  255. var list = new NativeList<int>(Allocator.Persistent);
  256. var array = list.AsArray();
  257. Assert.DoesNotThrow(() => { array.Dispose(); });
  258. list.Dispose();
  259. }
  260. // Burst error BC1071: Unsupported assert type
  261. // [BurstCompile(CompileSynchronously = true)]
  262. struct NativeArrayTestReadOnly : IJob
  263. {
  264. [ReadOnly]
  265. NativeArray<int> array;
  266. public NativeArrayTestReadOnly(NativeArray<int> array) { this.array = array; }
  267. public void Execute()
  268. {
  269. var arr = array;
  270. Assert.Throws<InvalidOperationException>(() => { arr[0] = 5; });
  271. Assert.AreEqual(7, array[0]);
  272. }
  273. }
  274. [Test]
  275. public void ReadOnlyAliasedArrayThrows()
  276. {
  277. var list = new NativeList<int>(Allocator.Persistent);
  278. list.Add(7);
  279. new NativeArrayTestReadOnly(list).Schedule().Complete();
  280. list.Dispose();
  281. }
  282. // Burst error BC1071: Unsupported assert type
  283. // [BurstCompile(CompileSynchronously = true)]
  284. struct NativeArrayTestWriteOnly : IJob
  285. {
  286. [WriteOnly]
  287. NativeArray<int> array;
  288. public NativeArrayTestWriteOnly(NativeArray<int> array) { this.array = array; }
  289. public void Execute()
  290. {
  291. var arr = array;
  292. Assert.Throws<InvalidOperationException>(() => { int read = arr[0]; });
  293. arr[0] = 7;
  294. }
  295. }
  296. [Test]
  297. public void NativeList_AsArray_Jobs()
  298. {
  299. var list = new NativeList<int>(Allocator.Persistent);
  300. list.Add(0);
  301. var writer = list.AsArray();
  302. var writerJob = new NativeArrayTestWriteOnly(writer).Schedule();
  303. var reader = list.AsArray();
  304. var readerJob = new NativeArrayTestReadOnly(reader).Schedule(writerJob);
  305. // Tests that read only container safety check trows...
  306. var writerJob2 = new NativeArrayTestWriteOnly(reader).Schedule(readerJob);
  307. // Tests that write only container safety check trows...
  308. var readerJob2 = new NativeArrayTestReadOnly(writer).Schedule(writerJob2);
  309. readerJob2.Complete();
  310. list.Dispose();
  311. }
  312. // Burst error BC1071: Unsupported assert type
  313. // [BurstCompile(CompileSynchronously = true)]
  314. struct NativeListTestParallelReader : IJob
  315. {
  316. [ReadOnly]
  317. public NativeArray<int>.ReadOnly reader;
  318. public void Execute()
  319. {
  320. Assert.True(reader.Contains(7));
  321. Assert.AreEqual(7, reader[0]);
  322. }
  323. }
  324. [Test]
  325. public void NativeList_ParallelReader()
  326. {
  327. NativeList<int> list;
  328. JobHandle readerJob;
  329. {
  330. list = new NativeList<int>(Allocator.Persistent);
  331. list.Add(7);
  332. var reader = list.AsParallelReader();
  333. list.Dispose(); // <- cause invalid use
  334. Assert.Throws<InvalidOperationException>(() => { readerJob = new NativeListTestParallelReader { reader = reader }.Schedule(); });
  335. }
  336. {
  337. list = new NativeList<int>(Allocator.Persistent);
  338. list.Add(7);
  339. var reader = list.AsParallelReader();
  340. readerJob = new NativeListTestParallelReader { reader = reader }.Schedule();
  341. }
  342. list.Dispose(readerJob);
  343. readerJob.Complete();
  344. }
  345. [BurstCompile(CompileSynchronously = true)]
  346. struct NativeListTestParallelWriter : IJob
  347. {
  348. [WriteOnly]
  349. public NativeList<int>.ParallelWriter writer;
  350. public unsafe void Execute()
  351. {
  352. var range = stackalloc int[2] { 7, 3 };
  353. writer.AddNoResize(range[0]);
  354. writer.AddRangeNoResize(range, 1);
  355. }
  356. }
  357. [Test]
  358. public void NativeList_ParallelWriter()
  359. {
  360. NativeList<int> list;
  361. {
  362. list = new NativeList<int>(2, Allocator.Persistent);
  363. var writer = list.AsParallelWriter();
  364. list.Dispose(); // <- cause invalid use
  365. Assert.Throws<InvalidOperationException>(() =>
  366. {
  367. var writerJob = new NativeListTestParallelWriter { writer = writer }.Schedule();
  368. writerJob.Complete();
  369. });
  370. }
  371. {
  372. list = new NativeList<int>(2, Allocator.Persistent);
  373. var writer = list.AsParallelWriter();
  374. var writerJob = new NativeListTestParallelWriter { writer = writer }.Schedule();
  375. writerJob.Complete();
  376. }
  377. Assert.AreEqual(2, list.Length);
  378. Assert.AreEqual(7, list[0]);
  379. Assert.AreEqual(7, list[1]);
  380. list.Dispose();
  381. }
  382. [Test]
  383. public void NativeList_ParallelWriter_NoPtrCaching()
  384. {
  385. NativeList<int> list;
  386. {
  387. list = new NativeList<int>(2, Allocator.Persistent);
  388. var writer = list.AsParallelWriter();
  389. list.Capacity = 100;
  390. var writerJob = new NativeListTestParallelWriter { writer = writer }.Schedule();
  391. writerJob.Complete();
  392. }
  393. Assert.AreEqual(2, list.Length);
  394. Assert.AreEqual(7, list[0]);
  395. Assert.AreEqual(7, list[1]);
  396. list.Dispose();
  397. }
  398. [Test]
  399. public void NativeList_ParallelReaderWriter()
  400. {
  401. NativeList<int> list;
  402. JobHandle jobHandle;
  403. list = new NativeList<int>(Allocator.Persistent);
  404. list.Add(7);
  405. jobHandle = new NativeListTestParallelReader { reader = list.AsParallelReader() }.Schedule();
  406. jobHandle = new NativeListTestParallelWriter { writer = list.AsParallelWriter() }.Schedule(jobHandle);
  407. jobHandle = new NativeListTestParallelReader { reader = list.AsParallelReader() }.Schedule(jobHandle);
  408. jobHandle = new NativeListTestParallelWriter { writer = list.AsParallelWriter() }.Schedule(jobHandle);
  409. list.Dispose(jobHandle);
  410. jobHandle.Complete();
  411. }
  412. unsafe void Expected(ref NativeList<int> list, int expectedLength, int[] expected)
  413. {
  414. Assert.AreEqual(0 == expectedLength, list.IsEmpty);
  415. Assert.AreEqual(list.Length, expectedLength);
  416. for (var i = 0; i < list.Length; ++i)
  417. {
  418. var value = list[i];
  419. Assert.AreEqual(expected[i], value);
  420. }
  421. }
  422. [Test]
  423. public unsafe void NativeList_RemoveRange()
  424. {
  425. var list = new NativeList<int>(10, Allocator.Persistent);
  426. int[] range = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  427. // test removing from the end
  428. fixed (int* r = range) list.AddRange(r, 10);
  429. list.RemoveRange(6, 3);
  430. Expected(ref list, 7, new int[] { 0, 1, 2, 3, 4, 5, 9 });
  431. list.Clear();
  432. // test removing all but one
  433. fixed (int* r = range) list.AddRange(r, 10);
  434. list.RemoveRange(0, 9);
  435. Expected(ref list, 1, new int[] { 9 });
  436. list.Clear();
  437. // test removing from the front
  438. fixed (int* r = range) list.AddRange(r, 10);
  439. list.RemoveRange(0, 3);
  440. Expected(ref list, 7, new int[] { 3, 4, 5, 6, 7, 8, 9 });
  441. list.Clear();
  442. // test removing from the middle
  443. fixed (int* r = range) list.AddRange(r, 10);
  444. list.RemoveRange(0, 3);
  445. Expected(ref list, 7, new int[] { 3, 4, 5, 6, 7, 8, 9 });
  446. list.Clear();
  447. // test removing whole range
  448. fixed (int* r = range) list.AddRange(r, 10);
  449. list.RemoveRange(0, 10);
  450. Expected(ref list, 0, new int[] { 0 });
  451. list.Clear();
  452. list.Dispose();
  453. }
  454. }