Оптимизация функции большого трафика в XNA - PullRequest
4 голосов
/ 31 октября 2009

У меня есть функция, которая вызывается сотни тысяч раз за обновление, и мне нужно ее оптимизировать. Теперь я обычно следую правилу «не оптимизировать слишком рано», но это критическая функция, на которую тратится практически все время моего кода, поэтому все, что вы можете предложить, поможет. Я также не очень знаком с какими-либо советами и рекомендациями, которые можно использовать для оптимизации кода XNA или c #. Вы можете мне помочь?

if (linearPosition.Y < _min.Y || linearPosition.Y > _max.Y)// the nonlinear space commisioned doesn't cover it so that's the behavior i want, same case with next line
{
    return linearPosition;
}
if (linearPosition.X < _min.X || linearPosition.X > _max.X)
{
    return linearPosition;
}
PositionData[] fourNearestPoints = new PositionData[4] 
{
    new PositionData {distance = float.MaxValue},
    new PositionData {distance = float.MaxValue},
    new PositionData {distance = float.MaxValue},
    new PositionData {distance = float.MaxValue}
};

for (int x = 0; x < _restPositions.GetLength(0); x++)
{
    for (int y = 0; y < _restPositions.GetLength(1); y++)
    {
        PositionData temp = new PositionData
        {
            indexX = x,
            indexY = y,
            value = _restPositions[x,y],
            distance = (linearPosition - _restPositions[x,y]).Length()
        };
        if (temp.distance < fourNearestPoints[0].distance)
        {
            fourNearestPoints[3] = fourNearestPoints[2];
            fourNearestPoints[2] = fourNearestPoints[1];
            fourNearestPoints[1] = fourNearestPoints[0];
            fourNearestPoints[0] = temp;
        }
    }
}
Vector2 averageRestVector = new Vector2((fourNearestPoints[0].value.X +
    fourNearestPoints[1].value.X +
    fourNearestPoints[2].value.X +
    fourNearestPoints[3].value.X) / 4,
    (fourNearestPoints[0].value.Y +
    fourNearestPoints[1].value.Y +
    fourNearestPoints[2].value.Y +
    fourNearestPoints[3].value.Y) / 4);
Vector2 averageDeformedVector = new Vector2((_deformedPositions[fourNearestPoints[0].indexX, fourNearestPoints[0].indexY].X +
    _deformedPositions[fourNearestPoints[1].indexX, fourNearestPoints[1].indexY].X +
    _deformedPositions[fourNearestPoints[2].indexX, fourNearestPoints[2].indexY].X +
    _deformedPositions[fourNearestPoints[3].indexX, fourNearestPoints[3].indexY].X) / 4,
    (_deformedPositions[fourNearestPoints[0].indexX, fourNearestPoints[0].indexY].Y +
    _deformedPositions[fourNearestPoints[1].indexX, fourNearestPoints[1].indexY].Y +
    _deformedPositions[fourNearestPoints[2].indexX, fourNearestPoints[2].indexY].Y +
    _deformedPositions[fourNearestPoints[3].indexX, fourNearestPoints[3].indexY].Y) / 4);

Vector2 displacement = averageDeformedVector - averageRestVector;
return linearPosition + displacement;

Ответы [ 2 ]

2 голосов
/ 31 октября 2009

Во-первых, попробуйте использовать одномерный массив вместо прямоугольного массива для _restPositions - CLR оптимизирован для одномерных массивов, начинающихся с нуля. Просто сохраните индекс в массиве и увеличивайте его на каждой итерации:

int index = 0;
// I'm assuming you can pass in width and height separately
for (int x = 0; x < width; x++)
{
    for (int y = 0; y < height; y++)
    {
        PositionData temp = new PositionData
        {
            indexX = x,
            indexY = y,
            value = _restPositions[index],
            distance = (linearPosition - _restPositions[index]).Length()
        };
        if (temp.distance < fourNearestPoints[0].distance)
        {
            fourNearestPoints[3] = fourNearestPoints[2];
            fourNearestPoints[2] = fourNearestPoints[1];
            fourNearestPoints[1] = fourNearestPoints[0];
            fourNearestPoints[0] = temp;
        }
        index++;
    }
}

Если бы вы могли создать конструктор для PositionData, который бы принимал соответствующие значения вместо того, чтобы иметь отдельные установщики свойств, то может также помочь.

Вы также индексируете в fourNearestPoints несколько раз - есть ли причина не просто использовать четыре локальные переменные? Это мало что даст, но ты никогда не узнаешь ...

2 голосов
/ 31 октября 2009

Первое, что я бы попробовал, это потерять массив fourNearestPoints ... Возможно, используя всего 4 переменные для 4 ближайших местоположений. Вы всегда рассматриваете это как постоянный индекс, так что это должно быть простое изменение, особенно если вы называете его как индекс массива:

PositionData fourNearestPoints_0 = ...,
             fourNearestPoints_1 = ...,
             fourNearestPoints_2 = ...,
             fourNearestPoints_3 = ...;

Следующее, на что я посмотрю, это использование _restPositions; Я не знаю, будет ли оптимизирован GetLength (в этом использовании), поэтому я бы попробовал предварительно кэшировать это. В линейном массиве оптимизируется .Length (по крайней мере, в полной CLR), но не GetLength AFAIK:

int width = _restPositions.GetLength(0), height = _restPositions.GetLength(1);
for (int x = 0; x < width; x++)
{
    for (int y = 0; y < height; y++)

Также; что такое PositionData? A struct или class? Я хотел бы попробовать это как: убедиться, что он неизменен, и передать данные через конструктор, чтобы сделать IL тоньше:

PositionData temp = new PositionData(x, y, _restPositions[x,y],
        (linearPosition - _restPositions[x,y]).Length());

Далее вы выполняете некоторую работу, от которой большую часть времени отказываются:

    PositionData temp = new PositionData
    {
        indexX = x,
        indexY = y,
        value = _restPositions[x,y],
        distance = (linearPosition - _restPositions[x,y]).Length()
    };
    if (temp.distance < fourNearestPoints[0].distance)
    {
        fourNearestPoints[3] = fourNearestPoints[2];
        fourNearestPoints[2] = fourNearestPoints[1];
        fourNearestPoints[1] = fourNearestPoints[0];
        fourNearestPoints[0] = temp;
    }

Я бы сделал:

var distance = (linearPosition - _restPositions[x,y]).Length();
if (distance < fourNearestPoints_0.distance) {
    fourNearestPoints_3 = fourNearestPoints_2;
    fourNearestPoints_2 = fourNearestPoints_1;
    fourNearestPoints_1 = fourNearestPoints_0;
    fourNearestPoints_0 = new PositionData(x, y, _restPositions[x,y], distance);
}

Меня также интересует эта строка distance=...; есть много того, чего мы не можем увидеть, что может потребовать больше работы - оператор - и метод Length().


Прав ли я, предполагая, что Length() включает квадратный корень? (дорого) Вы можете избежать этого, работая вместо этого на квадратном расстоянии. Возможно, вам придется сделать это явно с помощью метода квадратной длины, который не берет корень, и сравнивать квадратные длины по всей длине, но вы можете сэкономить много циклов ЦП. Это доступно как LengthSquared () .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...