🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1093 lines
32 KiB

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