benchmark.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  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_id_v<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. ENTT_ID_TYPE types[] = { entt::type_id_v<position>, entt::type_id_v<velocity> };
  256. timer timer;
  257. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  258. timer.elapsed();
  259. };
  260. test([&registry](auto entity) {
  261. registry.get<position>(entity).x = {};
  262. registry.get<velocity>(entity).x = {};
  263. });
  264. }
  265. TEST(Benchmark, IterateTwoComponentsRuntime1MHalf) {
  266. entt::registry registry;
  267. std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components, runtime view" << std::endl;
  268. for(std::uint64_t i = 0; i < 1000000L; i++) {
  269. const auto entity = registry.create();
  270. registry.assign<velocity>(entity);
  271. if(i % 2) {
  272. registry.assign<position>(entity);
  273. }
  274. }
  275. auto test = [&registry](auto func) {
  276. ENTT_ID_TYPE types[] = { entt::type_id_v<position>, entt::type_id_v<velocity> };
  277. timer timer;
  278. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  279. timer.elapsed();
  280. };
  281. test([&registry](auto entity) {
  282. registry.get<position>(entity).x = {};
  283. registry.get<velocity>(entity).x = {};
  284. });
  285. }
  286. TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
  287. entt::registry registry;
  288. std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components, runtime view" << std::endl;
  289. for(std::uint64_t i = 0; i < 1000000L; i++) {
  290. const auto entity = registry.create();
  291. registry.assign<velocity>(entity);
  292. if(i == 500000L) {
  293. registry.assign<position>(entity);
  294. }
  295. }
  296. auto test = [&registry](auto func) {
  297. ENTT_ID_TYPE types[] = { entt::type_id_v<position>, entt::type_id_v<velocity> };
  298. timer timer;
  299. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  300. timer.elapsed();
  301. };
  302. test([&registry](auto entity) {
  303. registry.get<position>(entity).x = {};
  304. registry.get<velocity>(entity).x = {};
  305. });
  306. }
  307. TEST(Benchmark, IterateThreeComponents1M) {
  308. entt::registry registry;
  309. std::cout << "Iterating over 1000000 entities, three components" << std::endl;
  310. for(std::uint64_t i = 0; i < 1000000L; i++) {
  311. const auto entity = registry.create();
  312. registry.assign<position>(entity);
  313. registry.assign<velocity>(entity);
  314. registry.assign<comp<0>>(entity);
  315. }
  316. auto test = [&registry](auto func) {
  317. timer timer;
  318. registry.view<position, velocity, comp<0>>().each(func);
  319. timer.elapsed();
  320. };
  321. test([](auto &... comp) {
  322. ((comp.x = {}), ...);
  323. });
  324. }
  325. TEST(Benchmark, IterateThreeComponents1MHalf) {
  326. entt::registry registry;
  327. std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components" << std::endl;
  328. for(std::uint64_t i = 0; i < 1000000L; i++) {
  329. const auto entity = registry.create();
  330. registry.assign<velocity>(entity);
  331. registry.assign<comp<0>>(entity);
  332. if(i % 2) {
  333. registry.assign<position>(entity);
  334. }
  335. }
  336. auto test = [&registry](auto func) {
  337. timer timer;
  338. registry.view<position, velocity, comp<0>>().each(func);
  339. timer.elapsed();
  340. };
  341. test([](auto &... comp) {
  342. ((comp.x = {}), ...);
  343. });
  344. }
  345. TEST(Benchmark, IterateThreeComponents1MOne) {
  346. entt::registry registry;
  347. std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components" << std::endl;
  348. for(std::uint64_t i = 0; i < 1000000L; i++) {
  349. const auto entity = registry.create();
  350. registry.assign<velocity>(entity);
  351. registry.assign<comp<0>>(entity);
  352. if(i == 500000L) {
  353. registry.assign<position>(entity);
  354. }
  355. }
  356. auto test = [&registry](auto func) {
  357. timer timer;
  358. registry.view<position, velocity, comp<0>>().each(func);
  359. timer.elapsed();
  360. };
  361. test([](auto &... comp) {
  362. ((comp.x = {}), ...);
  363. });
  364. }
  365. TEST(Benchmark, IterateThreeComponentsNonOwningGroup1M) {
  366. entt::registry registry;
  367. registry.group<>(entt::get<position, velocity, comp<0>>);
  368. std::cout << "Iterating over 1000000 entities, three components, non owning group" << std::endl;
  369. for(std::uint64_t i = 0; i < 1000000L; i++) {
  370. const auto entity = registry.create();
  371. registry.assign<position>(entity);
  372. registry.assign<velocity>(entity);
  373. registry.assign<comp<0>>(entity);
  374. }
  375. auto test = [&registry](auto func) {
  376. timer timer;
  377. registry.group<>(entt::get<position, velocity, comp<0>>).each(func);
  378. timer.elapsed();
  379. };
  380. test([](auto &... comp) {
  381. ((comp.x = {}), ...);
  382. });
  383. }
  384. TEST(Benchmark, IterateThreeComponentsFullOwningGroup1M) {
  385. entt::registry registry;
  386. registry.group<position, velocity, comp<0>>();
  387. std::cout << "Iterating over 1000000 entities, three components, full owning group" << std::endl;
  388. for(std::uint64_t i = 0; i < 1000000L; i++) {
  389. const auto entity = registry.create();
  390. registry.assign<position>(entity);
  391. registry.assign<velocity>(entity);
  392. registry.assign<comp<0>>(entity);
  393. }
  394. auto test = [&registry](auto func) {
  395. timer timer;
  396. registry.group<position, velocity, comp<0>>().each(func);
  397. timer.elapsed();
  398. };
  399. test([](auto &... comp) {
  400. ((comp.x = {}), ...);
  401. });
  402. }
  403. TEST(Benchmark, IterateThreeComponentsPartialOwningGroup1M) {
  404. entt::registry registry;
  405. registry.group<position, velocity>(entt::get<comp<0>>);
  406. std::cout << "Iterating over 1000000 entities, three components, partial owning group" << std::endl;
  407. for(std::uint64_t i = 0; i < 1000000L; i++) {
  408. const auto entity = registry.create();
  409. registry.assign<position>(entity);
  410. registry.assign<velocity>(entity);
  411. registry.assign<comp<0>>(entity);
  412. }
  413. auto test = [&registry](auto func) {
  414. timer timer;
  415. registry.group<position, velocity>(entt::get<comp<0>>).each(func);
  416. timer.elapsed();
  417. };
  418. test([](auto &... comp) {
  419. ((comp.x = {}), ...);
  420. });
  421. }
  422. TEST(Benchmark, IterateThreeComponentsRuntime1M) {
  423. entt::registry registry;
  424. std::cout << "Iterating over 1000000 entities, three components, runtime view" << std::endl;
  425. for(std::uint64_t i = 0; i < 1000000L; i++) {
  426. const auto entity = registry.create();
  427. registry.assign<position>(entity);
  428. registry.assign<velocity>(entity);
  429. registry.assign<comp<0>>(entity);
  430. }
  431. auto test = [&registry](auto func) {
  432. ENTT_ID_TYPE types[] = { entt::type_id_v<position>, entt::type_id_v<velocity>, entt::type_id_v<comp<0>> };
  433. timer timer;
  434. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  435. timer.elapsed();
  436. };
  437. test([&registry](auto entity) {
  438. registry.get<position>(entity).x = {};
  439. registry.get<velocity>(entity).x = {};
  440. registry.get<comp<0>>(entity).x = {};
  441. });
  442. }
  443. TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
  444. entt::registry registry;
  445. std::cout << "Iterating over 1000000 entities, three components, half of the entities have all the components, runtime view" << std::endl;
  446. for(std::uint64_t i = 0; i < 1000000L; i++) {
  447. const auto entity = registry.create();
  448. registry.assign<velocity>(entity);
  449. registry.assign<comp<0>>(entity);
  450. if(i % 2) {
  451. registry.assign<position>(entity);
  452. }
  453. }
  454. auto test = [&registry](auto func) {
  455. ENTT_ID_TYPE types[] = { entt::type_id_v<position>, entt::type_id_v<velocity>, entt::type_id_v<comp<0>> };
  456. timer timer;
  457. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  458. timer.elapsed();
  459. };
  460. test([&registry](auto entity) {
  461. registry.get<position>(entity).x = {};
  462. registry.get<velocity>(entity).x = {};
  463. registry.get<comp<0>>(entity).x = {};
  464. });
  465. }
  466. TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
  467. entt::registry registry;
  468. std::cout << "Iterating over 1000000 entities, three components, only one entity has all the components, runtime view" << std::endl;
  469. for(std::uint64_t i = 0; i < 1000000L; i++) {
  470. const auto entity = registry.create();
  471. registry.assign<velocity>(entity);
  472. registry.assign<comp<0>>(entity);
  473. if(i == 500000L) {
  474. registry.assign<position>(entity);
  475. }
  476. }
  477. auto test = [&registry](auto func) {
  478. ENTT_ID_TYPE types[] = { entt::type_id_v<position>, entt::type_id_v<velocity>, entt::type_id_v<comp<0>> };
  479. timer timer;
  480. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  481. timer.elapsed();
  482. };
  483. test([&registry](auto entity) {
  484. registry.get<position>(entity).x = {};
  485. registry.get<velocity>(entity).x = {};
  486. registry.get<comp<0>>(entity).x = {};
  487. });
  488. }
  489. TEST(Benchmark, IterateFiveComponents1M) {
  490. entt::registry registry;
  491. std::cout << "Iterating over 1000000 entities, five components" << std::endl;
  492. for(std::uint64_t i = 0; i < 1000000L; i++) {
  493. const auto entity = registry.create();
  494. registry.assign<position>(entity);
  495. registry.assign<velocity>(entity);
  496. registry.assign<comp<0>>(entity);
  497. registry.assign<comp<1>>(entity);
  498. registry.assign<comp<2>>(entity);
  499. }
  500. auto test = [&registry](auto func) {
  501. timer timer;
  502. registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
  503. timer.elapsed();
  504. };
  505. test([](auto &... comp) {
  506. ((comp.x = {}), ...);
  507. });
  508. }
  509. TEST(Benchmark, IterateFiveComponents1MHalf) {
  510. entt::registry registry;
  511. std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components" << std::endl;
  512. for(std::uint64_t i = 0; i < 1000000L; i++) {
  513. const auto entity = registry.create();
  514. registry.assign<velocity>(entity);
  515. registry.assign<comp<0>>(entity);
  516. registry.assign<comp<1>>(entity);
  517. registry.assign<comp<2>>(entity);
  518. if(i % 2) {
  519. registry.assign<position>(entity);
  520. }
  521. }
  522. auto test = [&registry](auto func) {
  523. timer timer;
  524. registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
  525. timer.elapsed();
  526. };
  527. test([](auto &... comp) {
  528. ((comp.x = {}), ...);
  529. });
  530. }
  531. TEST(Benchmark, IterateFiveComponents1MOne) {
  532. entt::registry registry;
  533. std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components" << std::endl;
  534. for(std::uint64_t i = 0; i < 1000000L; i++) {
  535. const auto entity = registry.create();
  536. registry.assign<velocity>(entity);
  537. registry.assign<comp<0>>(entity);
  538. registry.assign<comp<1>>(entity);
  539. registry.assign<comp<2>>(entity);
  540. if(i == 500000L) {
  541. registry.assign<position>(entity);
  542. }
  543. }
  544. auto test = [&registry](auto func) {
  545. timer timer;
  546. registry.view<position, velocity, comp<0>, comp<1>, comp<2>>().each(func);
  547. timer.elapsed();
  548. };
  549. test([](auto &... comp) {
  550. ((comp.x = {}), ...);
  551. });
  552. }
  553. TEST(Benchmark, IterateFiveComponentsNonOwningGroup1M) {
  554. entt::registry registry;
  555. registry.group<>(entt::get<position, velocity, comp<0>, comp<1>, comp<2>>);
  556. std::cout << "Iterating over 1000000 entities, five components, non owning group" << std::endl;
  557. for(std::uint64_t i = 0; i < 1000000L; i++) {
  558. const auto entity = registry.create();
  559. registry.assign<position>(entity);
  560. registry.assign<velocity>(entity);
  561. registry.assign<comp<0>>(entity);
  562. registry.assign<comp<1>>(entity);
  563. registry.assign<comp<2>>(entity);
  564. }
  565. auto test = [&registry](auto func) {
  566. timer timer;
  567. registry.group<>(entt::get<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, IterateFiveComponentsFullOwningGroup1M) {
  575. entt::registry registry;
  576. registry.group<position, velocity, comp<0>, comp<1>, comp<2>>();
  577. std::cout << "Iterating over 1000000 entities, five components, full 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<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, IterateFiveComponentsPartialFourOfFiveOwningGroup1M) {
  596. entt::registry registry;
  597. registry.group<position, velocity, comp<0>, comp<1>>(entt::get<comp<2>>);
  598. std::cout << "Iterating over 1000000 entities, five components, partial (4 of 5) 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>>(entt::get<comp<2>>).each(func);
  610. timer.elapsed();
  611. };
  612. test([](auto &... comp) {
  613. ((comp.x = {}), ...);
  614. });
  615. }
  616. TEST(Benchmark, IterateFiveComponentsPartialThreeOfFiveOwningGroup1M) {
  617. entt::registry registry;
  618. registry.group<position, velocity, comp<0>>(entt::get<comp<1>, comp<2>>);
  619. std::cout << "Iterating over 1000000 entities, five components, partial (3 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>>(entt::get<comp<1>, comp<2>>).each(func);
  631. timer.elapsed();
  632. };
  633. test([](auto &... comp) {
  634. ((comp.x = {}), ...);
  635. });
  636. }
  637. TEST(Benchmark, IterateFiveComponentsRuntime1M) {
  638. entt::registry registry;
  639. std::cout << "Iterating over 1000000 entities, five components, runtime view" << std::endl;
  640. for(std::uint64_t i = 0; i < 1000000L; i++) {
  641. const auto entity = registry.create();
  642. registry.assign<position>(entity);
  643. registry.assign<velocity>(entity);
  644. registry.assign<comp<0>>(entity);
  645. registry.assign<comp<1>>(entity);
  646. registry.assign<comp<2>>(entity);
  647. }
  648. auto test = [&registry](auto func) {
  649. ENTT_ID_TYPE types[] = {
  650. entt::type_id_v<position>,
  651. entt::type_id_v<velocity>,
  652. entt::type_id_v<comp<0>>,
  653. entt::type_id_v<comp<1>>,
  654. entt::type_id_v<comp<2>>
  655. };
  656. timer timer;
  657. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  658. timer.elapsed();
  659. };
  660. test([&registry](auto entity) {
  661. registry.get<position>(entity).x = {};
  662. registry.get<velocity>(entity).x = {};
  663. registry.get<comp<0>>(entity).x = {};
  664. registry.get<comp<1>>(entity).x = {};
  665. registry.get<comp<2>>(entity).x = {};
  666. });
  667. }
  668. TEST(Benchmark, IterateFiveComponentsRuntime1MHalf) {
  669. entt::registry registry;
  670. std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components, runtime view" << std::endl;
  671. for(std::uint64_t i = 0; i < 1000000L; i++) {
  672. const auto entity = registry.create();
  673. registry.assign<velocity>(entity);
  674. registry.assign<comp<0>>(entity);
  675. registry.assign<comp<1>>(entity);
  676. registry.assign<comp<2>>(entity);
  677. if(i % 2) {
  678. registry.assign<position>(entity);
  679. }
  680. }
  681. auto test = [&registry](auto func) {
  682. ENTT_ID_TYPE types[] = {
  683. entt::type_id_v<position>,
  684. entt::type_id_v<velocity>,
  685. entt::type_id_v<comp<0>>,
  686. entt::type_id_v<comp<1>>,
  687. entt::type_id_v<comp<2>>
  688. };
  689. timer timer;
  690. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  691. timer.elapsed();
  692. };
  693. test([&registry](auto entity) {
  694. registry.get<position>(entity).x = {};
  695. registry.get<velocity>(entity).x = {};
  696. registry.get<comp<0>>(entity).x = {};
  697. registry.get<comp<1>>(entity).x = {};
  698. registry.get<comp<2>>(entity).x = {};
  699. });
  700. }
  701. TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
  702. entt::registry registry;
  703. std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components, runtime view" << std::endl;
  704. for(std::uint64_t i = 0; i < 1000000L; i++) {
  705. const auto entity = registry.create();
  706. registry.assign<velocity>(entity);
  707. registry.assign<comp<0>>(entity);
  708. registry.assign<comp<1>>(entity);
  709. registry.assign<comp<2>>(entity);
  710. if(i == 500000L) {
  711. registry.assign<position>(entity);
  712. }
  713. }
  714. auto test = [&registry](auto func) {
  715. ENTT_ID_TYPE types[] = {
  716. entt::type_id_v<position>,
  717. entt::type_id_v<velocity>,
  718. entt::type_id_v<comp<0>>,
  719. entt::type_id_v<comp<1>>,
  720. entt::type_id_v<comp<2>>
  721. };
  722. timer timer;
  723. registry.runtime_view(std::begin(types), std::end(types)).each(func);
  724. timer.elapsed();
  725. };
  726. test([&registry](auto entity) {
  727. registry.get<position>(entity).x = {};
  728. registry.get<velocity>(entity).x = {};
  729. registry.get<comp<0>>(entity).x = {};
  730. registry.get<comp<1>>(entity).x = {};
  731. registry.get<comp<2>>(entity).x = {};
  732. });
  733. }
  734. TEST(Benchmark, IteratePathological) {
  735. std::cout << "Pathological case" << std::endl;
  736. pathological([](auto &registry, auto func) {
  737. timer timer;
  738. registry.template view<position, velocity, comp<0>>().each(func);
  739. timer.elapsed();
  740. });
  741. }
  742. TEST(Benchmark, IteratePathologicalNonOwningGroup) {
  743. std::cout << "Pathological case (non-owning group)" << std::endl;
  744. pathological([](auto &registry, auto func) {
  745. auto group = registry.template group<>(entt::get<position, velocity, comp<0>>);
  746. timer timer;
  747. group.each(func);
  748. timer.elapsed();
  749. });
  750. }
  751. TEST(Benchmark, IteratePathologicalFullOwningGroup) {
  752. std::cout << "Pathological case (full-owning group)" << std::endl;
  753. pathological([](auto &registry, auto func) {
  754. auto group = registry.template group<position, velocity, comp<0>>();
  755. timer timer;
  756. group.each(func);
  757. timer.elapsed();
  758. });
  759. }
  760. TEST(Benchmark, IteratePathologicalPartialOwningGroup) {
  761. std::cout << "Pathological case (partial-owning group)" << std::endl;
  762. pathological([](auto &registry, auto func) {
  763. auto group = registry.template group<position, velocity>(entt::get<comp<0>>);
  764. timer timer;
  765. group.each(func);
  766. timer.elapsed();
  767. });
  768. }
  769. TEST(Benchmark, SortSingle) {
  770. entt::registry registry;
  771. std::cout << "Sort 150000 entities, one component" << std::endl;
  772. for(std::uint64_t i = 0; i < 150000L; i++) {
  773. const auto entity = registry.create();
  774. registry.assign<position>(entity, i, i);
  775. }
  776. timer timer;
  777. registry.sort<position>([](const auto &lhs, const auto &rhs) {
  778. return lhs.x < rhs.x && lhs.y < rhs.y;
  779. });
  780. timer.elapsed();
  781. }
  782. TEST(Benchmark, SortMulti) {
  783. entt::registry registry;
  784. std::cout << "Sort 150000 entities, two components" << std::endl;
  785. for(std::uint64_t i = 0; i < 150000L; i++) {
  786. const auto entity = registry.create();
  787. registry.assign<position>(entity, i, i);
  788. registry.assign<velocity>(entity, i, i);
  789. }
  790. registry.sort<position>([](const auto &lhs, const auto &rhs) {
  791. return lhs.x < rhs.x && lhs.y < rhs.y;
  792. });
  793. timer timer;
  794. registry.sort<velocity, position>();
  795. timer.elapsed();
  796. }
  797. TEST(Benchmark, AlmostSortedStdSort) {
  798. entt::registry registry;
  799. entt::entity entities[3];
  800. std::cout << "Sort 150000 entities, almost sorted, std::sort" << std::endl;
  801. for(std::uint64_t i = 0; i < 150000L; i++) {
  802. const auto entity = registry.create();
  803. registry.assign<position>(entity, i, i);
  804. if(!(i % 50000)) {
  805. entities[i / 50000] = entity;
  806. }
  807. }
  808. for(std::uint64_t i = 0; i < 3; ++i) {
  809. registry.destroy(entities[i]);
  810. const auto entity = registry.create();
  811. registry.assign<position>(entity, 50000 * i, 50000 * i);
  812. }
  813. timer timer;
  814. registry.sort<position>([](const auto &lhs, const auto &rhs) {
  815. return lhs.x > rhs.x && lhs.y > rhs.y;
  816. });
  817. timer.elapsed();
  818. }
  819. TEST(Benchmark, AlmostSortedInsertionSort) {
  820. entt::registry registry;
  821. entt::entity entities[3];
  822. std::cout << "Sort 150000 entities, almost sorted, insertion sort" << std::endl;
  823. for(std::uint64_t i = 0; i < 150000L; i++) {
  824. const auto entity = registry.create();
  825. registry.assign<position>(entity, i, i);
  826. if(!(i % 50000)) {
  827. entities[i / 50000] = entity;
  828. }
  829. }
  830. for(std::uint64_t i = 0; i < 3; ++i) {
  831. registry.destroy(entities[i]);
  832. const auto entity = registry.create();
  833. registry.assign<position>(entity, 50000 * i, 50000 * i);
  834. }
  835. timer timer;
  836. registry.sort<position>([](const auto &lhs, const auto &rhs) {
  837. return lhs.x > rhs.x && lhs.y > rhs.y;
  838. }, entt::insertion_sort{});
  839. timer.elapsed();
  840. }