C# Арифметика указателя c медленнее, чем явно, если - PullRequest
1 голос
/ 24 февраля 2020

В настоящее время я портирую реализацию дерева критических битов с C на C#, используя небезопасный C#. Я заметил какое-то странное поведение с точки зрения производительности, которое я не могу объяснить.

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

    [StructLayout(LayoutKind.Sequential, Pack = 0)]
    internal unsafe struct CritBitTreeNode
    {
        public byte Type;

        public CritBitTreeNode* Child1;

        public CritBitTreeNode* Child2;

        public int Byte;

        public byte Otherbits;
    }

В зависимости от расчетного направления, я хочу следовать Child1 или Child2 в al oop. Таким образом, код выглядит примерно так:

while (node->Type == 1)
{
    int direction = CalculateDirection(...)
    node = direction == 0 ? node->Child1 : node->Child2;
}

Теперь я подумал, что иметь доступ к элементу if и затем должно быть медленнее, чем просто захватить указатель и добавить к нему направление следующим образом:

node = *(&node->Child1 + direction)

Оказывается, мое предположение было неверным. Мои тесты сравнивают мой алгоритм с хэш-набором по умолчанию. Изменение этой единственной строки приводит к изменению соотношения с довольно хорошего 0,75 до довольно плохого 1,33 (базовый хэшсет содержит). Может кто-нибудь объяснить мне, почему арифметика указателя c кажется медленнее?

Полный исходный код можно найти здесь (метод Contains): https://github.com/TimHeinrich/CritBitTree/blob/master/CritBitTree/UnmanagedCritBitTree.cs

Я также пытался воспроизвести эту проблему с помощью микробенчмарка, но безуспешно, арифметика указателей там выигрывает, поэтому я полагаю, что это должно быть что-то совершенно иное, например, условие ветвления? Любое понимание этого очень ценится!

...