Вопрос

У меня есть подпись метода C ++, которая выглядит следующим образом:

    static extern void ImageProcessing(
        [MarshalAs(UnmanagedType.LPArray)]ushort[] inImage,
        [MarshalAs(UnmanagedType.LPArray)]ushort[] outImage,
        int inYSize, int inXSize);

Я обернул функцию в методы синхронизации, как внутренние, так и внешние. Внутренне, функция работает на 0,24 с. Внешне функция работает за 2,8 с, или примерно в 12 раз медленнее. В чем дело? Маршаллинг замедляет меня так сильно? Если это так, как я могу обойти это? Должен ли я перейти на небезопасный код и использовать указатели или что-то? Я в некотором замешательстве относительно того, откуда взялись дополнительные затраты времени.

Это было полезно?

Решение 3

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

Временной код, который я использовал, был следующим:

Ipp32s timer;
ippGetCpuFreqMhz(&timer);
Ipp64u globalStart = ippGetCpuClocks();
globalStart = ippGetCpuClocks() *2 - globalStart; //use this method to get rid of the overhead of getting clock ticks

      //do some stuff

Ipp64u globalEnd = ippGetCpuClocks(); 
globalEnd = ippGetCpuClocks() *2 - globalEnd;
std::cout << "total runtime: " << ((Ipp64f)globalEnd - (Ipp64f)globalStart)/((Ipp64f)timer *1000000.0f) << " seconds" << std::endl;

Этот код специфичен для компилятора Intel и разработан для обеспечения чрезвычайно точных измерений времени. К сожалению, такая предельная точность означает стоимость примерно 2,5 секунды на цикл Удаление временного кода сняло это временное ограничение.

Тем не менее, кажется, что время выполнения все еще задерживается - код сообщит о 0,24 с при включенном временном коде, и теперь сообщает о времени примерно 0,35 с, что означает, что скорость составляет около 50%.

Изменение кода на это:

  static extern void ImageProcessing(
     IntPtr inImage, //[MarshalAs(UnmanagedType.LPArray)]ushort[] inImage,
     IntPtr outImage, //[MarshalAs(UnmanagedType.LPArray)]ushort[] outImage,
     int inYSize, int inXSize);

и называется как:

        unsafe {
            fixed (ushort* inImagePtr = theInputImage.DataArray){
                fixed (ushort* outImagePtr = theResult){
                    ImageProcessing((IntPtr)inImagePtr,//theInputImage.DataArray,
                        (IntPtr)outImagePtr,//theResult,
                        ysize,
                        xsize);
                }
            }
        }

сокращает время выполнения до 0,3 с (в среднем три запуска). Все еще слишком медленный для моих вкусов, но повышение скорости в 10 раз, безусловно, в рамках приемлемости для моего босса.

Другие советы

Посмотрите на эта статья . Хотя основное внимание уделяется Compact Framework, общие принципы применимы и к рабочему столу. Соответствующая цитата из раздела анализа выглядит следующим образом:

  

Управляемый вызов напрямую не вызывает собственный метод. Вместо этого он вызывает метод-заглушку JITted, который должен выполнять некоторые служебные процедуры, такие как вызовы, для определения статуса выгрузки GC (чтобы определить, ожидает ли GC, и нам нужно подождать). Также возможно, что некоторый код маршаллинга также получит JITted в заглушку. Это все требует времени.

Изменить . Также стоит прочитать эту статью блога о совершенстве кода JITted - опять же, специфично для CF, но все еще актуально Также есть статья, в которой рассматривается глубина стека вызовов и ее влияние на производительность , хотя этот, вероятно, специфичен для CF (не тестируется на рабочем столе).

Вы пытались переключить два параметра массива на IntPtr? PInvoke работает максимально быстро, когда все типы в маршалинговой сигнатуре являются легковесными. Это означает, что Pinvoke сводится к простой memcpy для получения данных взад и вперед.

В моей команде мы нашли самый эффективный способ управления нашим слоем PInvoke -

<Ол>
  • Гарантия того, что все, что есть у Маршалла, является мрачным
  • Платите цену маршалу вручную, например, массивам, манипулируя классом IntPtr по мере необходимости. Это очень тривиально, так как у нас есть много методов / классов-оболочек.
  • Как и в случае с любым "!", это будет быстрее &. ответ, вам нужно профилировать это ваша собственная база кода. Мы пришли к этому решению только после того, как несколько методов были рассмотрены и представлены.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top