{"id":13728187,"url":"https://github.com/friflo/ECS.CSharp.Benchmark-common-use-cases","last_synced_at":"2025-05-08T00:31:22.968Z","repository":{"id":247965891,"uuid":"826384667","full_name":"friflo/ECS.CSharp.Benchmark-common-use-cases","owner":"friflo","description":"Benchmark 🏁 of C# ECS frameworks comparing multiple use cases","archived":false,"fork":false,"pushed_at":"2024-11-12T13:15:58.000Z","size":516,"stargazers_count":22,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-12T14:24:15.017Z","etag":null,"topics":["benchmark","csharp","ecs","entity-component-system"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/friflo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-09T15:52:40.000Z","updated_at":"2024-11-12T13:16:03.000Z","dependencies_parsed_at":"2024-08-08T13:29:57.949Z","dependency_job_id":"f448394b-ede3-4f28-9645-fef0055a1320","html_url":"https://github.com/friflo/ECS.CSharp.Benchmark-common-use-cases","commit_stats":null,"previous_names":["friflo/ecs.csharp.benchmark-common-use-cases"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friflo%2FECS.CSharp.Benchmark-common-use-cases","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friflo%2FECS.CSharp.Benchmark-common-use-cases/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friflo%2FECS.CSharp.Benchmark-common-use-cases/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/friflo%2FECS.CSharp.Benchmark-common-use-cases/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/friflo","download_url":"https://codeload.github.com/friflo/ECS.CSharp.Benchmark-common-use-cases/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224679845,"owners_count":17351877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["benchmark","csharp","ecs","entity-component-system"],"created_at":"2024-08-03T02:00:38.346Z","updated_at":"2024-11-14T19:30:46.744Z","avatar_url":"https://github.com/friflo.png","language":"C#","funding_links":[],"categories":["[Other Resources](#contents)"],"sub_categories":["[Benchmarks](#contents)"],"readme":"[![Benchmark-CI](https://img.shields.io/github/actions/workflow/status/friflo/ECS.CSharp.Benchmark-common-use-cases/.github/workflows/benchmark-ci.yml?label=CI\u0026logo=github-actions\u0026logoColor=white)](https://github.com/friflo/ECS.CSharp.Benchmark-common-use-cases/actions/workflows/benchmark-ci.yml)\n[![Benchmark Archive](https://img.shields.io/badge/Benchmark-Archive-blue?logo=github\u0026logoColor=white)](https://github.com/friflo/ECS.CSharp.Benchmark-common-use-cases/tree/main/results/mac-mini-m2)\n\n# ECS.CSharp.Benchmark - Common use-cases\n\nMotivation of this benchmark project:\n\n- Compare performance of common uses cases of multiple ECS projects.  \n  *\"I want to compare the performance of two C# ECS projects\"?*  \n  Use the example command shown in the [Benchmark CLI](#benchmark-cli) examples below.\n\n- Utilize a common ECS operation of a specific ECS project in most **simple \u0026 performant** way.  \n\n- *\"I want to migrate from one C# ECS to another\"?*  \n  Navigate to a specific benchmark in both projects an use their implementations as migration guide.  \n  Benchmark implementations are intended to be as simple as possible.\n\n- Having an alternative to the popular [Ecs.CSharp.Benchmark](https://github.com/Doraku/Ecs.CSharp.Benchmark).  \n  As the mentioned project is currently not active maintained.\n\nSee comments about this benchmark at [reddit announcement post](https://www.reddit.com/r/EntityComponentSystem/comments/1e0qo62/just_published_new_github_repo_ecs_c_benchmark/)\n\n\n# Contents\n\n* [Tested projects](#tested-projects)\n* [ECS implementation](#ecs-implementation)\n* [Benchmarks](#benchmarks)\n  - [Overview](#overview)\n  - [Basic](#basic)\n  - [Relations](#relations)\n  - [Command buffer](#command-buffer)\n  - [Events](#events)\n  - [Search](#search)\n* [Setup](#setup)\n* [Contribution](#contribution)\n* [Benchmark CLI](#benchmark-cli)\n* [Other C# ECS Benchmarks](#other-c-ecs-benchmarks)\n\n\n\u003cbr/\u003e\n\n## Tested projects\n\n- [x] All tested projects are engine agnostic.  \n- [x] 🔒 **C#** - dll uses only *verifiable safe code*. This allows execution in trusted environments.  \n      See [Unsafe code ⋅ Microsoft](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code) and\n      [C# Language specification  ⋅ Microsoft](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/unsafe-code)\n      using `\u003cAllowUnsafeBlocks\u003e`.\n\n*Projects ordered by dll size*  \n| ECS                                                                       | ECS type    | Entity  | 🔒 C# | size kb |            tested | nuget latest\n|-------------------------------------------------------------------------- | ----------- | ------- |:-----:| -------:| -----------------:| --------------------------------------\n| [Leopotam.EcsLite](https://github.com/Leopotam/ecslite)                   | Sparse Set  | int     |  ✅   |      18 |             1.0.1 | [![nuget](https://img.shields.io/nuget/v/Leopotam.EcsLite?label=%20\u0026color=blue)](https://www.nuget.org/packages/Leopotam.EcsLite) ⁽¹⁾\n| [Morpeh](https://github.com/scellecs/morpeh)                              | ?           | class   |       |      76 |          2023.1.0 | [![nuget](https://img.shields.io/nuget/v/Scellecs.Morpeh?label=%20\u0026color=blue)](https://www.nuget.org/packages/Scellecs.Morpeh)\n| [fennecs](https://github.com/outfox/fennecs)                              | Archetype   | struct  |       |     157 |       0.5.10-beta | [![nuget](https://img.shields.io/nuget/vpre/fennecs?label=%20\u0026color=blue)](https://www.nuget.org/packages/fennecs)\n| [DefaultEcs](https://github.com/Doraku/DefaultEcs)                        | Sparse Set  | struct  |       |     169 |     0.18.0-beta01 | [![nuget](https://img.shields.io/nuget/vpre/DefaultEcs?label=%20\u0026color=blue)](https://www.nuget.org/packages/DefaultEcs)\n| [Friflo.Engine.ECS](https://github.com/friflo/Friflo.Engine.ECS)          | Archetype   | struct  |  ✅  |     307  |  3.0.0-preview.10 | [![nuget](https://img.shields.io/nuget/vpre/Friflo.Engine.ECS?label=%20\u0026color=blue)](https://www.nuget.org/packages/Friflo.Engine.ECS)\n| [Friflo.Engine.ECS.Boost](https://github.com/friflo/Friflo.Engine.ECS)    | 📦         |         |       |     +12 |  3.0.0-preview.10 | [![nuget](https://img.shields.io/nuget/vpre/Friflo.Engine.ECS.Boost?label=%20\u0026color=blue)](https://www.nuget.org/packages/Friflo.Engine.ECS.Boost)\n| [TinyEcs](https://github.com/andreakarasho/TinyEcs)                       | Archetype   | struct  |       |     487 |             1.4.0 | [![nuget](https://img.shields.io/nuget/v/TinyEcs.Main?label=%20\u0026color=blue)](https://www.nuget.org/packages/TinyEcs.Main)\n| [Myriad.ECS](https://github.com/martindevans/Myriad.ECS)                  | Archetype   | struct  |       |     631 |            21.2.1 | [![nuget](https://img.shields.io/nuget/v/Myriad.ECS?label=%20\u0026color=blue)](https://www.nuget.org/packages/Myriad.ECS)\n| [Arch](https://github.com/genaray/Arch)                                   | Archetype   | struct  |       |     765 |             1.2.8 | [![nuget](https://img.shields.io/nuget/v/Arch?label=%20\u0026color=blue)](https://www.nuget.org/packages/Arch)\n| [Arch.Relationships](https://github.com/genaray/Arch.Extended)            | 📦         |         |  ✅  |      +9  |             1.0.1 | [![nuget](https://img.shields.io/nuget/v/Arch.Relationships?label=%20\u0026color=blue)](https://www.nuget.org/packages/Arch.Relationships)\n| [Flecs.NET](https://github.com/BeanCheeseBurrito/Flecs.NET)               | Arch/Sparse | struct  |       |    1600 |             4.0.0 | [![nuget](https://img.shields.io/nuget/v/Flecs.NET.Release?label=%20\u0026color=blue)](https://www.nuget.org/packages/Flecs.NET.Release)\n\n⁽¹⁾ nuget package not published by project owner  \n\n\n## ECS implementation\n\nThe are typically two types used by many ECS projects\n\n### Archetype\n\nEntities are stored in single array. Components as stored in \"tables\" aka Archetypes.  \nAn Archetype contains arrays of components for a specific set of component types.\n\n**Pros:** Enable fast iteration of component queries.  \n**Cons**: Add/remove operations require a structural change.  \n\n### Sparse Set\n\nA sparse Set based ECS stores each component in its own sparse set which is has the entity id as key.\n\n**Pros:** Fast add/remove operations.  \n**Cons:** Each component type requires an array with the size of all components.  \n\n\u003cbr/\u003e\n\n\n# Benchmarks\n\n## Feature Matrix\n\n- [x] **Watch** - Watch / navigate entity components ad-hoc in debugger.\n    \u003cdetails\u003e    \n        \u003csummary\u003eSee example screenshot\u003c/summary\u003e\n        \u003cimg src=\"docs/images/Debugger-Watch.png\" width=\"634\" height=\"178\"/\u003e        \n    \u003c/details\u003e\n\n| ECS                  | Basic | Relations | Command Buffer | Events | Search | Watch  |\n|--------------------- | ----- | --------- | -------------- | ------ | ------ | ------ |\n| Arch + Relationships |  ✅  |  ✅       |  ✅           |  [^1]  |         |  ✅   |\n| DefaultEcs           |  ✅  |           |  ✅            |  ✅    |        |  ✅   |\n| fennecs              |  ✅  |  ✅       |                |  [^2]  |        |  ✅   |\n| Flecs.NET            |  ✅  |  ✅       |  ✅           |   ✅   |        |        |\n| Friflo.Engine.ECS    |  ✅  |  ✅ ¹     |  ✅           |   ✅   |   ✅   |  ✅   |\n| Leopotam.EcsLite     |  ✅  |           |                |         |        |       |\n| Morpeh               |  ✅  |           |  ✅            |        |        |        |\n| Myriad.ECS           |  ✅  |           |  ✅            |        |        |        |\n| TinyEcs              |  ✅  |  ✅       |  ✅           |   ✅   |        |        |\n\n¹ Ensures a cycle free entity hierarchy. See [CheckTreeCycles()](https://github.com/search?q=repo%3Afriflo%2FECS.CSharp.Benchmark-common-use-cases+CheckTreeCycles\u0026type=code)\n\n\u003cbr/\u003e\n\n| Benchmark Description                                         | Category                  |\n|-------------------------------------------------------------- | ------------------------- |\n| [**Basic**](#basic)                                           |                           |\n| Add \u0026 Remove 1/5 components on 100 entities                   | `AddRemoveComponents`     |\n| Create 100 entities with 1/3 components                       | `CreateEntity`            |\n| Create World                                                  | `CreateWorld`             |\n| Delete 100.000 entities with 5 components                     | `DeleteEntity`            |\n| Get \u0026 Set 1 / 5 components on 100 entities                    | `GetSetComponents`        |\n| Query 100 / 100.000 entities with 1 / 5 components            | `QueryComponents`         |\n|                                                               |                           |\n| [**Relations**](#relations)                                   |                           |\n| Add \u0026 Remove 1/100 link relation on 100 entities              | `AddRemoveLinks`          |\n| Add \u0026 Remove 1/10 relations on 100 entities                   | `AddRemoveRelations`      |\n| Add \u0026 Remove 10 child entities on 100 parent entities         | `ChildEntitiesAddRemove`  |\n|                                                               |                           |\n| [**Command Buffer**](#command-buffer) - *deferred operations* |                           |\n| Add \u0026 Remove 2 components on 100 entities                     | `CommandBufferAddRemove`  |\n|                                                               |                           |\n| [**Events**](#events) - *reactive ECS*                        |                           |\n| Get event callback on Add \u0026 Remove 1 component                | `ComponentEvents`         |\n|                                                               |                           |\n| [**Search**](#search)                                         |                           |\n| Search component field in 1.000.000 entities                  | `SearchComponentField`    |\n| Search range of component fields in 1.000.000 entities        | `SearchRange`             |\n\n\u003cbr/\u003e\n\nRun benchmarks always on an **Apple Mac Mini M2**.  \nIts hardware specs are fixed and can be compared with benchmarks you run by your own on this machine.\n\n```\nBenchmarkDotNet v0.13.12, macOS Sonoma 14.5 (23F79) [Darwin 23.5.0]\nApple M2, 1 CPU, 8 logical and 8 physical cores\n.NET SDK 8.0.100\n  [Host]   : .NET 8.0.0 (8.0.23.53103), Arm64 RyuJIT AdvSIMD\n  ShortRun : .NET 8.0.0 (8.0.23.53103), Arm64 RyuJIT AdvSIMD\n```\n\n\n## Overview\n\nReadme benchmark update: **2024-08-09** using this\n[run](https://github.com/friflo/ECS.CSharp.Benchmark-common-use-cases/blob/main/results/mac-mini-m2/all/BenchmarkRun-joined-2024-08-08-18-23-57-report-github.md)\n\n*Ratio*: Average Performance Ratio - see [C# ECS Benchmark Overview ⋅ Google Sheets](https://docs.google.com/spreadsheets/d/1170ZjOXhiQJpY-VuNxocxaxPKGTJYQL72Zcbrvq0CcY) \n\n|         |     friflo | Flecs.NET  | TinyEcs    | Arch       | fennecs    | Leopotam   | DefaultEcs | Morpeh     |\n| ------- | ----------:| ----------:| ----------:| ----------:| ----------:| ----------:| ----------:| ----------:|\n| *Ratio* |       1.00 |       2.55 |       3.42 |       6.96 |      19.02 |       2.57 |       3.81 |      21.09 |\n| *Notes* |            |            |            |            |            | [^sparse]  | [^sparse]  | [^sparse]  |\n\n[^sparse]: Sparse Set based ECS projects.\n\n## **Basic**\n\n### Add \u0026 Remove 1 / 5 component on 100 entities\n\n**Note:** See impact of structural changes in Archetype based ECS projects.  \n\n| Namespace         | Entities | Components | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |----------- |--------------:|---------:|-----------:|\n| Leopotam.EcsLite  | 100      | 1          |        981 ns |     0.17 |          - | \n| DefaultEcs        | 100      | 1          |      1,431 ns |     0.25 |          - | \n| Scellecs.Morpeh   | 100      | 1          |      1,676 ns |     0.29 |          - | \n| Flecs.NET         | 100      | 1          |      3,761 ns |     0.65 |          - | \n| TinyEcs           | 100      | 1          |      3,984 ns |     0.69 |          - | \n| Friflo.Engine.ECS | 100      | 1          |      5,787 ns |     1.00 |          - | \n| Arch              | 100      | 1          |      8,438 ns |     1.46 |    12000 B | \n| Myriad            | 100      | 1          |     19,044 ns |     3.29 |          - | \n| fennecs           | 100      | 1          |     38,594 ns |     6.67 |    86400 B | \n|                   |          |            |               |          |            | \n| Scellecs.Morpeh   | 100      | 5          |      4,988 ns |     0.64 |          - | \n| Leopotam.EcsLite  | 100      | 5          |      5,118 ns |     0.66 |          - | \n| DefaultEcs        | 100      | 5          |      7,120 ns |     0.92 |          - | \n| Friflo.Engine.ECS | 100      | 5          |      7,779 ns |     1.00 |          - | \n| Arch              | 100      | 5          |     23,106 ns |     2.97 |     8800 B | \n| TinyEcs           | 100      | 5          |     29,867 ns |     3.84 |          - | \n| Flecs.NET         | 100      | 5          |     37,030 ns |     4.76 |          - | \n| Myriad            | 100      | 5          |     54,960 ns |     7.06 |          - | \n| fennecs           | 100      | 5          |    307,458 ns |    39.52 |   620800 B | \n\n\n### Create 100 entities with 1 / 3 components\n\nCreated entities are initialized with custom values as recommended [here](https://github.com/friflo/ECS.CSharp.Benchmark-common-use-cases/pull/4#issuecomment-2269097772).  \n*\"in a real-world environment creating a large number of default entities isn't very useful and you'll always want to set component values!\"*\n\n| Namespace         | Entities | Components | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |----------- |--------------:|---------:|-----------:|\n| Leopotam.EcsLite  | 100      | 1          |      1,374 ns |     0.30 |     7048 B | \n| DefaultEcs        | 100      | 1          |      3,894 ns |     0.85 |    12960 B | \n| Friflo.Engine.ECS | 100      | 1          |      4,574 ns |     1.00 |    11600 B | \n| TinyEcs           | 100      | 1          |      5,536 ns |     1.22 |    86264 B | \n| Arch              | 100      | 1          |      7,948 ns |     1.74 |    36400 B | \n| Flecs.NET         | 100      | 1          |      8,558 ns |     1.87 |      736 B | \n| Myriad            | 100      | 1          |     11,178 ns |     2.45 |    18936 B | \n| Scellecs.Morpeh   | 100      | 1          |     13,511 ns |     2.99 |    42896 B | \n| fennecs           | 100      | 1          |     37,324 ns |     8.22 |   252376 B | \n|                   |          |            |               |          |            | \n| Leopotam.EcsLite  | 100      | 3          |      3,163 ns |     0.82 |    19672 B | \n| Friflo.Engine.ECS | 100      | 3          |      3,877 ns |     1.00 |    15856 B | \n| Arch              | 100      | 3          |      6,384 ns |     1.65 |    28256 B | \n| DefaultEcs        | 100      | 3          |      7,615 ns |     1.95 |    23368 B | \n| TinyEcs           | 100      | 3          |      8,953 ns |     2.31 |   121896 B | \n| Scellecs.Morpeh   | 100      | 3          |     16,683 ns |     4.28 |    54400 B | \n| Flecs.NET         | 100      | 3          |     17,391 ns |     4.55 |      736 B | \n| Myriad            | 100      | 3          |     21,014 ns |     5.39 |    27288 B | \n| fennecs           | 100      | 3          |    103,193 ns |    26.41 |   395856 B | \n\nSome frameworks support **bulk creation** of entities.  \nIf available bulk creation is faster than the approach creating entities ony by one.\n\n| Namespace         | Entities | Components | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |----------- |--------------:|---------:|-----------:|\n| Friflo.Engine.ECS | 100      | 1          |        988 ns |     1.00 |     7856 B | \n| Arch              | 100      | 1          |      7,360 ns |     7.53 |    36736 B | \n| fennecs           | 100      | 1          |     19,065 ns |    19.48 |   210712 B | \n|                   |          |            |               |          |            | \n| Friflo.Engine.ECS | 100      | 3          |      1,605 ns |     1.00 |    12112 B | \n| Arch              | 100      | 3          |      7,906 ns |     4.88 |    28592 B | \n| fennecs           | 100      | 3          |     25,458 ns |    15.74 |   214448 B | \n\n\n### Create World\n\n| Namespace         | Mean          | Ratio    | Allocated  | \n|------------------ |--------------:|---------:|-----------:|\n| DefaultEcs        |         74 ns |     0.31 |      336 B | \n| Friflo.Engine.ECS |        238 ns |     1.00 |     3952 B | \n| Myriad            |        802 ns |     3.36 |    19776 B | \n| Leopotam.EcsLite  |      1,443 ns |     6.04 |    58944 B | \n| Arch              |      3,369 ns |    14.11 |    37040 B | \n| Scellecs.Morpeh   |      4,295 ns |    17.98 |     5056 B | \n| fennecs           |     21,295 ns |    89.16 |   169364 B | \n| TinyEcs           |     51,588 ns |   215.98 |  1312184 B | \n| Flecs.NET         |  1,033,699 ns | 4,265.55 |     1009 B | \n\n\n### Delete 100.000 entities with 5 components\n\n| Namespace         | Entities | Components | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |----------- |--------------:|---------:|-----------:|\n| Friflo.Engine.ECS | 100000   | 5          |  1,590,691 ns |     1.00 |      736 B | \n| Myriad            | 100000   | 5          |  1,917,754 ns |     1.20 |  4196080 B | \n| Flecs.NET         | 100000   | 5          |  1,985,879 ns |     1.25 |      736 B | \n| Arch              | 100000   | 5          |  2,899,945 ns |     1.73 |     3088 B | \n| TinyEcs           | 100000   | 5          |  3,382,786 ns |     2.13 |     1480 B | \n| DefaultEcs        | 100000   | 5          |  3,684,181 ns |     2.31 |  3200736 B | \n| Leopotam.EcsLite  | 100000   | 5          |  4,814,687 ns |     3.03 |  6268768 B | \n| fennecs           | 100000   | 5          |  5,720,832 ns |     3.60 |  4366912 B | \n| Scellecs.Morpeh   | 100000   | 5          |  8,842,465 ns |     5.55 |  1398360 B | \n\n\n### Get \u0026 Set 1 / 5 component on 100 entities\n\n**Note:** Sparse Set based ECS projects are in lead because of viewer array lookups.\n\n| Namespace         | Entities | Components | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |----------- |--------------:|---------:|-----------:|\n| Leopotam.EcsLite  | 100      | 1          |         65 ns |     0.32 |          - | \n| DefaultEcs        | 100      | 1          |        115 ns |     0.57 |          - | \n| Scellecs.Morpeh   | 100      | 1          |        141 ns |     0.70 |          - | \n| Friflo.Engine.ECS | 100      | 1          |        202 ns |     1.00 |          - | \n| Arch              | 100      | 1          |        288 ns |     1.42 |          - | \n| Myriad            | 100      | 1          |        346 ns |     1.71 |          - | \n| Flecs.NET         | 100      | 1          |        582 ns |     2.87 |          - | \n| TinyEcs           | 100      | 1          |        729 ns |     3.60 |          - | \n| fennecs           | 100      | 1          |      2,369 ns |    11.68 |          - | \n|                   |          |            |               |          |            | \n| Leopotam.EcsLite  | 100      | 5          |        312 ns |     0.76 |          - | \n| Friflo.Engine.ECS | 100      | 5          |        410 ns |     1.00 |          - | \n| DefaultEcs        | 100      | 5          |        457 ns |     1.11 |          - | \n| Scellecs.Morpeh   | 100      | 5          |        614 ns |     1.50 |          - | \n| Arch              | 100      | 5          |      1,586 ns |     3.86 |          - | \n| Myriad            | 100      | 5          |      1,744 ns |     4.24 |          - | \n| Flecs.NET         | 100      | 5          |      2,690 ns |     6.55 |          - | \n| TinyEcs           | 100      | 5          |      4,004 ns |     9.74 |          - | \n| fennecs           | 100      | 5          |     14,345 ns |    34.91 |          - | \n\n\n### Query 100 / 100.000 entities with 1 / 5 components\n\n**Note:** Archetype based ECS projects are in lead if querying multiple components.  \nReturned components are sequentially stored in memory providing a high cache hit rate.\n\n**Rule**: Query implementations must not use vectorization (SIMD instructions).  \nIf doing so this case requires a new benchmark category: `QueryVectorization`.\n\n| Namespace         | Entities | Components | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |----------- |--------------:|---------:|-----------:|\n| DefaultEcs        | 100      | 1          |         44 ns |     0.86 |          - | \n| Friflo.Engine.ECS | 100      | 1          |         51 ns |     1.00 |          - | \n| Myriad            | 100      | 1          |         65 ns |     1.28 |          - | \n| TinyEcs           | 100      | 1          |         67 ns |     1.32 |          - | \n| Leopotam.EcsLite  | 100      | 1          |         77 ns |     1.51 |          - | \n| Flecs.NET         | 100      | 1          |        141 ns |     2.75 |          - | \n| fennecs           | 100      | 1          |        203 ns |     3.97 |       88 B | \n| Arch              | 100      | 1          |        299 ns |     5.84 |          - | \n| Scellecs.Morpeh   | 100      | 1          |        374 ns |     7.30 |          - | \n|                   |          |            |               |          |            | \n| Friflo.Engine.ECS | 100      | 5          |         65 ns |     1.00 |          - | \n| Myriad            | 100      | 5          |         71 ns |     1.09 |          - | \n| TinyEcs           | 100      | 5          |        127 ns |     1.95 |          - | \n| Flecs.NET         | 100      | 5          |        200 ns |     3.07 |          - | \n| DefaultEcs        | 100      | 5          |        272 ns |     4.17 |          - | \n| Leopotam.EcsLite  | 100      | 5          |        340 ns |     5.21 |          - | \n| Arch              | 100      | 5          |        341 ns |     5.22 |          - | \n| fennecs           | 100      | 5          |        441 ns |     6.76 |       88 B | \n| Scellecs.Morpeh   | 100      | 5          |        782 ns |    11.99 |          - | \n|                   |          |            |               |          |            | \n| DefaultEcs        | 100000   | 1          |     45,890 ns |     0.94 |          - | \n| Friflo.Engine.ECS | 100000   | 1          |     48,631 ns |     1.00 |          - | \n| fennecs           | 100000   | 1          |     49,366 ns |     1.02 |       88 B | \n| Flecs.NET         | 100000   | 1          |     49,899 ns |     1.03 |          - | \n| TinyEcs           | 100000   | 1          |     50,214 ns |     1.03 |          - | \n| Myriad            | 100000   | 1          |     51,355 ns |     1.06 |          - | \n| Leopotam.EcsLite  | 100000   | 1          |     77,551 ns |     1.60 |          - | \n| Arch              | 100000   | 1          |    211,165 ns |     4.34 |          - | \n| Scellecs.Morpeh   | 100000   | 1          |    855,866 ns |    17.60 |        1 B | \n|                   |          |            |               |          |            | \n| Friflo.Engine.ECS | 100000   | 5          |     48,055 ns |     1.00 |          - | \n| Myriad            | 100000   | 5          |     56,872 ns |     1.18 |          - | \n| Flecs.NET         | 100000   | 5          |     77,777 ns |     1.62 |          - | \n| TinyEcs           | 100000   | 5          |     89,260 ns |     1.86 |          - | \n| fennecs           | 100000   | 5          |    108,646 ns |     2.26 |       88 B | \n| Arch              | 100000   | 5          |    229,269 ns |     4.77 |          - | \n| DefaultEcs        | 100000   | 5          |    318,011 ns |     6.62 |          - | \n| Leopotam.EcsLite  | 100000   | 5          |    350,145 ns |     7.29 |          - | \n| Scellecs.Morpeh   | 100000   | 5          |  1,979,985 ns |    41.20 |        1 B | \n\n\n#### Query performance comparison: C++ vs C#\n\nPerformance reference [vanilla C++ implementation](docs/query-components-bench.cpp)\n\n| OS      | CPU | Lang. | Impl.             | Entities | Components | Mean          |\n|-------- | --- | ----- | ----------------- |--------- |----------- |--------------:|\n| macOS   | M2  | C++   | vanilla           | 100000   | 5          |     20,557 ns |\n| macOS   | M2  | C#    | Friflo.Engine.ECS | 100000   | 5          |     48,055 ns |\n| Windows | x64 | C++   | vanilla           | 100000   | 5          |     58,430 ns |\n| Windows | x64 | C#    | Friflo.Engine.ECS | 100000   | 5          |     79,058 ns |\n\n\u003cbr/\u003e\n\n\n## **Relations**\n\nSome ECS projects have support for [Entity Relationships](https://friflo.gitbook.io/friflo.engine.ecs/examples/component-types#entity-relationships).  \nCompared to relational databases: Entity relationships are similar to foreign keys referencing primary keys in other tables.\nECS implementations typically ensure [referential integrity](https://en.wikipedia.org/wiki/Referential_integrity).\nThis means there are never links to entities which doesn't exist.\n\nRelations enable *directed* links between entities aka entity relationships.  \n*Directed link* means that a link points from a source entity to a target entity.  \nA single entity can have multiple links to other target entities.\n\n### Add \u0026 Remove 1 / 100 link relations on 100 entities\n\n| Namespace         | Entities | Relations | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |---------- |--------------:|---------:|-----------:|\n| Friflo.Engine.ECS | 100      | 1         |      5,912 ns |     1.00 |          - | \n| Flecs.NET         | 100      | 1         |     10,552 ns |     1.78 |          - | \n| TinyEcs           | 100      | 1         |     15,864 ns |     2.68 |          - | \n| Arch              | 100      | 1         |     72,628 ns |    12.28 |    36800 B | \n| fennecs           | 100      | 1         |     94,414 ns |    15.97 |   180000 B | \n|                   |          |           |               |          |            | \n| Flecs.NET         | 100      | 100       |    976,119 ns |     0.78 |        1 B | \n| Friflo.Engine.ECS | 100      | 100       |  1,252,632 ns |     1.00 |        1 B | \n| Arch              | 100      | 100       |  4,353,920 ns |     3.48 |  2180006 B | \n| TinyEcs           | 100      | 100       |  4,694,910 ns |     3.75 |        8 B | \n| fennecs           | 100      | 100       | 71,847,234 ns |    57.35 | 93124905 B | \n\n\u003cbr/\u003e\n\nWhen dealing with an ECS following question arises at some point:  \n*\"Is it okay for performance to use an array, List\u003c\u003e or Dictionary\u003c\u003e as a component field\"?*  \nNo, its not 😲. Now each component has a one or more reference types.  \nAs a result there is no cache locality anymore and GC requires much more CPU \u0026 memory resources.  \nThis is the reason why many ECS projects have relations.\n\nA typical limitation of an ECS is that an entity can only contain one component of a certain type.  \nRelations can be used to **add multiple components of the same type** to a single entity.  \nTo differentiate relations added to the same entity following mechanisms are used:\n\n- **Friflo.Engine.ECS**         - A component field is used as discriminator specified in `IRelationComponent\u003cTKey\u003e`.\n- **Flecs.NET** \u0026 **TinyEcs**   - Tags are used as discriminator.\n- **Arch.Relationships**        - An additional entity with a component is used as discriminator.\n- **fennecs**                   - Reference type instances are used as discriminator.\n\n### Add \u0026 Remove 1 / 100 relations on 100 entities\n\n| Namespace         | Entities | Relations | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |---------- |--------------:|---------:|-----------:|\n| Friflo.Engine.ECS | 100      | 1         |      3,761 ns |     1.00 |          - | \n| Flecs.NET         | 100      | 1         |     12,266 ns |     3.26 |          - | \n| TinyEcs           | 100      | 1         |     23,416 ns |     6.22 |          - | \n| Arch              | 100      | 1         |     48,360 ns |    12.86 |    36800 B | \n| fennecs           | 100      | 1         |     96,676 ns |    25.71 |   180000 B | \n|                   |          |           |               |          |            | \n| Friflo.Engine.ECS | 100      | 10        |     47,569 ns |     1.00 |          - | \n| Flecs.NET         | 100      | 10        |    158,925 ns |     3.34 |          - | \n| Arch              | 100      | 10        |    204,024 ns |     4.29 |   240800 B | \n| TinyEcs           | 100      | 10        |    282,603 ns |     5.94 |        1 B | \n| fennecs           | 100      | 10        |  1,578,632 ns |    33.20 |  2568001 B | \n\n\n### Add \u0026 Remove 10 child entities on 100 parent entities\n\nChild / parent entity relationships are used to build a hierarchy / tree of entities.  \nIt is, among other things, a use case for scene trees, entity parenting or character rig skeletons.\n\n| Namespace         | Entities | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |--------------:|---------:|-----------:|\n| Friflo.Engine.ECS | 100      |     25,754 ns |     1.00 |          - | \n| Flecs.NET         | 100      |     94,588 ns |     3.67 |          - | \n| TinyEcs           | 100      |    191,267 ns |     7.43 |          - | \n| Arch              | 100      |    433,217 ns |    16.82 |   232801 B | \n| fennecs           | 100      |    929,259 ns |    36.08 |  1800001 B | \n\n\u003cbr/\u003e\n\n\n## **Command buffer**\n\nA command buffer is used to record entity changes in a buffer.  \nWhile recording the state of entities remains unchanged.  \nThese changes are applied to these entities when calling either   \n`Playback()`, `Execute()`, `Commit()` or `DeferEnd()`\n\n### Add \u0026 Remove 2 components on 100 entities using a command buffer\n\n1. Add components.    Apply changes.\n2. Remove components. Apply changes.\n\n| Namespace         | Entities | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |--------------:|---------:|-----------:|\n| Scellecs.Morpeh   | 100      |      5,020 ns |     0.58 |          - | \n| Friflo.Engine.ECS | 100      |      8,665 ns |     1.00 |          - | \n| TinyEcs           | 100      |     12,907 ns |     1.49 |     4800 B | \n| Flecs.NET         | 100      |     14,344 ns |     1.65 |          - | \n| DefaultEcs        | 100      |     16,319 ns |     1.88 |          - | \n| Myriad            | 100      |     27,799 ns |     3.21 |          - | \n| Arch              | 100      |     48,811 ns |     5.63 |     4800 B | \n\n\u003cbr/\u003e\n\n\n## **Events**\n\nECS implementations supporting callbacks for specific events are called **reactive**.  \nTypical event types are:\n- Add / Update / Remove component\n- Add / Remove tag\n- Create / Delete entity\n\n### Get callback event on Add \u0026 Remove 1 component on 100 entities\n\n| Namespace         | Entities | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |--------------:|---------:|-----------:|\n| DefaultEcs        | 100      |      2,605 ns |     0.33 |          - | \n| TinyEcs           | 100      |      4,395 ns |     0.56 |          - | \n| Friflo.Engine.ECS | 100      |      7,905 ns |     1.00 |          - | \n| Flecs.NET         | 100      |     11,251 ns |     1.42 |          - | \n\n[^1]:  Arch: Support for events requires a custom build. Performance of component related benchmarks will decrease.\n[^2]:  fennecs: Support for events is planned according to its project README.\n\n\u003cbr/\u003e\n\n\n## **Search**\n\nA search can be used to get all entities with a specific component field value.  \nThis type of search is typically executed in O(1) .  \nE.g. to find all entities having a `Player` component where `Player.name == \"Bob\"`\n```\nstruct Player { string name; } \n```\n\nA search can also be used for range queries to find all entities with a component field value in a [min, max] range.  \nE.g. a range query return all entities with a `Health` component where `Health.value` is between 10 and 100.\n```\nstruct Health { int value; } \n```\n\nSearch and Range Queries of component fields are explained at this [Wiki](https://friflo.gitbook.io/friflo.engine.ecs/examples/component-types#search).\n\n### Search component field in 1.000.000 entities\n\nExecute 1000 searches for different search values in a data set of 1.000.000 entities.  \nEach result has 1 match.\n\n| Namespace         | Entities | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |--------------:|---------:|-----------:|\n| Friflo.Engine.ECS | 1000000  |      4,745 ns |     1.00 |          - | \n\n### Search range of component fields in 1.000.000 entities\n\nExecute 1000 range queries with different [min, max] in a data set of 1.000.000 entities.  \nEach result has 100 matches.\n\n| Namespace         | Entities | Mean          | Ratio    | Allocated  | \n|------------------ |--------- |--------------:|---------:|-----------:|\n| Friflo.Engine.ECS | 1000000  |  1,512,413 ns |     1.00 |   560001 B | \n\n\u003cbr/\u003e\n\n\n# Setup\n\nThe benchmark project can be build and executed on **Windows**, **macOS** \u0026 **Linux**.  \nAll popular IDE's can be used to run and debug the project: **Rider**, **Visual Studio Code** \u0026 **Visual Studio**.\n\n**Benchmark constraints**\n\n- Each benchmark is **simple** and uses the fastest single threaded variant available.  \n  To obtain clarity a project must not have multiple variants of the same benchmark type.\n- A ECS framework must implement all [Basic](#basic) benchmarks. Reasons  \n  - Operations used in basic benchmarks are required to build a rudimentary application.\n  - Avoid cherry picking of benchmarks with good performance.\n- Each Benchmark shares no state or code with any other benchmarks.\n- Adding or removing a benchmark implementation has no effect on all others.\n- Each project has an extension class `BenchUtils` with two methods to used by its benchmarks.  \n  `BenchUtils.CreateEntities(int count)`  \n  `BenchUtils.AddComponents(this Entity[] entities)`\n- A package of the ECS must be available on nuget.\n\nThe benchmarks `CreateEntity` and `DeleteEntity` are changing the state of World which has influence on the benchmark measurement.  \nIf executing their `[Benchmark]` method multiple times the number of entities will grow / shrink for each method iteration.  \nThis would slow down the execution over time and give wrong measurement results.  \nTo avoid this these benchmarks are executed with 100.000 entities every time on a new World instance.\n\n\n# Contribution\n\nContributions are welcome.  \nOnly requirement: Ensure it compiles.\n\n- *How to add a single benchmark*?  \n  Copy an existing benchmark and make adaptations.\n\n- *How to add benchmarks for a new ECS project*?  \n  Copy an existing project and make adaptations.\n\n- *Adding a new benchmark category*?  \n  Open a new issue or discussion to explain the feature.\n\n\n# Benchmark CLI\n\nCurrently ~ 100 benchmarks\n\n- Running all benchmarks                    ~ 40 minutes\n- Running all benchmarks with `--job Short` ~ 10 minutes\n- Running all benchmarks with `--job Dry`   ~  1 minute (used by CI)\n\nThe published benchmarks are executed without: `--job` argument.  \nThe measurement difference when using `--job Short` were 2x in some benchmarks.  \n\nFor documentation of `--job` argument see [BenchmarkDotNet CLI args](https://github.com/dotnet/BenchmarkDotNet/blob/master/docs/articles/guides/console-args.md#more)\n\n### Windows CLI\n\n```php\ncd ./src\n\ndotnet run -c Release --filter *                                # run all benchmarks\ndotnet run -c Release --filter *AddRemoveComponents_Friflo*     # run a specific benchmark\ndotnet run -c Release --filter *AddRemoveComponents*            # run benchmarks of single category\ndotnet run -c Release --filter *Friflo*                         # run benchmarks of single project\ndotnet run -c Release --filter *Friflo* *Arch*                  # compare benchmarks of two projects\n\n# run basic benchmarks\ndotnet run -c Release --filter *AddRemoveComponents* *GetSetComponents* *CreateEntity* *CreateWorld* *DeleteEntity* *Query*\ndotnet run -c Release --filter *Links* *Relations*              # run relation benchmarks\ndotnet run -c Release --filter *CommandBuffer*                  # run command buffer benchmarks\ndotnet run -c Release --filter *Events*                         # run component events benchmarks\ndotnet run -c Release --filter *Search*                         # run search benchmarks\n```\n\n### macOS / Linux CLI\n\n```php\ncd ./src\n\ndotnet run -c Release --filter \\*                               # run all benchmarks\ndotnet run -c Release --filter \\*AddRemoveComponents_Friflo\\*   # run a specific benchmark\ndotnet run -c Release --filter \\*AddRemoveComponents\\*          # run benchmarks of single category\ndotnet run -c Release --filter \\*Friflo\\*                       # run benchmarks of single project\ndotnet run -c Release --filter \\*Friflo\\* \\*Arch\\*              # compare benchmarks of two projects\n\n# run basic benchmarks\ndotnet run -c Release --filter \\*AddRemoveComponents\\* \\*GetSetComponents\\* \\*CreateEntity\\* \\*CreateWorld\\* \\*DeleteEntity\\* \\*Query\\*\ndotnet run -c Release --filter \\*Links\\* \\*Relations\\*          # run relation benchmarks\ndotnet run -c Release --filter \\*CommandBuffer\\*                # run command buffer benchmarks\ndotnet run -c Release --filter \\*Events\\*                       # run component events benchmarks\ndotnet run -c Release --filter \\*Search\\*                       # run search benchmarks\n```\n\n# Other C# ECS Benchmarks\n\n- [Ecs.CSharp.Benchmark](https://github.com/Doraku/Ecs.CSharp.Benchmark)  \n  Popular C# ECS Benchmark with focus on large data sets: Create \u0026 query entities\n\n- [ecs-benchmark-runner-dotnet](https://github.com/cNoNim/ecs-benchmark-runner-dotnet)  \n  C# ECS benchmark frameworks with a near-real-world scenario test scenario.  \n  Benchmarks runs on multiple platforms: .NET, Native AOT \u0026 Unity.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffriflo%2FECS.CSharp.Benchmark-common-use-cases","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffriflo%2FECS.CSharp.Benchmark-common-use-cases","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffriflo%2FECS.CSharp.Benchmark-common-use-cases/lists"}