benchmark.cpp 37 KB

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