1
0

benchmark.cpp 37 KB

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