1
0

benchmark.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  1. #include <chrono>
  2. #include <cstdint>
  3. #include <iostream>
  4. #include <utility>
  5. #include <vector>
  6. #include <gtest/gtest.h>
  7. #include <entt/core/algorithm.hpp>
  8. #include <entt/entity/mixin.hpp>
  9. #include <entt/entity/registry.hpp>
  10. #include <entt/entity/runtime_view.hpp>
  11. #include <entt/entity/storage.hpp>
  12. #include <entt/entity/view.hpp>
  13. struct position {
  14. std::uint64_t x;
  15. std::uint64_t y;
  16. };
  17. struct velocity: position {};
  18. struct stable_position: position {
  19. static constexpr auto in_place_delete = true;
  20. };
  21. template<auto>
  22. struct comp {
  23. int x;
  24. };
  25. struct timer final {
  26. timer()
  27. : start{std::chrono::system_clock::now()} {}
  28. void elapsed() {
  29. auto now = std::chrono::system_clock::now();
  30. std::cout << std::chrono::duration<double>(now - start).count() << " seconds" << std::endl;
  31. }
  32. private:
  33. std::chrono::time_point<std::chrono::system_clock> start;
  34. };
  35. template<typename Func, typename... Args>
  36. void generic_with(Func func) {
  37. timer timer;
  38. func();
  39. timer.elapsed();
  40. }
  41. template<typename Iterable, typename Func>
  42. void iterate_with(Iterable &&iterable, Func func) {
  43. timer timer;
  44. std::forward<Iterable>(iterable).each(func);
  45. timer.elapsed();
  46. }
  47. template<typename Func>
  48. void pathological_with(Func func) {
  49. entt::registry registry;
  50. auto view = func(registry);
  51. for(std::uint64_t i = 0; i < 500000L; i++) {
  52. const auto entt = registry.create();
  53. registry.emplace<position>(entt);
  54. registry.emplace<velocity>(entt);
  55. registry.emplace<comp<0>>(entt);
  56. }
  57. for(auto i = 0; i < 10; ++i) {
  58. auto curr = 0;
  59. for(auto [entt]: registry.storage<entt::entity>().each()) {
  60. if(!(++curr % 7)) {
  61. registry.remove<position>(entt);
  62. }
  63. if(!(++curr % 11)) {
  64. registry.remove<velocity>(entt);
  65. }
  66. if(!(++curr % 13)) {
  67. registry.remove<comp<0>>(entt);
  68. }
  69. if(!(++curr % 17)) {
  70. registry.destroy(entt);
  71. }
  72. }
  73. for(std::uint64_t j = 0; j < 50000L; j++) {
  74. const auto entt = registry.create();
  75. registry.emplace<position>(entt);
  76. registry.emplace<velocity>(entt);
  77. registry.emplace<comp<0>>(entt);
  78. }
  79. }
  80. timer timer;
  81. view.each([](auto &...comp) { ((comp.x = {}), ...); });
  82. timer.elapsed();
  83. }
  84. TEST(Benchmark, Create) {
  85. entt::registry registry;
  86. std::cout << "Creating 1000000 entities" << std::endl;
  87. generic_with([&]() {
  88. for(std::uint64_t i = 0; i < 1000000L; i++) {
  89. static_cast<void>(registry.create());
  90. }
  91. });
  92. }
  93. TEST(Benchmark, CreateMany) {
  94. entt::registry registry;
  95. std::vector<entt::entity> entity(1000000);
  96. std::cout << "Creating 1000000 entities at once" << std::endl;
  97. generic_with([&]() {
  98. registry.create(entity.begin(), entity.end());
  99. });
  100. }
  101. TEST(Benchmark, CreateManyAndEmplaceComponents) {
  102. entt::registry registry;
  103. std::vector<entt::entity> entity(1000000);
  104. std::cout << "Creating 1000000 entities at once and emplace components" << std::endl;
  105. generic_with([&]() {
  106. registry.create(entity.begin(), entity.end());
  107. for(const auto entt: entity) {
  108. registry.emplace<position>(entt);
  109. registry.emplace<velocity>(entt);
  110. }
  111. });
  112. }
  113. TEST(Benchmark, CreateManyWithComponents) {
  114. entt::registry registry;
  115. std::vector<entt::entity> entity(1000000);
  116. std::cout << "Creating 1000000 entities at once with components" << std::endl;
  117. generic_with([&]() {
  118. registry.create(entity.begin(), entity.end());
  119. registry.insert<position>(entity.begin(), entity.end());
  120. registry.insert<velocity>(entity.begin(), entity.end());
  121. });
  122. }
  123. TEST(Benchmark, Erase) {
  124. entt::registry registry;
  125. std::vector<entt::entity> entity(1000000);
  126. auto view = registry.view<position>();
  127. std::cout << "Erasing 1000000 components from their entities" << std::endl;
  128. registry.create(entity.begin(), entity.end());
  129. registry.insert<position>(entity.begin(), entity.end());
  130. generic_with([&]() {
  131. for(auto entt: view) {
  132. registry.erase<position>(entt);
  133. }
  134. });
  135. }
  136. TEST(Benchmark, EraseMany) {
  137. entt::registry registry;
  138. std::vector<entt::entity> entity(1000000);
  139. auto view = registry.view<position>();
  140. std::cout << "Erasing 1000000 components from their entities at once" << std::endl;
  141. registry.create(entity.begin(), entity.end());
  142. registry.insert<position>(entity.begin(), entity.end());
  143. generic_with([&]() {
  144. registry.erase<position>(view.begin(), view.end());
  145. });
  146. }
  147. TEST(Benchmark, EraseManyMulti) {
  148. entt::registry registry;
  149. std::vector<entt::entity> entity(1000000);
  150. auto view = registry.view<position>();
  151. std::cout << "Erasing 1000000 components per type from their entities at once" << std::endl;
  152. registry.create(entity.begin(), entity.end());
  153. registry.insert<position>(entity.begin(), entity.end());
  154. registry.insert<velocity>(entity.begin(), entity.end());
  155. generic_with([&]() {
  156. registry.erase<position, velocity>(view.begin(), view.end());
  157. });
  158. }
  159. TEST(Benchmark, Remove) {
  160. entt::registry registry;
  161. std::vector<entt::entity> entity(1000000);
  162. auto view = registry.view<position>();
  163. std::cout << "Removing 1000000 components from their entities" << std::endl;
  164. registry.create(entity.begin(), entity.end());
  165. registry.insert<position>(entity.begin(), entity.end());
  166. generic_with([&]() {
  167. for(auto entt: view) {
  168. registry.remove<position>(entt);
  169. }
  170. });
  171. }
  172. TEST(Benchmark, RemoveMany) {
  173. entt::registry registry;
  174. std::vector<entt::entity> entity(1000000);
  175. auto view = registry.view<position>();
  176. std::cout << "Removing 1000000 components from their entities at once" << std::endl;
  177. registry.create(entity.begin(), entity.end());
  178. registry.insert<position>(entity.begin(), entity.end());
  179. generic_with([&]() {
  180. registry.remove<position>(view.begin(), view.end());
  181. });
  182. }
  183. TEST(Benchmark, RemoveManyMulti) {
  184. entt::registry registry;
  185. std::vector<entt::entity> entity(1000000);
  186. auto view = registry.view<position>();
  187. std::cout << "Removing 1000000 components per type from their entities at once" << std::endl;
  188. registry.create(entity.begin(), entity.end());
  189. registry.insert<position>(entity.begin(), entity.end());
  190. registry.insert<velocity>(entity.begin(), entity.end());
  191. generic_with([&]() {
  192. registry.remove<position, velocity>(view.begin(), view.end());
  193. });
  194. }
  195. TEST(Benchmark, Clear) {
  196. entt::registry registry;
  197. std::vector<entt::entity> entity(1000000);
  198. std::cout << "Clearing 1000000 components from their entities" << std::endl;
  199. registry.create(entity.begin(), entity.end());
  200. registry.insert<position>(entity.begin(), entity.end());
  201. generic_with([&]() {
  202. registry.clear<position>();
  203. });
  204. }
  205. TEST(Benchmark, ClearMulti) {
  206. entt::registry registry;
  207. std::vector<entt::entity> entity(1000000);
  208. std::cout << "Clearing 1000000 components per type from their entities" << std::endl;
  209. registry.create(entity.begin(), entity.end());
  210. registry.insert<position>(entity.begin(), entity.end());
  211. registry.insert<velocity>(entity.begin(), entity.end());
  212. generic_with([&]() {
  213. registry.clear<position, velocity>();
  214. });
  215. }
  216. TEST(Benchmark, ClearStable) {
  217. entt::registry registry;
  218. std::vector<entt::entity> entity(1000000);
  219. std::cout << "Clearing 1000000 stable components from their entities" << std::endl;
  220. registry.create(entity.begin(), entity.end());
  221. registry.insert<stable_position>(entity.begin(), entity.end());
  222. generic_with([&]() {
  223. registry.clear<stable_position>();
  224. });
  225. }
  226. TEST(Benchmark, Recycle) {
  227. entt::registry registry;
  228. std::vector<entt::entity> entity(1000000);
  229. std::cout << "Recycling 1000000 entities" << std::endl;
  230. registry.create(entity.begin(), entity.end());
  231. registry.destroy(entity.begin(), entity.end());
  232. generic_with([&]() {
  233. for(auto next = entity.size(); next; --next) {
  234. entity[next] = registry.create();
  235. }
  236. });
  237. }
  238. TEST(Benchmark, RecycleMany) {
  239. entt::registry registry;
  240. std::vector<entt::entity> entity(1000000);
  241. std::cout << "Recycling 1000000 entities" << std::endl;
  242. registry.create(entity.begin(), entity.end());
  243. registry.destroy(entity.begin(), entity.end());
  244. generic_with([&]() {
  245. registry.create(entity.begin(), entity.end());
  246. });
  247. }
  248. TEST(Benchmark, Destroy) {
  249. entt::registry registry;
  250. std::vector<entt::entity> entity(1000000);
  251. auto view = registry.view<position>();
  252. std::cout << "Destroying 1000000 entities" << std::endl;
  253. registry.create(entity.begin(), entity.end());
  254. registry.insert<position>(entity.begin(), entity.end());
  255. generic_with([&]() {
  256. for(auto entt: view) {
  257. registry.destroy(entt);
  258. }
  259. });
  260. }
  261. TEST(Benchmark, DestroyMany) {
  262. entt::registry registry;
  263. std::vector<entt::entity> entity(1000000);
  264. auto view = registry.view<position>();
  265. std::cout << "Destroying 1000000 entities at once" << std::endl;
  266. registry.create(entity.begin(), entity.end());
  267. registry.insert<position>(entity.begin(), entity.end());
  268. generic_with([&]() {
  269. registry.destroy(view.begin(), view.end());
  270. });
  271. }
  272. TEST(Benchmark, DestroyManyMulti) {
  273. entt::registry registry;
  274. std::vector<entt::entity> entity(1000000);
  275. auto view = registry.view<position>();
  276. std::cout << "Destroying 1000000 entities at once, multiple components" << std::endl;
  277. registry.create(entity.begin(), entity.end());
  278. registry.insert<position>(entity.begin(), entity.end());
  279. registry.insert<velocity>(entity.begin(), entity.end());
  280. generic_with([&]() {
  281. registry.destroy(view.begin(), view.end());
  282. });
  283. }
  284. TEST(Benchmark, GetFromRegistry) {
  285. entt::registry registry;
  286. std::vector<entt::entity> entity(1000000);
  287. std::cout << "Getting data for 1000000 entities from a registry, one component" << std::endl;
  288. registry.create(entity.begin(), entity.end());
  289. registry.insert<position>(entity.begin(), entity.end());
  290. generic_with([&]() {
  291. for(auto entt: entity) {
  292. registry.get<position>(entt).x = 0u;
  293. }
  294. });
  295. }
  296. TEST(Benchmark, GetFromRegistryMulti) {
  297. entt::registry registry;
  298. std::vector<entt::entity> entity(1000000);
  299. std::cout << "Getting data for 1000000 entities from a registry, multiple components" << std::endl;
  300. registry.create(entity.begin(), entity.end());
  301. registry.insert<position>(entity.begin(), entity.end());
  302. registry.insert<velocity>(entity.begin(), entity.end());
  303. generic_with([&]() {
  304. for(auto entt: entity) {
  305. registry.get<position>(entt).x = 0u;
  306. registry.get<velocity>(entt).y = 0u;
  307. }
  308. });
  309. }
  310. TEST(Benchmark, GetFromView) {
  311. entt::registry registry;
  312. std::vector<entt::entity> entity(1000000);
  313. auto view = registry.view<position>();
  314. std::cout << "Getting data for 1000000 entities from a view, one component" << std::endl;
  315. registry.create(entity.begin(), entity.end());
  316. registry.insert<position>(entity.begin(), entity.end());
  317. generic_with([&]() {
  318. for(auto entt: entity) {
  319. view.get<position>(entt).x = 0u;
  320. }
  321. });
  322. }
  323. TEST(Benchmark, GetFromViewMulti) {
  324. entt::registry registry;
  325. std::vector<entt::entity> entity(1000000);
  326. auto view = registry.view<position, velocity>();
  327. std::cout << "Getting data for 1000000 entities from a view, multiple components" << std::endl;
  328. registry.create(entity.begin(), entity.end());
  329. registry.insert<position>(entity.begin(), entity.end());
  330. registry.insert<velocity>(entity.begin(), entity.end());
  331. generic_with([&]() {
  332. for(auto entt: entity) {
  333. view.get<position>(entt).x = 0u;
  334. view.get<velocity>(entt).y = 0u;
  335. }
  336. });
  337. }
  338. TEST(Benchmark, IterateSingleComponent1M) {
  339. entt::registry registry;
  340. std::cout << "Iterating over 1000000 entities, one component" << std::endl;
  341. for(std::uint64_t i = 0; i < 1000000L; i++) {
  342. const auto entt = registry.create();
  343. registry.emplace<position>(entt);
  344. }
  345. iterate_with(registry.view<position>(), [](auto &...comp) {
  346. ((comp.x = {}), ...);
  347. });
  348. }
  349. TEST(Benchmark, IterateSingleStableComponent1M) {
  350. entt::registry registry;
  351. std::cout << "Iterating over 1000000 entities, one stable component" << std::endl;
  352. for(std::uint64_t i = 0; i < 1000000L; i++) {
  353. const auto entt = registry.create();
  354. registry.emplace<stable_position>(entt);
  355. }
  356. iterate_with(registry.view<stable_position>(), [](auto &...comp) {
  357. ((comp.x = {}), ...);
  358. });
  359. }
  360. TEST(Benchmark, IterateSingleComponentRuntime1M) {
  361. entt::registry registry;
  362. std::cout << "Iterating over 1000000 entities, one component, runtime view" << std::endl;
  363. for(std::uint64_t i = 0; i < 1000000L; i++) {
  364. const auto entt = registry.create();
  365. registry.emplace<position>(entt);
  366. }
  367. entt::runtime_view view{};
  368. view.iterate(registry.storage<position>());
  369. iterate_with(view, [&](auto entt) {
  370. registry.get<position>(entt).x = {};
  371. });
  372. }
  373. TEST(Benchmark, IterateTwoComponents1M) {
  374. entt::registry registry;
  375. std::cout << "Iterating over 1000000 entities, two components" << std::endl;
  376. for(std::uint64_t i = 0; i < 1000000L; i++) {
  377. const auto entt = registry.create();
  378. registry.emplace<position>(entt);
  379. registry.emplace<velocity>(entt);
  380. }
  381. iterate_with(registry.view<position, velocity>(), [](auto &...comp) {
  382. ((comp.x = {}), ...);
  383. });
  384. }
  385. TEST(Benchmark, IterateTwoStableComponents1M) {
  386. entt::registry registry;
  387. std::cout << "Iterating over 1000000 entities, two stable components" << std::endl;
  388. for(std::uint64_t i = 0; i < 1000000L; i++) {
  389. const auto entt = registry.create();
  390. registry.emplace<stable_position>(entt);
  391. registry.emplace<velocity>(entt);
  392. }
  393. iterate_with(registry.view<stable_position, velocity>(), [](auto &...comp) {
  394. ((comp.x = {}), ...);
  395. });
  396. }
  397. TEST(Benchmark, IterateTwoComponents1MHalf) {
  398. entt::registry registry;
  399. std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components" << std::endl;
  400. for(std::uint64_t i = 0; i < 1000000L; i++) {
  401. const auto entt = registry.create();
  402. registry.emplace<velocity>(entt);
  403. if(i % 2) {
  404. registry.emplace<position>(entt);
  405. }
  406. }
  407. iterate_with(registry.view<position, velocity>(), [](auto &...comp) {
  408. ((comp.x = {}), ...);
  409. });
  410. }
  411. TEST(Benchmark, IterateTwoComponents1MOne) {
  412. entt::registry registry;
  413. std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components" << std::endl;
  414. for(std::uint64_t i = 0; i < 1000000L; i++) {
  415. const auto entt = registry.create();
  416. registry.emplace<velocity>(entt);
  417. if(i == 500000L) {
  418. registry.emplace<position>(entt);
  419. }
  420. }
  421. iterate_with(registry.view<position, velocity>(), [](auto &...comp) {
  422. ((comp.x = {}), ...);
  423. });
  424. }
  425. TEST(Benchmark, IterateTwoComponentsNonOwningGroup1M) {
  426. entt::registry registry;
  427. std::cout << "Iterating over 1000000 entities, two components, non owning group" << std::endl;
  428. for(std::uint64_t i = 0; i < 1000000L; i++) {
  429. const auto entt = registry.create();
  430. registry.emplace<position>(entt);
  431. registry.emplace<velocity>(entt);
  432. }
  433. iterate_with(registry.group<>(entt::get<position, velocity>), [](auto &...comp) {
  434. ((comp.x = {}), ...);
  435. });
  436. }
  437. TEST(Benchmark, IterateTwoComponentsFullOwningGroup1M) {
  438. entt::registry registry;
  439. std::cout << "Iterating over 1000000 entities, two components, full owning group" << std::endl;
  440. for(std::uint64_t i = 0; i < 1000000L; i++) {
  441. const auto entt = registry.create();
  442. registry.emplace<position>(entt);
  443. registry.emplace<velocity>(entt);
  444. }
  445. iterate_with(registry.group<position, velocity>(), [](auto &...comp) {
  446. ((comp.x = {}), ...);
  447. });
  448. }
  449. TEST(Benchmark, IterateTwoComponentsPartialOwningGroup1M) {
  450. entt::registry registry;
  451. std::cout << "Iterating over 1000000 entities, two components, partial owning group" << std::endl;
  452. for(std::uint64_t i = 0; i < 1000000L; i++) {
  453. const auto entt = registry.create();
  454. registry.emplace<position>(entt);
  455. registry.emplace<velocity>(entt);
  456. }
  457. iterate_with(registry.group<position>(entt::get<velocity>), [](auto &...comp) {
  458. ((comp.x = {}), ...);
  459. });
  460. }
  461. TEST(Benchmark, IterateTwoComponentsRuntime1M) {
  462. entt::registry registry;
  463. std::cout << "Iterating over 1000000 entities, two components, runtime view" << std::endl;
  464. for(std::uint64_t i = 0; i < 1000000L; i++) {
  465. const auto entt = registry.create();
  466. registry.emplace<position>(entt);
  467. registry.emplace<velocity>(entt);
  468. }
  469. entt::runtime_view view{};
  470. view.iterate(registry.storage<position>())
  471. .iterate(registry.storage<velocity>());
  472. iterate_with(view, [&](auto entt) {
  473. registry.get<position>(entt).x = {};
  474. registry.get<velocity>(entt).x = {};
  475. });
  476. }
  477. TEST(Benchmark, IterateTwoComponentsRuntime1MHalf) {
  478. entt::registry registry;
  479. std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components, runtime view" << std::endl;
  480. for(std::uint64_t i = 0; i < 1000000L; i++) {
  481. const auto entt = registry.create();
  482. registry.emplace<velocity>(entt);
  483. if(i % 2) {
  484. registry.emplace<position>(entt);
  485. }
  486. }
  487. entt::runtime_view view{};
  488. view.iterate(registry.storage<position>())
  489. .iterate(registry.storage<velocity>());
  490. iterate_with(view, [&](auto entt) {
  491. registry.get<position>(entt).x = {};
  492. registry.get<velocity>(entt).x = {};
  493. });
  494. }
  495. TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
  496. entt::registry registry;
  497. std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components, runtime view" << std::endl;
  498. for(std::uint64_t i = 0; i < 1000000L; i++) {
  499. const auto entt = registry.create();
  500. registry.emplace<velocity>(entt);
  501. if(i == 500000L) {
  502. registry.emplace<position>(entt);
  503. }
  504. }
  505. entt::runtime_view view{};
  506. view.iterate(registry.storage<position>())
  507. .iterate(registry.storage<velocity>());
  508. iterate_with(view, [&](auto entt) {
  509. registry.get<position>(entt).x = {};
  510. registry.get<velocity>(entt).x = {};
  511. });
  512. }
  513. TEST(Benchmark, IterateThreeComponents1M) {
  514. entt::registry registry;
  515. std::cout << "Iterating over 1000000 entities, three components" << std::endl;
  516. for(std::uint64_t i = 0; i < 1000000L; i++) {
  517. const auto entt = registry.create();
  518. registry.emplace<position>(entt);
  519. registry.emplace<velocity>(entt);
  520. registry.emplace<comp<0>>(entt);
  521. }
  522. iterate_with(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
  523. ((comp.x = {}), ...);
  524. });
  525. }
  526. TEST(Benchmark, IterateThreeStableComponents1M) {
  527. entt::registry registry;
  528. std::cout << "Iterating over 1000000 entities, three stable components" << std::endl;
  529. for(std::uint64_t i = 0; i < 1000000L; i++) {
  530. const auto entt = registry.create();
  531. registry.emplace<stable_position>(entt);
  532. registry.emplace<velocity>(entt);
  533. registry.emplace<comp<0>>(entt);
  534. }
  535. iterate_with(registry.view<stable_position, velocity, comp<0>>(), [](auto &...comp) {
  536. ((comp.x = {}), ...);
  537. });
  538. }
  539. TEST(Benchmark, IterateThreeComponents1MHalf) {
  540. entt::registry registry;
  541. std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components" << std::endl;
  542. for(std::uint64_t i = 0; i < 1000000L; i++) {
  543. const auto entt = registry.create();
  544. registry.emplace<velocity>(entt);
  545. registry.emplace<comp<0>>(entt);
  546. if(i % 2) {
  547. registry.emplace<position>(entt);
  548. }
  549. }
  550. iterate_with(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
  551. ((comp.x = {}), ...);
  552. });
  553. }
  554. TEST(Benchmark, IterateThreeComponents1MOne) {
  555. entt::registry registry;
  556. std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components" << std::endl;
  557. for(std::uint64_t i = 0; i < 1000000L; i++) {
  558. const auto entt = registry.create();
  559. registry.emplace<velocity>(entt);
  560. registry.emplace<comp<0>>(entt);
  561. if(i == 500000L) {
  562. registry.emplace<position>(entt);
  563. }
  564. }
  565. iterate_with(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
  566. ((comp.x = {}), ...);
  567. });
  568. }
  569. TEST(Benchmark, IterateThreeComponentsNonOwningGroup1M) {
  570. entt::registry registry;
  571. std::cout << "Iterating over 1000000 entities, three components, non owning group" << std::endl;
  572. for(std::uint64_t i = 0; i < 1000000L; i++) {
  573. const auto entt = registry.create();
  574. registry.emplace<position>(entt);
  575. registry.emplace<velocity>(entt);
  576. registry.emplace<comp<0>>(entt);
  577. }
  578. iterate_with(registry.group<>(entt::get<position, velocity, comp<0>>), [](auto &...comp) {
  579. ((comp.x = {}), ...);
  580. });
  581. }
  582. TEST(Benchmark, IterateThreeComponentsFullOwningGroup1M) {
  583. entt::registry registry;
  584. std::cout << "Iterating over 1000000 entities, three components, full owning group" << std::endl;
  585. for(std::uint64_t i = 0; i < 1000000L; i++) {
  586. const auto entt = registry.create();
  587. registry.emplace<position>(entt);
  588. registry.emplace<velocity>(entt);
  589. registry.emplace<comp<0>>(entt);
  590. }
  591. iterate_with(registry.group<position, velocity, comp<0>>(), [](auto &...comp) {
  592. ((comp.x = {}), ...);
  593. });
  594. }
  595. TEST(Benchmark, IterateThreeComponentsPartialOwningGroup1M) {
  596. entt::registry registry;
  597. std::cout << "Iterating over 1000000 entities, three components, partial owning group" << std::endl;
  598. for(std::uint64_t i = 0; i < 1000000L; i++) {
  599. const auto entt = registry.create();
  600. registry.emplace<position>(entt);
  601. registry.emplace<velocity>(entt);
  602. registry.emplace<comp<0>>(entt);
  603. }
  604. iterate_with(registry.group<position, velocity>(entt::get<comp<0>>), [](auto &...comp) {
  605. ((comp.x = {}), ...);
  606. });
  607. }
  608. TEST(Benchmark, IterateThreeComponentsRuntime1M) {
  609. entt::registry registry;
  610. std::cout << "Iterating over 1000000 entities, three components, runtime view" << std::endl;
  611. for(std::uint64_t i = 0; i < 1000000L; i++) {
  612. const auto entt = registry.create();
  613. registry.emplace<position>(entt);
  614. registry.emplace<velocity>(entt);
  615. registry.emplace<comp<0>>(entt);
  616. }
  617. entt::runtime_view view{};
  618. view.iterate(registry.storage<position>())
  619. .iterate(registry.storage<velocity>())
  620. .iterate(registry.storage<comp<0>>());
  621. iterate_with(view, [&](auto entt) {
  622. registry.get<position>(entt).x = {};
  623. registry.get<velocity>(entt).x = {};
  624. registry.get<comp<0>>(entt).x = {};
  625. });
  626. }
  627. TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
  628. entt::registry registry;
  629. std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components, runtime view" << std::endl;
  630. for(std::uint64_t i = 0; i < 1000000L; i++) {
  631. const auto entt = registry.create();
  632. registry.emplace<velocity>(entt);
  633. registry.emplace<comp<0>>(entt);
  634. if(i % 2) {
  635. registry.emplace<position>(entt);
  636. }
  637. }
  638. entt::runtime_view view{};
  639. view.iterate(registry.storage<position>())
  640. .iterate(registry.storage<velocity>())
  641. .iterate(registry.storage<comp<0>>());
  642. iterate_with(view, [&](auto entt) {
  643. registry.get<position>(entt).x = {};
  644. registry.get<velocity>(entt).x = {};
  645. registry.get<comp<0>>(entt).x = {};
  646. });
  647. }
  648. TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
  649. entt::registry registry;
  650. std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components, runtime view" << std::endl;
  651. for(std::uint64_t i = 0; i < 1000000L; i++) {
  652. const auto entt = registry.create();
  653. registry.emplace<velocity>(entt);
  654. registry.emplace<comp<0>>(entt);
  655. if(i == 500000L) {
  656. registry.emplace<position>(entt);
  657. }
  658. }
  659. entt::runtime_view view{};
  660. view.iterate(registry.storage<position>())
  661. .iterate(registry.storage<velocity>())
  662. .iterate(registry.storage<comp<0>>());
  663. iterate_with(view, [&](auto entt) {
  664. registry.get<position>(entt).x = {};
  665. registry.get<velocity>(entt).x = {};
  666. registry.get<comp<0>>(entt).x = {};
  667. });
  668. }
  669. TEST(Benchmark, IterateFiveComponents1M) {
  670. entt::registry registry;
  671. std::cout << "Iterating over 1000000 entities, five components" << std::endl;
  672. for(std::uint64_t i = 0; i < 1000000L; i++) {
  673. const auto entt = registry.create();
  674. registry.emplace<position>(entt);
  675. registry.emplace<velocity>(entt);
  676. registry.emplace<comp<0>>(entt);
  677. registry.emplace<comp<1>>(entt);
  678. registry.emplace<comp<2>>(entt);
  679. }
  680. iterate_with(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
  681. ((comp.x = {}), ...);
  682. });
  683. }
  684. TEST(Benchmark, IterateFiveStableComponents1M) {
  685. entt::registry registry;
  686. std::cout << "Iterating over 1000000 entities, five stable components" << std::endl;
  687. for(std::uint64_t i = 0; i < 1000000L; i++) {
  688. const auto entt = registry.create();
  689. registry.emplace<stable_position>(entt);
  690. registry.emplace<velocity>(entt);
  691. registry.emplace<comp<0>>(entt);
  692. registry.emplace<comp<1>>(entt);
  693. registry.emplace<comp<2>>(entt);
  694. }
  695. iterate_with(registry.view<stable_position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
  696. ((comp.x = {}), ...);
  697. });
  698. }
  699. TEST(Benchmark, IterateFiveComponents1MHalf) {
  700. entt::registry registry;
  701. std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components" << std::endl;
  702. for(std::uint64_t i = 0; i < 1000000L; i++) {
  703. const auto entt = registry.create();
  704. registry.emplace<velocity>(entt);
  705. registry.emplace<comp<0>>(entt);
  706. registry.emplace<comp<1>>(entt);
  707. registry.emplace<comp<2>>(entt);
  708. if(i % 2) {
  709. registry.emplace<position>(entt);
  710. }
  711. }
  712. iterate_with(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
  713. ((comp.x = {}), ...);
  714. });
  715. }
  716. TEST(Benchmark, IterateFiveComponents1MOne) {
  717. entt::registry registry;
  718. std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components" << std::endl;
  719. for(std::uint64_t i = 0; i < 1000000L; i++) {
  720. const auto entt = registry.create();
  721. registry.emplace<velocity>(entt);
  722. registry.emplace<comp<0>>(entt);
  723. registry.emplace<comp<1>>(entt);
  724. registry.emplace<comp<2>>(entt);
  725. if(i == 500000L) {
  726. registry.emplace<position>(entt);
  727. }
  728. }
  729. iterate_with(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
  730. ((comp.x = {}), ...);
  731. });
  732. }
  733. TEST(Benchmark, IterateFiveComponentsNonOwningGroup1M) {
  734. entt::registry registry;
  735. std::cout << "Iterating over 1000000 entities, five components, non owning group" << std::endl;
  736. for(std::uint64_t i = 0; i < 1000000L; i++) {
  737. const auto entt = registry.create();
  738. registry.emplace<position>(entt);
  739. registry.emplace<velocity>(entt);
  740. registry.emplace<comp<0>>(entt);
  741. registry.emplace<comp<1>>(entt);
  742. registry.emplace<comp<2>>(entt);
  743. }
  744. iterate_with(registry.group<>(entt::get<position, velocity, comp<0>, comp<1>, comp<2>>), [](auto &...comp) {
  745. ((comp.x = {}), ...);
  746. });
  747. }
  748. TEST(Benchmark, IterateFiveComponentsFullOwningGroup1M) {
  749. entt::registry registry;
  750. std::cout << "Iterating over 1000000 entities, five components, full owning group" << std::endl;
  751. for(std::uint64_t i = 0; i < 1000000L; i++) {
  752. const auto entt = registry.create();
  753. registry.emplace<position>(entt);
  754. registry.emplace<velocity>(entt);
  755. registry.emplace<comp<0>>(entt);
  756. registry.emplace<comp<1>>(entt);
  757. registry.emplace<comp<2>>(entt);
  758. }
  759. iterate_with(registry.group<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
  760. ((comp.x = {}), ...);
  761. });
  762. }
  763. TEST(Benchmark, IterateFiveComponentsPartialFourOfFiveOwningGroup1M) {
  764. entt::registry registry;
  765. std::cout << "Iterating over 1000000 entities, five components, partial (4 of 5) owning group" << std::endl;
  766. for(std::uint64_t i = 0; i < 1000000L; i++) {
  767. const auto entt = registry.create();
  768. registry.emplace<position>(entt);
  769. registry.emplace<velocity>(entt);
  770. registry.emplace<comp<0>>(entt);
  771. registry.emplace<comp<1>>(entt);
  772. registry.emplace<comp<2>>(entt);
  773. }
  774. iterate_with(registry.group<position, velocity, comp<0>, comp<1>>(entt::get<comp<2>>), [](auto &...comp) {
  775. ((comp.x = {}), ...);
  776. });
  777. }
  778. TEST(Benchmark, IterateFiveComponentsPartialThreeOfFiveOwningGroup1M) {
  779. entt::registry registry;
  780. std::cout << "Iterating over 1000000 entities, five components, partial (3 of 5) owning group" << std::endl;
  781. for(std::uint64_t i = 0; i < 1000000L; i++) {
  782. const auto entt = registry.create();
  783. registry.emplace<position>(entt);
  784. registry.emplace<velocity>(entt);
  785. registry.emplace<comp<0>>(entt);
  786. registry.emplace<comp<1>>(entt);
  787. registry.emplace<comp<2>>(entt);
  788. }
  789. iterate_with(registry.group<position, velocity, comp<0>>(entt::get<comp<1>, comp<2>>), [](auto &...comp) {
  790. ((comp.x = {}), ...);
  791. });
  792. }
  793. TEST(Benchmark, IterateFiveComponentsRuntime1M) {
  794. entt::registry registry;
  795. std::cout << "Iterating over 1000000 entities, five components, runtime view" << std::endl;
  796. for(std::uint64_t i = 0; i < 1000000L; i++) {
  797. const auto entt = registry.create();
  798. registry.emplace<position>(entt);
  799. registry.emplace<velocity>(entt);
  800. registry.emplace<comp<0>>(entt);
  801. registry.emplace<comp<1>>(entt);
  802. registry.emplace<comp<2>>(entt);
  803. }
  804. entt::runtime_view view{};
  805. view.iterate(registry.storage<position>())
  806. .iterate(registry.storage<velocity>())
  807. .iterate(registry.storage<comp<0>>())
  808. .iterate(registry.storage<comp<1>>())
  809. .iterate(registry.storage<comp<2>>());
  810. iterate_with(view, [&](auto entt) {
  811. registry.get<position>(entt).x = {};
  812. registry.get<velocity>(entt).x = {};
  813. registry.get<comp<0>>(entt).x = {};
  814. registry.get<comp<1>>(entt).x = {};
  815. registry.get<comp<2>>(entt).x = {};
  816. });
  817. }
  818. TEST(Benchmark, IterateFiveComponentsRuntime1MHalf) {
  819. entt::registry registry;
  820. std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components, runtime view" << std::endl;
  821. for(std::uint64_t i = 0; i < 1000000L; i++) {
  822. const auto entt = registry.create();
  823. registry.emplace<velocity>(entt);
  824. registry.emplace<comp<0>>(entt);
  825. registry.emplace<comp<1>>(entt);
  826. registry.emplace<comp<2>>(entt);
  827. if(i % 2) {
  828. registry.emplace<position>(entt);
  829. }
  830. }
  831. entt::runtime_view view{};
  832. view.iterate(registry.storage<position>())
  833. .iterate(registry.storage<velocity>())
  834. .iterate(registry.storage<comp<0>>())
  835. .iterate(registry.storage<comp<1>>())
  836. .iterate(registry.storage<comp<2>>());
  837. iterate_with(view, [&](auto entt) {
  838. registry.get<position>(entt).x = {};
  839. registry.get<velocity>(entt).x = {};
  840. registry.get<comp<0>>(entt).x = {};
  841. registry.get<comp<1>>(entt).x = {};
  842. registry.get<comp<2>>(entt).x = {};
  843. });
  844. }
  845. TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
  846. entt::registry registry;
  847. std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components, runtime view" << std::endl;
  848. for(std::uint64_t i = 0; i < 1000000L; i++) {
  849. const auto entt = registry.create();
  850. registry.emplace<velocity>(entt);
  851. registry.emplace<comp<0>>(entt);
  852. registry.emplace<comp<1>>(entt);
  853. registry.emplace<comp<2>>(entt);
  854. if(i == 500000L) {
  855. registry.emplace<position>(entt);
  856. }
  857. }
  858. entt::runtime_view view{};
  859. view.iterate(registry.storage<position>())
  860. .iterate(registry.storage<velocity>())
  861. .iterate(registry.storage<comp<0>>())
  862. .iterate(registry.storage<comp<1>>())
  863. .iterate(registry.storage<comp<2>>());
  864. iterate_with(view, [&](auto entt) {
  865. registry.get<position>(entt).x = {};
  866. registry.get<velocity>(entt).x = {};
  867. registry.get<comp<0>>(entt).x = {};
  868. registry.get<comp<1>>(entt).x = {};
  869. registry.get<comp<2>>(entt).x = {};
  870. });
  871. }
  872. TEST(Benchmark, IteratePathological) {
  873. std::cout << "Pathological case" << std::endl;
  874. pathological_with([](auto &registry) { return registry.template view<position, velocity, comp<0>>(); });
  875. }
  876. TEST(Benchmark, IteratePathologicalNonOwningGroup) {
  877. std::cout << "Pathological case (non-owning group)" << std::endl;
  878. pathological_with([](auto &registry) { return registry.template group<>(entt::get<position, velocity, comp<0>>); });
  879. }
  880. TEST(Benchmark, IteratePathologicalFullOwningGroup) {
  881. std::cout << "Pathological case (full-owning group)" << std::endl;
  882. pathological_with([](auto &registry) { return registry.template group<position, velocity, comp<0>>(); });
  883. }
  884. TEST(Benchmark, IteratePathologicalPartialOwningGroup) {
  885. std::cout << "Pathological case (partial-owning group)" << std::endl;
  886. pathological_with([](auto &registry) { return registry.template group<position, velocity>(entt::get<comp<0>>); });
  887. }
  888. TEST(Benchmark, SortSingle) {
  889. entt::registry registry;
  890. std::cout << "Sort 150000 entities, one component" << std::endl;
  891. for(std::uint64_t i = 0; i < 150000L; i++) {
  892. const auto entt = registry.create();
  893. registry.emplace<position>(entt, i, i);
  894. }
  895. generic_with([&]() {
  896. registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x < rhs.x && lhs.y < rhs.y; });
  897. });
  898. }
  899. TEST(Benchmark, SortMulti) {
  900. entt::registry registry;
  901. std::cout << "Sort 150000 entities, two components" << std::endl;
  902. for(std::uint64_t i = 0; i < 150000L; i++) {
  903. const auto entt = registry.create();
  904. registry.emplace<position>(entt, i, i);
  905. registry.emplace<velocity>(entt, i, i);
  906. }
  907. registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x < rhs.x && lhs.y < rhs.y; });
  908. generic_with([&]() {
  909. registry.sort<velocity, position>();
  910. });
  911. }
  912. TEST(Benchmark, AlmostSortedStdSort) {
  913. entt::registry registry;
  914. entt::entity entity[3]{};
  915. std::cout << "Sort 150000 entities, almost sorted, std::sort" << std::endl;
  916. for(std::uint64_t i = 0; i < 150000L; i++) {
  917. const auto entt = registry.create();
  918. registry.emplace<position>(entt, i, i);
  919. if(!(i % 50000)) {
  920. entity[i / 50000] = entt;
  921. }
  922. }
  923. for(std::uint64_t i = 0; i < 3; ++i) {
  924. registry.destroy(entity[i]);
  925. const auto entt = registry.create();
  926. registry.emplace<position>(entt, 50000 * i, 50000 * i);
  927. }
  928. generic_with([&]() {
  929. registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x > rhs.x && lhs.y > rhs.y; });
  930. });
  931. }
  932. TEST(Benchmark, AlmostSortedInsertionSort) {
  933. entt::registry registry;
  934. entt::entity entity[3]{};
  935. std::cout << "Sort 150000 entities, almost sorted, insertion sort" << std::endl;
  936. for(std::uint64_t i = 0; i < 150000L; i++) {
  937. const auto entt = registry.create();
  938. registry.emplace<position>(entt, i, i);
  939. if(!(i % 50000)) {
  940. entity[i / 50000] = entt;
  941. }
  942. }
  943. for(std::uint64_t i = 0; i < 3; ++i) {
  944. registry.destroy(entity[i]);
  945. const auto entt = registry.create();
  946. registry.emplace<position>(entt, 50000 * i, 50000 * i);
  947. }
  948. generic_with([&]() {
  949. registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x > rhs.x && lhs.y > rhs.y; }, entt::insertion_sort{});
  950. });
  951. }