Skip to content

Rezangyal/cpp_coroutine_test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C++ Coroutines in Game Object Control (Experimental Project)

This project explores how modern C++ coroutines can be used to control game object behavior, and evaluates their performance and practicality in a real-time game-like environment.

Key Takeaways

  • Coroutines can be a very expressive and clean way to write control logic.
  • Performance measurements can vary significantly when other systems (e.g. rendering) run in parallel.
    → It is more meaningful to evaluate impact on total frame time rather than isolated execution time.
  • The size of a coroutine frame cannot be queried, making it difficult to implement a proper custom allocator.
  • Accessing the coroutine's promise object from within the coroutine body requires non-trivial workarounds.
  • The Visual Studio 2022 + C++20 coroutine implementation is slow. There is clear room for improvement (see CoroGoto approach).
  • Using a coroutine introduces roughly ~40 ns overhead per invocation (hardware dependent).
  • As of 2026, the C++ coroutine ecosystem still feels immature and underdeveloped.

Tested Approaches

Basic

Baseline implementation using traditional control flow.

  • Fastest solution, but not necessarily the cleanest (though trivial in this case)
  • No per-object control function calls
  • Logic is expanded inside a single loop
  • BasicTargets is a separate persistent array (state survives between ticks)
  • BasicTargets[Index].X is used as a flag to indicate initialization

CoroAllInOne

Coroutine-based implementation with the cleanest logic.

  • No need to store per-object state manually
  • The coroutine system preserves state automatically between calls
  • Downsides:
    • Coroutine state is ~320 bytes even for trivial logic
    • Allocated dynamically on the heap by default

CoroGoto

Coroutine simulation using goto.

  • Manually implemented → fragile and hard to maintain
  • Performance close to the Basic implementation
  • In an ideal world, this is roughly how a compiler could implement coroutines
  • If compiler-generated, it would remove fragility and make coroutines far more attractive
  • State size is minimal (similar to Basic: status:int + Target)

CoroSetJump

Coroutine simulation using setjmp.

  • Similar conceptually to the goto solution
  • Tested so others don't have to 🙂
  • Extremely slow, not practical

CoroTwoLevel

Tests coroutine behavior in a more complex system with dynamic creation.

  • Simulates real-world usage with dynamically spawned coroutines
  • introduces additional overhead

Benchmark Results

Platform:
i5 @ 3200 MHz, RTX 2070, Visual Studio 2022, C++20 mode, UE 5.7, Shipping build


Scenario 1

1,000,000 position calculations per frame, first 10,000 objects rendered

Method CalcPosition (ms) Frame (ms)
Basic 15.4 18.1
CoroAllInOne 53.5 56.1
CoroGoto 18.53 21.12

Scenario 2

1,000,000 position calculations per frame, first 80,000 objects rendered

Method CalcPosition (ms) Frame (ms) Additonal time (ms)
Basic 23.1 38.9 0
CoroAllInOne 62.6 76.4 37.5
CoroGoto 26.25 41.0 2.1
CoroSetJump ~1280 ~1320 too many.
CoroTwoLevel 88.1 102.0 63.1

Conclusion

While C++ coroutines provide a clean and expressive abstraction, their current implementations come with significant performance and usability drawbacks in performance-critical environments like games.

For now:

  • They are great for clarity
  • But questionable for high-performance gameplay systems

The gap between ideal coroutine behavior and current compiler implementations remains substantial.

About

cpp coroutine test with ue5.7

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors