Skip to content

perf: optimize _abilities_count_and_build_progress - #253

Open
SamOgon-one wants to merge 3 commits into
BurnySc2:developfrom
SamOgon-one:patch-2
Open

SamOgon-one wants to merge 3 commits into
BurnySc2:developfrom
SamOgon-one:patch-2

Conversation

@SamOgon-one

@SamOgon-one SamOgon-one commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Optimize _abilities_count_and_build_progress

Description

Optimizes _abilities_count_and_build_progress by eliminating intermediate Python object allocations and reducing attribute lookup overhead in the main loop over all_own_units.

Note: This PR uses self.game_data.structure_type_ids, which replaces structure_types introduced in PR #252. Once #252 is merged, tests should be re-run to verify everything passes cleanly.

How it optimizes & speeds up:

  1. Bypasses UnitOrder instantiation: Instead of iterating over unit.orders (which creates a new UnitOrder instance and converts target coordinates to Point2 for every single order), we read directly from unit._proto.orders.
  2. Fast Enum resolution: Uses AbilityId._value2member_map_ cached in a local variable for direct $O(1)$ dict lookups of order.ability_id.
  3. Loop-invariant hoisting: Hoists is_terran = self.race == Race.Terran and structure_type_ids = self.game_data.structure_type_ids out of the unit loop.
  4. Direct protobuf field access: Reads proto.build_progress and proto.unit_type directly to avoid property overhead where applicable.

Benchmark / Profiling:

According to py-spy profiling across a 10-minute Protoss game:

  • Before: _abilities_count_and_build_progress accounted for 3.5% of total CPU runtime.
  • After: Reduced to 2.6% of total CPU runtime (~26% relative reduction for this method).

### Optimize `_abilities_count_and_build_progress`

#### Description
Optimizes `_abilities_count_and_build_progress` by eliminating intermediate Python object allocations and reducing attribute lookup overhead in the main loop over `all_own_units`.

#### How it optimizes & speeds up:
1. **Bypasses `UnitOrder` instantiation:** Instead of iterating over `unit.orders` (which creates a new `UnitOrder` instance and converts target coordinates to `Point2` for every single order), we read directly from `unit._proto.orders`.
2. **Fast Enum resolution:** Uses `AbilityId._value2member_map_` cached in a local variable for direct $O(1)$ dict lookups of `order.ability_id`.
3. **Loop-invariant hoisting:** Hoists `is_terran = self.race == Race.Terran` and `structure_type_ids = self.game_data.structure_type_ids` out of the unit loop.
4. **Direct protobuf field access:** Reads `proto.build_progress` and `proto.unit_type` directly to avoid property overhead where applicable.

#### Benchmark / Profiling:
According to `py-spy` profiling across a 10-minute Protoss game:
* **Before:** `_abilities_count_and_build_progress` accounted for **3.5%** of total CPU runtime.
* **After:** Reduced to **2.6%** of total CPU runtime (~26% relative reduction for this method).
Cast ability_by_id to the correct type for better type safety.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant