benchmark.cpp 30 KB

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