Подтвердить что ты не робот

Существует ли временное ограничение С# 28 временного ограничения?

Я работаю над оптимизацией программы моделирования физики, используя Red Gate Performance Profiler. Одна часть кода, касающаяся обнаружения столкновений, имела около 52 из следующих небольших проверок, касающихся ячеек в 26 направлениях в трех измерениях, в двух случаях.

CollisionPrimitiveList cell = innerGrid[cellIndex + 1];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

cell = innerGrid[cellIndex + grid.XExtent];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

cell = innerGrid[cellIndex + grid.XzLayerSize];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

Как чрезвычайно сложный цикл программы, все это должно было быть одним и тем же методом, но я обнаружил, что внезапно после того, как я расширил область от двух измерений до трех измерений (увеличение числа до 52 проверок от 16), вдруг cell.Count уже не был привязан, хотя это простой геттер. public int Count { get { return count; } } Это вызвало огромный удар по производительности, и мне потребовалось немало времени, чтобы обнаружить, что, когда cell.Count появился в методе 28 раз или меньше, он был вложен каждый раз, но как только cell.Count появился в методе 29 раз или более, он не был установлен в одно время (хотя подавляющее большинство звонков было из наихудшего сценария части кода, которые редко выполнялись.)

Итак, вернемся к моему вопросу, есть ли у кого-нибудь идеи обойти этот предел? Я думаю, что простое решение состоит в том, чтобы сделать поле счетчика внутренним, а не частным, но я бы хотел получить лучшее решение, чем это, или, по крайней мере, просто лучше понять ситуацию. Я бы хотел, чтобы подобное было упомянуто на странице "Высокопроизводительные управляемые приложения Microsoft Writing" на http://msdn.microsoft.com/en-us/library/ms973858.aspx, но, к сожалению, это не так (возможно, потому что от того, насколько произвольным считается ограничение на количество 28?)

Я использую .NET 4.0.

EDIT: Похоже, я неверно истолковал свое небольшое тестирование. Я обнаружил, что отказ встроенных был вызван не самими методами, а называемыми примерно 28+ раз, но потому, что метод, которым они должны быть встроены, является "слишком длинным" по некоторому стандарту. Это все еще меня смущает, потому что я не вижу, как простой геттер может быть рационально не привязан (и производительность значительно лучше с ними, так как мой профилировщик явно показывает мне), но, по-видимому, компилятор CLI JIT отказывается встраивать что-либо только потому, что метод уже велик (игра с небольшими вариациями показала мне, что этот предел - это размер кода (от idasm) 1500, выше которого не выполняется ни одна вставка, даже в случае моих геттеров, которые, как показали некоторые тесты, не добавили дополнительного кода накладные расходы должны быть встроены).

Спасибо.

4b9b3361

Ответ 1

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

Обратите внимание, что количество раз, когда метод вложен, скорее всего, зависит от размера нативного кода для этого метода (см. http://blogs.msdn.com/b/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx), число 28 относится к этому свойству. Простое свойство, скорее всего, будет добавлено больше времени, чем более сложный метод.

Ответ 2

Прямо, это не объясняет, почему 28 - это магическое число, но мне любопытно, что произойдет, если вы сопоставьте все ваши экземпляры CollisionListPrimitive вашего кандидата в массив, а затем вызовите блок "if count > 0" внутри цикл массива?

Является ли вызов cell.Count снова выполненным внутри?

например.

CollisionPrimitiveList[] cells = new CollisionPrimitiveList {
    innerGrid[cellIndex + 1],
    innerGrid[cellIndex + grid.XExtent],
    innerGrid[cellIndex + grid.XzLayerSize]
    // and all the rest
};

// Loop over cells - for demo only. Use for loop or LINQ'ify if faster
foreach (CollisionPrimitiveList cell in cells) 
{
    if (cell.Count > 0)
        contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);  
}

Я знаю, что производительность - это проблема, и у вас возникнут накладные расходы, которые создадут массив и пройдут через него, но если cell.Count снова будет встроен, может ли производительность по-прежнему быть лучше/достаточно хорошо?

Ответ 3

Я предполагаю (хотя и никак не положительно), что это может иметь отношение к упомянутой проблеме enregistration - возможно, что CLR выделяет новую переменную для каждого оператора if и что они превышают в общей сложности 64 переменных. Считаете ли вы, что это может быть так?