benchmark.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. #include <iostream>
  2. #include <cstddef>
  3. #include <cstdint>
  4. #include <chrono>
  5. #include <gtest/gtest.h>
  6. #include <entt/entity/registry.hpp>
  7. struct Position {
  8. std::uint64_t x;
  9. std::uint64_t y;
  10. };
  11. struct Velocity {
  12. std::uint64_t x;
  13. std::uint64_t y;
  14. };
  15. template<std::size_t>
  16. struct Comp { int x; };
  17. struct Timer final {
  18. Timer(): start{std::chrono::system_clock::now()} {}
  19. void elapsed() {
  20. auto now = std::chrono::system_clock::now();
  21. std::cout << std::chrono::duration<double>(now - start).count() << " seconds" << std::endl;
  22. }
  23. private:
  24. std::chrono::time_point<std::chrono::system_clock> start;
  25. };
  26. TEST(Benchmark, Construct) {
  27. entt::DefaultRegistry registry;
  28. std::cout << "Constructing 1000000 entities" << std::endl;
  29. Timer timer;
  30. for(std::uint64_t i = 0; i < 1000000L; i++) {
  31. registry.create();
  32. }
  33. timer.elapsed();
  34. }
  35. TEST(Benchmark, Destroy) {
  36. entt::DefaultRegistry registry;
  37. std::cout << "Destroying 1000000 entities" << std::endl;
  38. for(std::uint64_t i = 0; i < 1000000L; i++) {
  39. registry.create();
  40. }
  41. Timer timer;
  42. registry.each([&registry](auto entity) {
  43. registry.destroy(entity);
  44. });
  45. timer.elapsed();
  46. }
  47. TEST(Benchmark, IterateCreateDeleteSingleComponent) {
  48. entt::DefaultRegistry registry;
  49. std::cout << "Looping 10000 times creating and deleting a random number of entities" << std::endl;
  50. Timer timer;
  51. auto view = registry.view<Position>();
  52. for(int i = 0; i < 10000; i++) {
  53. for(int j = 0; j < 10000; j++) {
  54. const auto entity = registry.create();
  55. registry.assign<Position>(entity);
  56. }
  57. for(auto entity: view) {
  58. if(rand() % 2 == 0) {
  59. registry.destroy(entity);
  60. }
  61. }
  62. }
  63. timer.elapsed();
  64. }
  65. TEST(Benchmark, IterateSingleComponent1M) {
  66. entt::DefaultRegistry registry;
  67. std::cout << "Iterating over 1000000 entities, one component" << std::endl;
  68. for(std::uint64_t i = 0; i < 1000000L; i++) {
  69. const auto entity = registry.create();
  70. registry.assign<Position>(entity);
  71. }
  72. auto test = [&registry](auto func) {
  73. Timer timer;
  74. registry.view<Position>().each(func);
  75. timer.elapsed();
  76. };
  77. test([](auto, const auto &) {});
  78. test([](auto, auto &... comp) {
  79. using accumulator_type = int[];
  80. accumulator_type accumulator = { (comp.x = {}, 0)... };
  81. (void)accumulator;
  82. });
  83. }
  84. TEST(Benchmark, IterateSingleComponentRaw1M) {
  85. entt::DefaultRegistry registry;
  86. std::cout << "Iterating over 1000000 entities, one component, raw view" << std::endl;
  87. for(std::uint64_t i = 0; i < 1000000L; i++) {
  88. const auto entity = registry.create();
  89. registry.assign<Position>(entity);
  90. }
  91. auto test = [&registry](auto func) {
  92. Timer timer;
  93. registry.view<Position>(entt::raw_t{}).each(func);
  94. timer.elapsed();
  95. };
  96. test([](const auto &) {});
  97. test([](auto &... comp) {
  98. using accumulator_type = int[];
  99. accumulator_type accumulator = { (comp.x = {}, 0)... };
  100. (void)accumulator;
  101. });
  102. }
  103. TEST(Benchmark, IterateTwoComponents1M) {
  104. entt::DefaultRegistry registry;
  105. std::cout << "Iterating over 1000000 entities, two components" << std::endl;
  106. for(std::uint64_t i = 0; i < 1000000L; i++) {
  107. const auto entity = registry.create();
  108. registry.assign<Position>(entity);
  109. registry.assign<Velocity>(entity);
  110. }
  111. auto test = [&registry](auto func) {
  112. Timer timer;
  113. registry.view<Position, Velocity>().each(func);
  114. timer.elapsed();
  115. };
  116. test([](auto, const auto &...) {});
  117. test([](auto, auto &... comp) {
  118. using accumulator_type = int[];
  119. accumulator_type accumulator = { (comp.x = {}, 0)... };
  120. (void)accumulator;
  121. });
  122. }
  123. TEST(Benchmark, IterateTwoComponents1MHalf) {
  124. entt::DefaultRegistry registry;
  125. std::cout << "Iterating over 1000000 entities, two components, half of the entities have all the components" << std::endl;
  126. for(std::uint64_t i = 0; i < 1000000L; i++) {
  127. const auto entity = registry.create();
  128. registry.assign<Velocity>(entity);
  129. if(i % 2) {
  130. registry.assign<Position>(entity);
  131. }
  132. }
  133. auto test = [&registry](auto func) {
  134. Timer timer;
  135. registry.view<Position, Velocity>().each(func);
  136. timer.elapsed();
  137. };
  138. test([](auto, const auto &...) {});
  139. test([](auto, auto &... comp) {
  140. using accumulator_type = int[];
  141. accumulator_type accumulator = { (comp.x = {}, 0)... };
  142. (void)accumulator;
  143. });
  144. }
  145. TEST(Benchmark, IterateTwoComponents1MOne) {
  146. entt::DefaultRegistry registry;
  147. std::cout << "Iterating over 1000000 entities, two components, only one entity has all the components" << std::endl;
  148. for(std::uint64_t i = 0; i < 1000000L; i++) {
  149. const auto entity = registry.create();
  150. registry.assign<Velocity>(entity);
  151. if(i == 5000000L) {
  152. registry.assign<Position>(entity);
  153. }
  154. }
  155. auto test = [&registry](auto func) {
  156. Timer timer;
  157. registry.view<Position, Velocity>().each(func);
  158. timer.elapsed();
  159. };
  160. test([](auto, const auto &...) {});
  161. test([](auto, auto &... comp) {
  162. using accumulator_type = int[];
  163. accumulator_type accumulator = { (comp.x = {}, 0)... };
  164. (void)accumulator;
  165. });
  166. }
  167. TEST(Benchmark, IterateTwoComponentsPersistent1M) {
  168. entt::DefaultRegistry registry;
  169. registry.prepare<Position, Velocity>();
  170. std::cout << "Iterating over 1000000 entities, two components, persistent view" << std::endl;
  171. for(std::uint64_t i = 0; i < 1000000L; i++) {
  172. const auto entity = registry.create();
  173. registry.assign<Position>(entity);
  174. registry.assign<Velocity>(entity);
  175. }
  176. auto test = [&registry](auto func) {
  177. Timer timer;
  178. registry.view<Position, Velocity>(entt::persistent_t{}).each(func);
  179. timer.elapsed();
  180. };
  181. test([](auto, const auto &...) {});
  182. test([](auto, auto &... comp) {
  183. using accumulator_type = int[];
  184. accumulator_type accumulator = { (comp.x = {}, 0)... };
  185. (void)accumulator;
  186. });
  187. }
  188. TEST(Benchmark, IterateFiveComponents1M) {
  189. entt::DefaultRegistry registry;
  190. std::cout << "Iterating over 1000000 entities, five components" << std::endl;
  191. for(std::uint64_t i = 0; i < 1000000L; i++) {
  192. const auto entity = registry.create();
  193. registry.assign<Position>(entity);
  194. registry.assign<Velocity>(entity);
  195. registry.assign<Comp<1>>(entity);
  196. registry.assign<Comp<2>>(entity);
  197. registry.assign<Comp<3>>(entity);
  198. }
  199. auto test = [&registry](auto func) {
  200. Timer timer;
  201. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each(func);
  202. timer.elapsed();
  203. };
  204. test([](auto, const auto &...) {});
  205. test([](auto, auto &... comp) {
  206. using accumulator_type = int[];
  207. accumulator_type accumulator = { (comp.x = {}, 0)... };
  208. (void)accumulator;
  209. });
  210. }
  211. TEST(Benchmark, IterateFiveComponents1MHalf) {
  212. entt::DefaultRegistry registry;
  213. std::cout << "Iterating over 1000000 entities, five components, half of the entities have all the components" << std::endl;
  214. for(std::uint64_t i = 0; i < 1000000L; i++) {
  215. const auto entity = registry.create();
  216. registry.assign<Velocity>(entity);
  217. registry.assign<Comp<1>>(entity);
  218. registry.assign<Comp<2>>(entity);
  219. registry.assign<Comp<3>>(entity);
  220. if(i % 2) {
  221. registry.assign<Position>(entity);
  222. }
  223. }
  224. auto test = [&registry](auto func) {
  225. Timer timer;
  226. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each(func);
  227. timer.elapsed();
  228. };
  229. test([](auto, const auto &...) {});
  230. test([](auto, auto &... comp) {
  231. using accumulator_type = int[];
  232. accumulator_type accumulator = { (comp.x = {}, 0)... };
  233. (void)accumulator;
  234. });
  235. }
  236. TEST(Benchmark, IterateFiveComponents1MOne) {
  237. entt::DefaultRegistry registry;
  238. std::cout << "Iterating over 1000000 entities, five components, only one entity has all the components" << std::endl;
  239. for(std::uint64_t i = 0; i < 1000000L; i++) {
  240. const auto entity = registry.create();
  241. registry.assign<Velocity>(entity);
  242. registry.assign<Comp<1>>(entity);
  243. registry.assign<Comp<2>>(entity);
  244. registry.assign<Comp<3>>(entity);
  245. if(i == 5000000L) {
  246. registry.assign<Position>(entity);
  247. }
  248. }
  249. auto test = [&registry](auto func) {
  250. Timer timer;
  251. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each(func);
  252. timer.elapsed();
  253. };
  254. test([](auto, const auto &...) {});
  255. test([](auto, auto &... comp) {
  256. using accumulator_type = int[];
  257. accumulator_type accumulator = { (comp.x = {}, 0)... };
  258. (void)accumulator;
  259. });
  260. }
  261. TEST(Benchmark, IterateFiveComponentsPersistent1M) {
  262. entt::DefaultRegistry registry;
  263. registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>();
  264. std::cout << "Iterating over 1000000 entities, five components, persistent view" << std::endl;
  265. for(std::uint64_t i = 0; i < 1000000L; i++) {
  266. const auto entity = registry.create();
  267. registry.assign<Position>(entity);
  268. registry.assign<Velocity>(entity);
  269. registry.assign<Comp<1>>(entity);
  270. registry.assign<Comp<2>>(entity);
  271. registry.assign<Comp<3>>(entity);
  272. }
  273. auto test = [&registry](auto func) {
  274. Timer timer;
  275. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>(entt::persistent_t{}).each(func);
  276. timer.elapsed();
  277. };
  278. test([](auto, const auto &...) {});
  279. test([](auto, auto &... comp) {
  280. using accumulator_type = int[];
  281. accumulator_type accumulator = { (comp.x = {}, 0)... };
  282. (void)accumulator;
  283. });
  284. }
  285. TEST(Benchmark, IterateTenComponents1M) {
  286. entt::DefaultRegistry registry;
  287. std::cout << "Iterating over 1000000 entities, ten components" << std::endl;
  288. for(std::uint64_t i = 0; i < 1000000L; i++) {
  289. const auto entity = registry.create();
  290. registry.assign<Position>(entity);
  291. registry.assign<Velocity>(entity);
  292. registry.assign<Comp<1>>(entity);
  293. registry.assign<Comp<2>>(entity);
  294. registry.assign<Comp<3>>(entity);
  295. registry.assign<Comp<4>>(entity);
  296. registry.assign<Comp<5>>(entity);
  297. registry.assign<Comp<6>>(entity);
  298. registry.assign<Comp<7>>(entity);
  299. registry.assign<Comp<8>>(entity);
  300. }
  301. auto test = [&registry](auto func) {
  302. Timer timer;
  303. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each(func);
  304. timer.elapsed();
  305. };
  306. test([](auto, const auto &...) {});
  307. test([](auto, auto &... comp) {
  308. using accumulator_type = int[];
  309. accumulator_type accumulator = { (comp.x = {}, 0)... };
  310. (void)accumulator;
  311. });
  312. }
  313. TEST(Benchmark, IterateTenComponents1MHalf) {
  314. entt::DefaultRegistry registry;
  315. std::cout << "Iterating over 1000000 entities, ten components, half of the entities have all the components" << std::endl;
  316. for(std::uint64_t i = 0; i < 1000000L; i++) {
  317. const auto entity = registry.create();
  318. registry.assign<Velocity>(entity);
  319. registry.assign<Comp<1>>(entity);
  320. registry.assign<Comp<2>>(entity);
  321. registry.assign<Comp<3>>(entity);
  322. registry.assign<Comp<4>>(entity);
  323. registry.assign<Comp<5>>(entity);
  324. registry.assign<Comp<6>>(entity);
  325. registry.assign<Comp<7>>(entity);
  326. registry.assign<Comp<8>>(entity);
  327. if(i % 2) {
  328. registry.assign<Position>(entity);
  329. }
  330. }
  331. auto test = [&registry](auto func) {
  332. Timer timer;
  333. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each(func);
  334. timer.elapsed();
  335. };
  336. test([](auto, auto &...) {});
  337. test([](auto, auto &... comp) {
  338. using accumulator_type = int[];
  339. accumulator_type accumulator = { (comp.x = {}, 0)... };
  340. (void)accumulator;
  341. });
  342. }
  343. TEST(Benchmark, IterateTenComponents1MOne) {
  344. entt::DefaultRegistry registry;
  345. std::cout << "Iterating over 1000000 entities, ten components, only one entity has all the components" << std::endl;
  346. for(std::uint64_t i = 0; i < 1000000L; i++) {
  347. const auto entity = registry.create();
  348. registry.assign<Velocity>(entity);
  349. registry.assign<Comp<1>>(entity);
  350. registry.assign<Comp<2>>(entity);
  351. registry.assign<Comp<3>>(entity);
  352. registry.assign<Comp<4>>(entity);
  353. registry.assign<Comp<5>>(entity);
  354. registry.assign<Comp<6>>(entity);
  355. registry.assign<Comp<7>>(entity);
  356. registry.assign<Comp<8>>(entity);
  357. if(i == 5000000L) {
  358. registry.assign<Position>(entity);
  359. }
  360. }
  361. auto test = [&registry](auto func) {
  362. Timer timer;
  363. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each(func);
  364. timer.elapsed();
  365. };
  366. test([](auto, const auto &...) {});
  367. test([](auto, auto &... comp) {
  368. using accumulator_type = int[];
  369. accumulator_type accumulator = { (comp.x = {}, 0)... };
  370. (void)accumulator;
  371. });
  372. }
  373. TEST(Benchmark, IterateTenComponentsPersistent1M) {
  374. entt::DefaultRegistry registry;
  375. registry.prepare<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>();
  376. std::cout << "Iterating over 1000000 entities, ten components, persistent view" << std::endl;
  377. for(std::uint64_t i = 0; i < 1000000L; i++) {
  378. const auto entity = registry.create();
  379. registry.assign<Position>(entity);
  380. registry.assign<Velocity>(entity);
  381. registry.assign<Comp<1>>(entity);
  382. registry.assign<Comp<2>>(entity);
  383. registry.assign<Comp<3>>(entity);
  384. registry.assign<Comp<4>>(entity);
  385. registry.assign<Comp<5>>(entity);
  386. registry.assign<Comp<6>>(entity);
  387. registry.assign<Comp<7>>(entity);
  388. registry.assign<Comp<8>>(entity);
  389. }
  390. auto test = [&registry](auto func) {
  391. Timer timer;
  392. registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>(entt::persistent_t{}).each(func);
  393. timer.elapsed();
  394. };
  395. test([](auto, const auto &...) {});
  396. test([](auto, auto &... comp) {
  397. using accumulator_type = int[];
  398. accumulator_type accumulator = { (comp.x = {}, 0)... };
  399. (void)accumulator;
  400. });
  401. }
  402. TEST(Benchmark, SortSingle) {
  403. entt::DefaultRegistry registry;
  404. std::cout << "Sort 150000 entities, one component" << std::endl;
  405. for(std::uint64_t i = 0; i < 150000L; i++) {
  406. const auto entity = registry.create();
  407. registry.assign<Position>(entity, i, i);
  408. }
  409. Timer timer;
  410. registry.sort<Position>([](const auto &lhs, const auto &rhs) {
  411. return lhs.x < rhs.x && lhs.y < rhs.y;
  412. });
  413. timer.elapsed();
  414. }
  415. TEST(Benchmark, SortMulti) {
  416. entt::DefaultRegistry registry;
  417. std::cout << "Sort 150000 entities, two components" << std::endl;
  418. for(std::uint64_t i = 0; i < 150000L; i++) {
  419. const auto entity = registry.create();
  420. registry.assign<Position>(entity, i, i);
  421. registry.assign<Velocity>(entity, i, i);
  422. }
  423. registry.sort<Position>([](const auto &lhs, const auto &rhs) {
  424. return lhs.x < rhs.x && lhs.y < rhs.y;
  425. });
  426. Timer timer;
  427. registry.sort<Velocity, Position>();
  428. timer.elapsed();
  429. }
  430. TEST(Benchmark, AlmostSortedStdSort) {
  431. entt::DefaultRegistry registry;
  432. entt::DefaultRegistry::entity_type entities[3];
  433. std::cout << "Sort 150000 entities, almost sorted, std::sort" << std::endl;
  434. for(std::uint64_t i = 0; i < 150000L; i++) {
  435. const auto entity = registry.create();
  436. registry.assign<Position>(entity, i, i);
  437. if(!(i % 50000)) {
  438. entities[i / 50000] = entity;
  439. }
  440. }
  441. for(std::uint64_t i = 0; i < 3; ++i) {
  442. registry.destroy(entities[i]);
  443. const auto entity = registry.create();
  444. registry.assign<Position>(entity, 50000 * i, 50000 * i);
  445. }
  446. Timer timer;
  447. registry.sort<Position>([](const auto &lhs, const auto &rhs) {
  448. return lhs.x > rhs.x && lhs.y > rhs.y;
  449. });
  450. timer.elapsed();
  451. }
  452. TEST(Benchmark, AlmostSortedInsertionSort) {
  453. entt::DefaultRegistry registry;
  454. entt::DefaultRegistry::entity_type entities[3];
  455. std::cout << "Sort 150000 entities, almost sorted, insertion sort" << std::endl;
  456. for(std::uint64_t i = 0; i < 150000L; i++) {
  457. const auto entity = registry.create();
  458. registry.assign<Position>(entity, i, i);
  459. if(!(i % 50000)) {
  460. entities[i / 50000] = entity;
  461. }
  462. }
  463. for(std::uint64_t i = 0; i < 3; ++i) {
  464. registry.destroy(entities[i]);
  465. const auto entity = registry.create();
  466. registry.assign<Position>(entity, 50000 * i, 50000 * i);
  467. }
  468. Timer timer;
  469. registry.sort<Position>([](const auto &lhs, const auto &rhs) {
  470. return lhs.x > rhs.x && lhs.y > rhs.y;
  471. }, entt::InsertionSort{});
  472. timer.elapsed();
  473. }