benchmark.cpp 35 KB

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