Shroud, access ProjectedCellLayer by array index. Shroud.touchedCount to avoid Tick updates.

Shroud, access ProjectedCellLayer by array index over PPos index.

Performance improvement. Avoid the multiple PPos to array index
conversions in the same method call by calculating the cell
layer index once.

Background:

`Shroud.Tick` and `ProjectedCellLayer.Index(PPos puv)` shows up
in profile reports as one of the most expensive methods
(9% of CPU time).

In `Shroud.Tick` calls `ProjectedCellLayer.Index(PPos puv)` multiple
times for the same or different cell layers of the same dimension.

Improvement:

Benchmark results show an 0.5ms mean improvement in tick
time and 0.3 improvement in render time -
on a replay map of 1.12 min of play at max speed.

Render time:
       render222052(bleed)  render221934(this commit)
count   8144.000000   8144.000000
mean      11.410075     11.470100
std        5.004876      4.731463
min        3.450700      3.638400
25%        7.409100      7.015900
50%       12.410600     12.435900
75%       13.998100     14.242900
max      149.036200    149.656500

Tick time:
       tick_time222043(bleed)  tick_time221923(this commit)
count      2366.000000      2366.000000
mean          4.762923         4.275833
std           3.240976         3.206362
min           0.263900         1.653600
25%           4.145375         3.668600
50%           4.779350         4.240050
75%           5.232575         4.611775
max          85.751800        87.387100

Shroud.touchedCount to avoid Tick updates if no cells touched.

Avoids iterating over all map cells of the `touched` cell layer.

Tick time improvement of 40%+ - during at least the first two
minutes of gameplay.

During the first minutes of a game - out of every 1000 ticks
only 10-100 result in the Shroud - of any player - to be touched.

For certains player types (Neutral, Creep) less Shroud updates
are expected throughout a complete game.

Throughout a complete game human/AI players can also have no
Shroud touches during certain Ticks.
This commit is contained in:
Vapre
2020-10-21 22:23:15 +02:00
committed by Paul Chote
parent 7f32776701
commit 17996dfdfc
2 changed files with 73 additions and 31 deletions

View File

@@ -22,11 +22,24 @@ namespace OpenRA
: base(gridType, size) { }
// Resolve an array index from map coordinates.
int Index(PPos uv)
public int Index(PPos uv)
{
return uv.V * Size.Width + uv.U;
}
public T this[int index]
{
get
{
return entries[index];
}
set
{
entries[index] = value;
}
}
/// <summary>Gets or sets the layer contents using projected map coordinates.</summary>
public T this[PPos uv]
{

View File

@@ -99,6 +99,7 @@ namespace OpenRA.Traits
readonly ProjectedCellLayer<short> generatedShroudCount;
readonly ProjectedCellLayer<bool> explored;
readonly ProjectedCellLayer<bool> touched;
bool anyCellTouched;
// Per-cell cache of the resolved cell type (shroud/fog/visible)
readonly ProjectedCellLayer<ShroudCellType> resolvedType;
@@ -142,6 +143,7 @@ namespace OpenRA.Traits
generatedShroudCount = new ProjectedCellLayer<short>(map);
explored = new ProjectedCellLayer<bool>(map);
touched = new ProjectedCellLayer<bool>(map);
anyCellTouched = true;
// Defaults to 0 = Shroud
resolvedType = new ProjectedCellLayer<ShroudCellType>(map);
@@ -159,31 +161,42 @@ namespace OpenRA.Traits
void ITick.Tick(Actor self)
{
if (!anyCellTouched)
return;
anyCellTouched = false;
if (OnShroudChanged == null)
return;
foreach (var puv in map.ProjectedCells)
{
if (!touched[puv])
var index = touched.Index(puv);
if (!touched[index])
continue;
touched[puv] = false;
touched[index] = false;
var type = ShroudCellType.Shroud;
if (explored[puv] && (!shroudGenerationEnabled || generatedShroudCount[puv] == 0 || visibleCount[puv] > 0))
if (explored[index])
{
var count = visibleCount[puv];
if (passiveVisibilityEnabled)
count += passiveVisibleCount[puv];
var count = visibleCount[index];
if (!shroudGenerationEnabled || count > 0 || generatedShroudCount[index] == 0)
{
if (passiveVisibilityEnabled)
count += passiveVisibleCount[index];
type = count > 0 ? ShroudCellType.Visible : ShroudCellType.Fog;
type = count > 0 ? ShroudCellType.Visible : ShroudCellType.Fog;
}
}
var oldResolvedType = resolvedType[puv];
resolvedType[puv] = type;
var oldResolvedType = resolvedType[index];
if (type != oldResolvedType)
{
resolvedType[index] = type;
OnShroudChanged(puv);
}
}
Hash = Sync.HashPlayer(self.Owner) + self.World.WorldTick;
@@ -231,21 +244,23 @@ namespace OpenRA.Traits
if (!map.Contains(puv))
continue;
touched[puv] = true;
var index = touched.Index(puv);
touched[index] = true;
anyCellTouched = true;
switch (type)
{
case SourceType.PassiveVisibility:
passiveVisibilityEnabled = true;
passiveVisibleCount[puv]++;
explored[puv] = true;
passiveVisibleCount[index]++;
explored[index] = true;
break;
case SourceType.Visibility:
visibleCount[puv]++;
explored[puv] = true;
visibleCount[index]++;
explored[index] = true;
break;
case SourceType.Shroud:
shroudGenerationEnabled = true;
generatedShroudCount[puv]++;
generatedShroudCount[index]++;
break;
}
}
@@ -261,17 +276,19 @@ namespace OpenRA.Traits
// Cells outside the visible bounds don't increment visibleCount
if (map.Contains(puv))
{
touched[puv] = true;
var index = touched.Index(puv);
touched[index] = true;
anyCellTouched = true;
switch (state.Type)
{
case SourceType.PassiveVisibility:
passiveVisibleCount[puv]--;
passiveVisibleCount[index]--;
break;
case SourceType.Visibility:
visibleCount[puv]--;
visibleCount[index]--;
break;
case SourceType.Shroud:
generatedShroudCount[puv]--;
generatedShroudCount[index]--;
break;
}
}
@@ -284,10 +301,15 @@ namespace OpenRA.Traits
{
foreach (var puv in cells)
{
if (map.Contains(puv) && !explored[puv])
if (map.Contains(puv))
{
touched[puv] = true;
explored[puv] = true;
var index = touched.Index(puv);
if (!explored[index])
{
touched[index] = true;
anyCellTouched = true;
explored[index] = true;
}
}
}
}
@@ -299,10 +321,12 @@ namespace OpenRA.Traits
foreach (var puv in map.ProjectedCells)
{
if (!explored[puv] && s.explored[puv])
var index = touched.Index(puv);
if (!explored[index] && s.explored[index])
{
touched[puv] = true;
explored[puv] = true;
touched[index] = true;
anyCellTouched = true;
explored[index] = true;
}
}
}
@@ -311,10 +335,12 @@ namespace OpenRA.Traits
{
foreach (var puv in map.ProjectedCells)
{
if (!explored[puv])
var index = touched.Index(puv);
if (!explored[index])
{
touched[puv] = true;
explored[puv] = true;
touched[index] = true;
anyCellTouched = true;
explored[index] = true;
}
}
}
@@ -323,9 +349,12 @@ namespace OpenRA.Traits
{
foreach (var puv in map.ProjectedCells)
{
touched[puv] = true;
explored[puv] = (visibleCount[puv] + passiveVisibleCount[puv]) > 0;
var index = touched.Index(puv);
touched[index] = true;
explored[index] = (visibleCount[index] + passiveVisibleCount[index]) > 0;
}
anyCellTouched = true;
}
public bool IsExplored(WPos pos)