benchmark.cpp 36 KB

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