benchmark.cpp 35 KB

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