benchmark.cpp 37 KB

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