benchmark.cpp 35 KB

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