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