🛠️🐜 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.

1095 lines
31 KiB

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