Улучшить производительность Bitconverter.ToInt16 - PullRequest
0 голосов
/ 22 октября 2018

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

В данный момент я собираю данные, которые доставляются в байтовом массиве 65536 байтов. Первые два байта представляют 16 бит данных в формате little-endian .Эти два байта должны быть помещены в первый элемент двойного массива.Вторые два байта должны быть помещены в первый элемент другого двойного массива.Затем это повторяется для всех байтов в буфере 65536, так что вы получаете 2 double[] массива размером 16384.

В настоящее время я использую BitConverter.ToInt16, как показано в коде.Для запуска требуется около 0,3 мс, но это нужно сделать 10 раз, чтобы получить пакет для отправки на аудиовыход.Таким образом, накладные расходы составляют 3 мс, что достаточно для того, чтобы некоторые пакеты не были доставлены вовремя.

Код

byte[] buffer = new byte[65536];
double[] bufferA = new double[16384];
double[] bufferB = new double[16384]

for(int i= 0; i < 65536; i +=4)
{
    bufferA[i/4] = BitConverter.ToInt16(buffer, i);
    bufferB[i/4] = BitConverter.ToInt16(buffer, i+2);
}

Как я могу улучшить это?Можно ли скопировать значения с небезопасным кодом?У меня нет опыта в этом.Спасибо

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

"Так что каждая миллисекунда считается."Если это так, вы имеете дело с Программирование в реальном времени здесь.Несмотря на всю свою мощь, среда .NET Runtime не идеальна для программирования в реальном времени.

Управление памятью мусора само по себе, как правило, дисквалифицирует для программирования в реальном времени .

Теперь выможет изменить .NET с управления памятью GC на прямое управление.И уменьшите производительность, перейдя на небезопасный код и используя голые указатели.Но это именно то место, где вы удалили все точки продажи .NET.И было бы лучше, если бы две написали всю эту часть / ту часть на нативном C ++ для начала.

0 голосов
/ 22 октября 2018

Это дает мне примерно тройную скорость в релизе, используя Указатели и unsafe.Могут быть и другие микрооптимизации, но я не могу оставить эти детали до массы

Обновлено

Мой оригинальный алгоритм имел ошибку и мог быть улучшен

Модифицированный код

public unsafe (double[], double[]) Test2(byte[] input, int scale)
{
   var bufferA = new double[input.Length / 4];
   var bufferB = new double[input.Length / 4];

   fixed (byte* pSource = input)
      fixed (double* pBufferA = bufferA, pBufferB = bufferB)
      {
         var pLen = pSource + input.Length;
         double* pA = pBufferA, pB = pBufferB;

         for (var pS = pSource; pS < pLen; pS += 4, pA++, pB++)
         {
            *pA = *(short*)pS;
            *pB = *(short*)(pS + 2);
         }
      }

   return (bufferA, bufferB);
}

Behnchmarks

Каждый тест выполняется 1000 раз, мусор собирается перед каждым запуском и масштабируется до различной длины массива.Все результаты сверяются с исходной OP-версией

Тестовая среда

----------------------------------------------------------------------------
Mode             : Release (64Bit)
Test Framework   : .NET Framework 4.7.1 (CLR 4.0.30319.42000)
----------------------------------------------------------------------------
Operating System : Microsoft Windows 10 Pro
Version          : 10.0.17134
----------------------------------------------------------------------------
CPU Name         : Intel(R) Core(TM) i7-3770K CPU @ 3.50GHz
Description      : Intel64 Family 6 Model 58 Stepping 9
Cores (Threads)  : 4 (8)      : Architecture  : x64
Clock Speed      : 3901 MHz   : Bus Speed     : 100 MHz
L2Cache          : 1 MB       : L3Cache       : 8 MB
----------------------------------------------------------------------------

Результаты

--- Random Set of byte ------------------------------------------------------
| Value    |    Average |    Fastest |    Cycles | Garbage | Test |    Gain |
--- Scale 16,384 -------------------------------------------- Time 13.727 ---
| Unsafe   |  19.487 µs |  14.029 µs |  71.479 K | 0.000 B | Pass | 59.02 % |
| Original |  47.556 µs |  34.781 µs | 169.580 K | 0.000 B | Base |  0.00 % |
--- Scale 32,768 -------------------------------------------- Time 14.809 ---
| Unsafe   |  40.398 µs |  31.274 µs | 145.024 K | 0.000 B | Pass | 56.62 % |
| Original |  93.127 µs |  79.501 µs | 329.320 K | 0.000 B | Base |  0.00 % |
--- Scale 65,536 -------------------------------------------- Time 18.984 ---
| Unsafe   |  68.318 µs |  43.550 µs | 245.083 K | 0.000 B | Pass | 68.34 % |
| Original | 215.758 µs | 160.171 µs | 758.955 K | 0.000 B | Base |  0.00 % |
--- Scale 131,072 ------------------------------------------- Time 22.620 ---
| Unsafe   | 120.764 µs |  79.208 µs | 428.626 K | 0.000 B | Pass | 71.24 % |
| Original | 419.889 µs | 322.388 µs |   1.461 M | 0.000 B | Base |  0.00 % |
-----------------------------------------------------------------------------
...