3.2 KiB
lofivor sandbox - stress test design
a minimal harness for finding entity count ceilings on weak hardware before designing game systems.
goals
purpose: answer "how many simple entities can we update and render at 60fps?"
target hardware:
- primary: intel i5-6500T + HD 530 (thinkcentre m900) @ 1280x1024
- secondary: windows laptop for dev iteration
what it does:
- spawns colored circles that drift toward screen center
- manual controls to add/remove entities in real-time
- on-screen metrics: entity count, frame time (ms), update time, render time
- circles respawn at random edge when reaching center
what it doesn't do (yet):
- no collision detection
- no player input beyond entity count controls
- no game logic, damage, spawning waves
- no particles or visual effects
success criteria:
- locked 60fps with some meaningful entity count (finding that number is the goal)
- clear breakdown of where frame time goes (CPU update vs GPU render)
- stable enough to leave running while tweaking counts
data structures
const Entity = struct {
x: f32,
y: f32,
vx: f32,
vy: f32,
color: u32,
};
simple flat array of entities. no ECS, no spatial partitioning, no indirection. measuring the baseline - fancy structures come later.
memory budget: 20 bytes per entity. 10k entities = 200KB (fits in L2 cache on skylake).
update loop
for each entity:
x += vx
y += vy
if distance_to_center < threshold:
respawn at random edge
recalculate vx, vy toward center
~5 float ops per entity per frame. no collision, no branching beyond respawn check.
velocity: on spawn, compute normalized direction to center, multiply by constant speed, store vx/vy.
rendering
each frame:
- clear screen (dark background #0a0a12)
- draw all entities as filled circles (4px radius)
- draw metrics overlay
entity color: cyan (#00ffff) - bright against dark background
metrics overlay (top-left):
entities: 5000
frame: 12.4ms
update: 8.2ms
render: 4.1ms
controls
| key | action |
|---|---|
= / + |
add 100 entities |
- |
remove 100 entities |
shift + = |
add 1000 entities |
shift + - |
remove 1000 entities |
space |
pause update loop (render continues) |
r |
reset to 0 entities |
pause isolates render cost from update cost.
what we're measuring
key questions:
- what's the entity ceiling at 60fps? (where frame time crosses 16.6ms)
- is it CPU-bound or GPU-bound? (compare update vs render time)
- where does it fall apart? (gradual degradation or sudden cliff?)
hypotheses to test:
- HD 530 might struggle with thousands of individual draw calls (GPU-bound)
- if CPU-bound, update loop needs SIMD or better memory access
- skylake's 4 cores are untouched - parallelism is a future lever
next steps based on results
| bottleneck | next experiment |
|---|---|
| render (draw calls) | batch rendering - instancing, sprite batches |
| update (CPU) | SIMD, struct-of-arrays layout, multithreading |
| both equally | optimize either for gains |
stretch measurements
- memory bandwidth (cache-bound?)
- draw call count vs batched draws
- fixed-point vs float update cost comparison