benchmark.cpp 31 KB

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