Как стать автором
Обновить

Комментарии 43

Интересно было бы сравнить с аналогичными реализациями на Питоне (особенно с использованием библиотек вроде NumPy).

Наивная реализация же на Python будет на 2-3 порядка медленее. А библиотеки типа NumPy — это и есть кирпичики. Если из них получается собрать алгоритм, то он будет быстрым. А если нет, то, увы, придётся переписывать на другом языке.


И да, мне тоже интересно, насколько самописная свёртка отличается по скорости работы от её реализации в Python. Может быть, когда-нибудь я это проверю.

В очередной раз пытаться сравнить некорректно. Уже был в какой-то статье в комментариях тред на эту тему. В ядре NumPy лежит реализация на C, которая естественно работает быстро
НЛО прилетело и опубликовало эту надпись здесь
Ходят слухи, что как минимум CLR и некоторые структуры данных в .NET Core тоже на С написаны. С другой стороны — зачем писать алгоритмы на чистом Python, если есть NumPy, OpenCV и прочие TensorFlow?
Иронично, но всё же CLR — это среда выполнения, которая на лету компилирует IL-код сборок, а NumPy, как правильно ответили — это набор библиотек написанных на C++ с обёрткой на питоне

Потребление памяти должно быть одинаково: в C# память для изображений выделяется в unmanaged пуле и управляется явно.

То есть, Вы откидываете все то, что предоставляет C# и пользуетесь им практически как C++?

Именно так. Даже не как C++, а как C.


Не, ну можно, конечно, использовать и возможности C#: выделять память через MemoryPool<T>, затем делать ей .Pin() и получать указатель. Но, скорее всего, это будет немного медленнее.

Можно, но я хотел использовать одинаковую реализацию для C# и C++.


Вот результаты для BenchmarkDotNet:


BenchmarkDotNet=v0.12.1, OS=arch
Intel Core i7-2600K CPU 3.40GHz (Sandy Bridge), 1 CPU, 4 logical and 4 physical cores
.NET Core SDK=5.0.101
  [Host]     : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT
  DefaultJob : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT

|               Method |         Mean |     Error |    StdDev |
|--------------------- |-------------:|----------:|----------:|
|    Sum_GetSetMethods |    114.99 us |  0.028 us |  0.026 us |
|        Sum_RefMethod |    117.90 us |  0.530 us |  0.470 us |
|     Sum_ThisProperty |    116.15 us |  0.219 us |  0.183 us |
|        Sum_Optimized |     40.74 us |  0.028 us |  0.027 us |
|              Sum_Avx |     21.23 us |  0.038 us |  0.032 us |
|            Rotate180 |     90.51 us |  0.024 us |  0.019 us |
|  Rotate180_Optimized |     34.80 us |  0.002 us |  0.002 us |
|        Rotate180_Avx |     14.82 us |  0.003 us |  0.003 us |
|      MedianFilter3x3 |  4,187.24 us | 12.817 us | 11.989 us |
|      MedianFilter5x5 | 11,535.95 us | 47.904 us | 42.466 us |
|      MedianFilter7x7 | 23,677.71 us | 13.734 us | 12.175 us |
|             Convolve |  5,592.16 us | 36.351 us | 34.003 us |
|   Convolve_Optimized |  2,923.87 us |  2.341 us |  1.955 us |
|         Convolve_Avx |    708.22 us |  0.856 us |  0.758 us |
| Convolve_AvxIsolated |    512.15 us |  1.144 us |  1.070 us |

Как видно, мой велосипед не так уж и плох.

НЛО прилетело и опубликовало эту надпись здесь
Она вызывает void Convolution::PerformVector() в котором векторные инструкции в явном виде не применяются.

Из которой, в свою очередь, вызывается ProcessUncheckedVector. Будьте немного внимательнее.


Плюс сами методы в тесте вызываются по указателю (через std::function) — это очень плохо способствует (по сути наверно убивает) инлайнинг и как следствия возможные дальнейшие оптимизации.

Вы написали ерунду. Нет никакого смысла оптимизировать сам вызов тестируемого метода. Вызов по указателю делается ровно один раз для каждой итерации. Это повышает время работы программы примерно на 0.001%. Внутри же тестируемого метода же никаких индирекций нет.


Еще неплохобы явно говорить компилятору что указатели которые используются в методах ссылаются на непересекающиеся куски памяти (__restrict).

И давно эта штука присутствует в стандарте C++?


Вообщем то что в нативной C++ реализации производительность больше на 10% мне как-то слабовато верится.

А зря. Об этом и статья. Примерно пару лет назад я делал подобное тестирование, и отставание C# от C++ было примерно в 2 раза для векторизованного метода. Сейчас же C# меня приятно удивил.


Лучше было попробовать нагуглить готовые заоптимизированные во все возможные щели реализации и сравнивать с ними а не писать самому.

Критикуете — предлагайте. Загуглите готовые заоптимизированные во все возможные щели реализации и предложите конкретные варианты. Если форкните проект и реализуете предложения самостоятельно, сообщество скажет дополнительное спасибо.


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

НЛО прилетело и опубликовало эту надпись здесь
Это как минимум неверно, потому что можно распараллелить все эти алгоритмы.

Конечно, можно. У меня есть и параллельные реализации алгоритмов. Но пропорции все равно сохраняются, поэтому приведение параллельных реализаций в данном случае нерелевантно: код станет сложнее, а выводы о сравнении производительности C# и C++ останутся теми же.


Правда, опять же, для распараллеливания используется велосипед: так получается, что собственная реализация для частных случаев оказывается эффективнее универсальных решений из эффективных библиотек (типа Intel TBB) за счёт меньшего оверхеда.


И по сути в большинстве случаев будет иметь значение именно латенси а не срупут.

Как раз для нейросетей, которые отлично параллелятся на множество медленных вычислителей, важнее throughput.


И не факт что синхронизация на C# и C++ будут прямо одинаково быстро работать.

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


Во первых что значит «использует UB»

Имеется в виду, что отсутствуют проверки на выход из границу массива. Если бы поведение программы в этом случае было определённым, значит, имело бы место проверка, а значит, была бы ниже производительность.


Это какой то тролинг? Те примеры которые тут даны это как раз древнии вещи насколько это возможно, а вот разработку какая-нибудь невиданнаой досели архитектуры нейросети вполне можно назвать «чем-то новым».

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

НЛО прилетело и опубликовало эту надпись здесь
Я говорю о том что инференс сети (конволющен сети в примерно 100% случаев для картинок) имеет условную скорость 100 картинок\сек то это ничего не значит если 1 изображение обрабатывается 0.3 сек например.

От задачи зависит. Например, для задачи повышения качества видеофайла важен именно первый параметр, а второй может быть хоть 30 секунд.


Например, замена вот этой строчки в функции

У меня закономерно меняется только время вычисления медианы.


Сам тест в MeasureExecutionTime вызывается N раз для одного и тоже изображения, что естественно уже при наверно 3-4 проходе заносит всю информацию в кеши. Это как-то не совсем правдоподобная ситуация.

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


Чтобы провести более-менее «честный» эксперимент логично взять какой нить ролик, раскодровать его и использовать эти картинки как вход (без учета времени считывания в память естественно).

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

НЛО прилетело и опубликовало эту надпись здесь
Немного тема устарела. Сейчас подобные вещи стоит писать на CUDA/OpenCL. И соответственно, на языках, которые такое поддерживают изкоробки.

А еще для математики желательна бесплатная перегрузка операторов.
Сейчас подобные вещи стоит писать на CUDA/OpenCL.

Ваше утверждение тоже устарело. Зачем руками писать на CUDA/OpenCL, когда есть Tensorflow с обёрткой Tensorflow.NET или даже Matlab?


На самом деле, у каждого языка или фрейморка есть своё предназначение. И использование даже Tensorflow для некоторых задач — это уже оверкилл. Например, если я хочу продемонстрировать потенциальному заказчику работу нейросети, я не буду заставлять его устанавливать гигабайтные фреймворки. Я просто реализую нейросетку на голом C++ (CPU-only) без дополнительных зависимостей и передам ему компактный файлик, с которым он сможет играться.

Либо мы сравниваем наивные реализации, как в статье, либо…

Почему?

не дай бог вам такие «простые» вещи писать на Куде…, скажем так, только их писать на куде точно не имеет смысл, время выгрузки картинок на GPU и обратно будет дольше чем самы вычисления… как часть намного более продолжительных вычислений на GPU… конечно да

с OpenCL немного не так все однозначно
так как его поддерживают и встореные в CPU видео карты, время копирования пркатически ноль… и возможно да будет выйгрышь
Вы не проверяли: там где наблюдается паритет скорости, не упирается ли все в пропускную способность памяти?

Нет, не упирается: при распараллеливании время выполнения уменьшается пропорционально числу потоков. Если бы упиралось в память, такого бы не наблюдалось.

Ну как не упирается? Для суммирования изображения это обычно так. Смотрите: Ваш процессор с AVX имеет производительность порядка 50 GFLOPS на ядро, а для такого быстродействия потребуется загрузить 50 * 2 * 4 = 400 GB данных в секунду, тогда как пропускная способность памяти на канал порядка 10 GB в секунду. Т.е. в 40 раз меньше.
Дополнительные потоки позволяют задействовать второй канал памяти. Кроме того, если размеры изображения не велики — все данные могут вмещаться в кеш процессора. Но даже для кеша L1 — 400 GB данных в секунду — это многовато. А ведь результаты нужно еще сохранять.

Операция свертки, или медианная фильтрация теоретически могут задействовать все вычислительные ресурсы процессора. Но там паритета вроде нет?

Согласен, упирается. Результаты сильно зависят от размера изображений:
64x64, 128x128 — 3.8 GFLOPS (L2 cache) — ~30GB/sec
256x256, 512x512 — ~3.2 GLOPS (L3 cache) — ~25GB/sec
1024x1024 и выше — 1.2 GFLOPS (memory) — ~10GB/sec


Не упирается только для свёртки. Распалеллеливание на 4 потока даёт закономерное ускорение почти в 4 раза вне зависимости от размера изображения.


Ваш процессор с AVX имеет производительность порядка 50 GFLOPS на ядро,

Если быть более точным, то 8 умножений и 8 сложений на цикл. В реальности это недостижимо — FMA-то нет. Linpack показывает пиковую производительность 25-30 GLOPS на ядро в зависимости от частоты процессора.


а для такого быстродействия потребуется загрузить 50 2 4 = 400 GB данных в секунду

Так это в теории, а на практике помимо VADDPS у нас будет аж 3 команды VMOVAPS, причём с необходимостью вычисления адреса, ещё регистр под счётчик надо держать. Для Sandy Bridge цифры такие:
VMOVAPS (r/mem) — latency 4, throughput 1 — их надо 3 штуки
VADDPS — latency 3, throughput 1


Итого имеем в лучшем случае: 2 цикла на прочитать данные, 3 цикла на сложить (ибо зависимость по данным), 4 цикла на записать, ну и 1 цикл на инкремент счётчика (но, скорее всего, он выполнится параллельно с операцией записи). То есть не больше 400 M подобных блоков в секунду, или 3.2 GFLOPS, что в целом соответствует цифрам из статьи (20 мкс, 65536 сложений = ~3.2 млрд).


Теоретически, можно ещё немного выжать производительности, избавившись от зависимости операций по данным и добившись задержки в 1 цикл для сложения и, если это вообще возможно, 1 цикл для записи. Но эффект будет наблюдаться только для L1 кэша.


Дополнительные потоки позволяют задействовать второй канал памяти.

Так в каждом ядре процессора по 2 блока для чтения. Разве процессор не способен задействовать оба канала из одного ядра?


Операция свертки, или медианная фильтрация теоретически могут задействовать все вычислительные ресурсы процессора. Но там паритета вроде нет?

Есть паритет между C# и g++ для свёртки. А вот clang уделывает за счёт оптимизаций. Если g++, судя по дизассемблеру, работал максимально аккуратно: не инлайнил Convolution::ProcessUncheckedVector, не разворачивал цикл, то clang заинлайнил практически всё.

C++ библиотека предоставляет более быструю частичную сортировку (nth_element) которую все обычно применяют в идиоматическом коде для поиска медианы.

Она заведомо (тк нет эквивалента в c#) не используется в бенчмарке?
Она заведомо (тк нет эквивалента в c#) не используется в бенчмарке?

Всё проще: она не используется, потому что я про неё раньше не знал. Да и не было цели сравнивать стандартные библиотеки.


Для медианы небольших размеров (3х3, 5х5) эффективнее использовать сортировочные сети, которые отлично векторизуются. А медину больших размеров на практике как-то и не приходилось использовать.

Мне приходилось для поиска дефектов (ядро до 31х31), но в этом случае я пользовался алгоритмом Хуанга, это "бегущая" медиана, которая вычисляется на основе локальной гистограммы, грубо говоря мы при смещении на пиксель добавляем новый столбец в гистограмму, а другой удаляем и корректируем значение медианы так чтобы на гистограмме слева и справа было одинаковое количество отсчётов (в чём суть медианы и есть).

Наверное вам будет интересно взглянуть на этот проект https://github.com/evilguest/linq2d
Там же есть ссылка на презентацию. Тут идея кодогенерации с использованием интрисинков и LINQ и дерева выражений.

Спасибо, любопытно.


Вообще, в одном из старых проектов у меня было сделано что-то похожее, но без использования LINQ: можно было написать что-то типа ((a + b) * c + c.Shift(1, 0)).Abs().Create();, где внутри метода Create аналогичным образом строилось Expression tree, которое потом компилировалось в метод из динамической сборки.

Конечно, можно. Код на Github же открытый лежит.

а есть потверждение что цишные компиляторы использовали авто векторизацию, ну то есть смотрели в дисассемблер?
Конечно, смотрел
0000000000003250 <_Z8ImageSumRK5ImageIfES2_RS0_>:
    3250:   55                      push   rbp
    3251:   48 89 e5                mov    rbp,rsp
    3254:   41 57                   push   r15
    3256:   41 56                   push   r14
    3258:   41 55                   push   r13
    325a:   41 54                   push   r12
    325c:   53                      push   rbx
    325d:   48 83 e4 e0             and    rsp,0xffffffffffffffe0
    3261:   8b 42 0c                mov    eax,DWORD PTR [rdx+0xc]
    3264:   89 44 24 fc             mov    DWORD PTR [rsp-0x4],eax
    3268:   85 c0                   test   eax,eax
    326a:   0f 8e a0 01 00 00       jle    3410 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1c0>
    3270:   44 8b 5a 08             mov    r11d,DWORD PTR [rdx+0x8]
    3274:   45 85 db                test   r11d,r11d
    3277:   0f 8e 93 01 00 00       jle    3410 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1c0>
    327d:   8b 47 10                mov    eax,DWORD PTR [rdi+0x10]
    3280:   45 89 d9                mov    r9d,r11d
    3283:   45 89 dd                mov    r13d,r11d
    3286:   45 89 de                mov    r14d,r11d
    3289:   48 8b 1e                mov    rbx,QWORD PTR [rsi]
    328c:   45 8d 7b ff             lea    r15d,[r11-0x1]
    3290:   41 c1 e9 03             shr    r9d,0x3
    3294:   41 83 e5 f8             and    r13d,0xfffffff8
    3298:   4c 8b 27                mov    r12,QWORD PTR [rdi]
    329b:   49 c1 e1 05             shl    r9,0x5
    329f:   31 ff                   xor    edi,edi
    32a1:   89 44 24 e8             mov    DWORD PTR [rsp-0x18],eax
    32a5:   8b 46 10                mov    eax,DWORD PTR [rsi+0x10]
    32a8:   89 44 24 ec             mov    DWORD PTR [rsp-0x14],eax
    32ac:   48 8b 02                mov    rax,QWORD PTR [rdx]
    32af:   48 89 44 24 f0          mov    QWORD PTR [rsp-0x10],rax
    32b4:   8b 42 10                mov    eax,DWORD PTR [rdx+0x10]
    32b7:   89 44 24 f8             mov    DWORD PTR [rsp-0x8],eax
    32bb:   44 89 d8                mov    eax,r11d
    32be:   83 e0 07                and    eax,0x7
    32c1:   89 44 24 e4             mov    DWORD PTR [rsp-0x1c],eax
    32c5:   83 e8 01                sub    eax,0x1
    32c8:   89 44 24 e0             mov    DWORD PTR [rsp-0x20],eax
    32cc:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]
    32d0:   8b 44 24 f8             mov    eax,DWORD PTR [rsp-0x8]
    32d4:   8b 4c 24 e8             mov    ecx,DWORD PTR [rsp-0x18]
    32d8:   8b 54 24 ec             mov    edx,DWORD PTR [rsp-0x14]
    32dc:   0f af c7                imul   eax,edi
    32df:   0f af cf                imul   ecx,edi
    32e2:   0f af d7                imul   edx,edi
    32e5:   48 98                   cdqe   
    32e7:   48 03 44 24 f0          add    rax,QWORD PTR [rsp-0x10]
    32ec:   48 63 c9                movsxd rcx,ecx
    32ef:   4d 8d 44 0c 04          lea    r8,[r12+rcx*1+0x4]
    32f4:   48 63 d2                movsxd rdx,edx
    32f7:   4c 8d 54 13 04          lea    r10,[rbx+rdx*1+0x4]
    32fc:   48 89 c6                mov    rsi,rax
    32ff:   4c 29 c6                sub    rsi,r8
    3302:   49 89 c0                mov    r8,rax
    3305:   48 83 fe 18             cmp    rsi,0x18
    3309:   40 0f 97 c6             seta   sil
    330d:   4d 29 d0                sub    r8,r10
    3310:   49 83 f8 18             cmp    r8,0x18
    3314:   41 0f 97 c0             seta   r8b
    3318:   44 84 c6                test   sil,r8b
    331b:   0f 84 ff 00 00 00       je     3420 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1d0>
    3321:   41 83 ff 02             cmp    r15d,0x2
    3325:   0f 86 f5 00 00 00       jbe    3420 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1d0>
    332b:   41 83 ff 06             cmp    r15d,0x6
    332f:   0f 86 15 01 00 00       jbe    344a <_Z8ImageSumRK5ImageIfES2_RS0_+0x1fa>
    3335:   4c 01 e1                add    rcx,r12
    3338:   48 01 da                add    rdx,rbx
    333b:   31 f6                   xor    esi,esi
    333d:   0f 1f 00                nop    DWORD PTR [rax]
    3340:   c5 f8 10 14 31          vmovups xmm2,XMMWORD PTR [rcx+rsi*1]
    3345:   c4 e3 6d 18 44 31 10 01     vinsertf128 ymm0,ymm2,XMMWORD PTR [rcx+rsi*1+0x10],0x1
    334d:   c5 f8 10 1c 32          vmovups xmm3,XMMWORD PTR [rdx+rsi*1]
    3352:   c4 e3 65 18 4c 32 10 01     vinsertf128 ymm1,ymm3,XMMWORD PTR [rdx+rsi*1+0x10],0x1
    335a:   c5 fc 58 c1             vaddps ymm0,ymm0,ymm1
    335e:   c5 f8 11 04 30          vmovups XMMWORD PTR [rax+rsi*1],xmm0
    3363:   c4 e3 7d 19 44 30 10 01     vextractf128 XMMWORD PTR [rax+rsi*1+0x10],ymm0,0x1
    336b:   48 83 c6 20             add    rsi,0x20
    336f:   4c 39 ce                cmp    rsi,r9
    3372:   75 cc                   jne    3340 <_Z8ImageSumRK5ImageIfES2_RS0_+0xf0>
    3374:   45 39 eb                cmp    r11d,r13d
    3377:   0f 84 83 00 00 00       je     3400 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1b0>
    337d:   83 7c 24 e0 02          cmp    DWORD PTR [rsp-0x20],0x2
    3382:   44 8b 54 24 e4          mov    r10d,DWORD PTR [rsp-0x1c]
    3387:   0f 86 d0 00 00 00       jbe    345d <_Z8ImageSumRK5ImageIfES2_RS0_+0x20d>
    338d:   44 89 ee                mov    esi,r13d
    3390:   45 89 e8                mov    r8d,r13d
    3393:   48 c1 e6 02             shl    rsi,0x2
    3397:   c5 f8 10 24 31          vmovups xmm4,XMMWORD PTR [rcx+rsi*1]
    339c:   c5 d8 58 04 32          vaddps xmm0,xmm4,XMMWORD PTR [rdx+rsi*1]
    33a1:   c5 f8 11 04 30          vmovups XMMWORD PTR [rax+rsi*1],xmm0
    33a6:   44 89 d6                mov    esi,r10d
    33a9:   83 e6 fc                and    esi,0xfffffffc
    33ac:   41 01 f0                add    r8d,esi
    33af:   41 39 f2                cmp    r10d,esi
    33b2:   74 4c                   je     3400 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1b0>
    33b4:   45 8d 50 01             lea    r10d,[r8+0x1]
    33b8:   49 63 f0                movsxd rsi,r8d
    33bb:   48 c1 e6 02             shl    rsi,0x2
    33bf:   c5 fa 10 04 32          vmovss xmm0,DWORD PTR [rdx+rsi*1]
    33c4:   c5 fa 58 04 31          vaddss xmm0,xmm0,DWORD PTR [rcx+rsi*1]
    33c9:   c5 fa 11 04 30          vmovss DWORD PTR [rax+rsi*1],xmm0
    33ce:   45 39 d3                cmp    r11d,r10d
    33d1:   7e 2d                   jle    3400 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1b0>
    33d3:   c5 fa 10 44 31 04       vmovss xmm0,DWORD PTR [rcx+rsi*1+0x4]
    33d9:   41 83 c0 02             add    r8d,0x2
    33dd:   c5 fa 58 44 32 04       vaddss xmm0,xmm0,DWORD PTR [rdx+rsi*1+0x4]
    33e3:   c5 fa 11 44 30 04       vmovss DWORD PTR [rax+rsi*1+0x4],xmm0
    33e9:   45 39 c3                cmp    r11d,r8d
    33ec:   7e 12                   jle    3400 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1b0>
    33ee:   c5 fa 10 44 31 08       vmovss xmm0,DWORD PTR [rcx+rsi*1+0x8]
    33f4:   c5 fa 58 44 32 08       vaddss xmm0,xmm0,DWORD PTR [rdx+rsi*1+0x8]
    33fa:   c5 fa 11 44 30 08       vmovss DWORD PTR [rax+rsi*1+0x8],xmm0
    3400:   83 c7 01                add    edi,0x1
    3403:   3b 7c 24 fc             cmp    edi,DWORD PTR [rsp-0x4]
    3407:   0f 85 c3 fe ff ff       jne    32d0 <_Z8ImageSumRK5ImageIfES2_RS0_+0x80>
    340d:   c5 f8 77                vzeroupper 
    3410:   48 8d 65 d8             lea    rsp,[rbp-0x28]
    3414:   5b                      pop    rbx
    3415:   41 5c                   pop    r12
    3417:   41 5d                   pop    r13
    3419:   41 5e                   pop    r14
    341b:   41 5f                   pop    r15
    341d:   5d                      pop    rbp
    341e:   c3                      ret    
    341f:   90                      nop
    3420:   31 f6                   xor    esi,esi
    3422:   4c 01 e1                add    rcx,r12
    3425:   48 01 da                add    rdx,rbx
    3428:   0f 1f 84 00 00 00 00 00     nop    DWORD PTR [rax+rax*1+0x0]
    3430:   c5 fa 10 04 b2          vmovss xmm0,DWORD PTR [rdx+rsi*4]
    3435:   c5 fa 58 04 b1          vaddss xmm0,xmm0,DWORD PTR [rcx+rsi*4]
    343a:   c5 fa 11 04 b0          vmovss DWORD PTR [rax+rsi*4],xmm0
    343f:   48 83 c6 01             add    rsi,0x1
    3443:   4c 39 f6                cmp    rsi,r14
    3446:   75 e8                   jne    3430 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1e0>
    3448:   eb b6                   jmp    3400 <_Z8ImageSumRK5ImageIfES2_RS0_+0x1b0>
    344a:   45 89 da                mov    r10d,r11d
    344d:   31 f6                   xor    esi,esi
    344f:   45 31 c0                xor    r8d,r8d
    3452:   4c 01 e1                add    rcx,r12
    3455:   48 01 da                add    rdx,rbx
    3458:   e9 36 ff ff ff          jmp    3393 <_Z8ImageSumRK5ImageIfES2_RS0_+0x143>
    345d:   45 89 e8                mov    r8d,r13d
    3460:   e9 4f ff ff ff          jmp    33b4 <_Z8ImageSumRK5ImageIfES2_RS0_+0x164>
    3465:   66 66 2e 0f 1f 84 00 00 00 00 00    data16 nop WORD PTR cs:[rax+rax*1+0x0]

0000000000003470 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_>:
    3470:   55                      push   rbp
    3471:   48 89 e5                mov    rbp,rsp
    3474:   41 57                   push   r15
    3476:   41 56                   push   r14
    3478:   41 55                   push   r13
    347a:   41 54                   push   r12
    347c:   53                      push   rbx
    347d:   48 83 e4 e0             and    rsp,0xffffffffffffffe0
    3481:   8b 42 0c                mov    eax,DWORD PTR [rdx+0xc]
    3484:   89 44 24 ec             mov    DWORD PTR [rsp-0x14],eax
    3488:   85 c0                   test   eax,eax
    348a:   0f 8e 0a 02 00 00       jle    369a <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x22a>
    3490:   4c 8b 3f                mov    r15,QWORD PTR [rdi]
    3493:   8b 5a 08                mov    ebx,DWORD PTR [rdx+0x8]
    3496:   4c 8b 1e                mov    r11,QWORD PTR [rsi]
    3499:   48 63 4e 10             movsxd rcx,DWORD PTR [rsi+0x10]
    349d:   48 63 47 10             movsxd rax,DWORD PTR [rdi+0x10]
    34a1:   4c 89 7c 24 f8          mov    QWORD PTR [rsp-0x8],r15
    34a6:   4c 8b 12                mov    r10,QWORD PTR [rdx]
    34a9:   89 5c 24 f0             mov    DWORD PTR [rsp-0x10],ebx
    34ad:   8b 72 10                mov    esi,DWORD PTR [rdx+0x10]
    34b0:   85 db                   test   ebx,ebx
    34b2:   0f 8e e2 01 00 00       jle    369a <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x22a>
    34b8:   48 89 44 24 d8          mov    QWORD PTR [rsp-0x28],rax
    34bd:   8d 43 ff                lea    eax,[rbx-0x1]
    34c0:   41 89 d8                mov    r8d,ebx
    34c3:   89 df                   mov    edi,ebx
    34c5:   89 44 24 e8             mov    DWORD PTR [rsp-0x18],eax
    34c9:   89 d8                   mov    eax,ebx
    34cb:   83 e3 07                and    ebx,0x7
    34ce:   48 63 d6                movsxd rdx,esi
    34d1:   83 e0 f8                and    eax,0xfffffff8
    34d4:   41 c1 e8 03             shr    r8d,0x3
    34d8:   89 5c 24 c8             mov    DWORD PTR [rsp-0x38],ebx
    34dc:   83 eb 01                sub    ebx,0x1
    34df:   48 89 54 24 e0          mov    QWORD PTR [rsp-0x20],rdx
    34e4:   49 c1 e0 05             shl    r8,0x5
    34e8:   4c 89 da                mov    rdx,r11
    34eb:   48 89 4c 24 d0          mov    QWORD PTR [rsp-0x30],rcx
    34f0:   4c 89 f9                mov    rcx,r15
    34f3:   89 44 24 cc             mov    DWORD PTR [rsp-0x34],eax
    34f7:   4c 89 d0                mov    rax,r10
    34fa:   c7 44 24 f4 00 00 00 00     mov    DWORD PTR [rsp-0xc],0x0
    3502:   48 89 7c 24 b8          mov    QWORD PTR [rsp-0x48],rdi
    3507:   89 5c 24 c4             mov    DWORD PTR [rsp-0x3c],ebx
    350b:   0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]
    3510:   48 8d 79 04             lea    rdi,[rcx+0x4]
    3514:   48 89 c6                mov    rsi,rax
    3517:   49 89 d4                mov    r12,rdx
    351a:   48 29 fe                sub    rsi,rdi
    351d:   48 89 c3                mov    rbx,rax
    3520:   49 89 c9                mov    r9,rcx
    3523:   4c 2b 4c 24 f8          sub    r9,QWORD PTR [rsp-0x8]
    3528:   4d 29 dc                sub    r12,r11
    352b:   4c 29 d3                sub    rbx,r10
    352e:   4c 8d 6a 04             lea    r13,[rdx+0x4]
    3532:   48 83 fe 18             cmp    rsi,0x18
    3536:   48 89 c7                mov    rdi,rax
    3539:   40 0f 97 c6             seta   sil
    353d:   4c 29 ef                sub    rdi,r13
    3540:   48 83 ff 18             cmp    rdi,0x18
    3544:   40 0f 97 c7             seta   dil
    3548:   40 84 fe                test   sil,dil
    354b:   0f 84 5f 01 00 00       je     36b0 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x240>
    3551:   8b 7c 24 e8             mov    edi,DWORD PTR [rsp-0x18]
    3555:   83 ff 02                cmp    edi,0x2
    3558:   0f 86 52 01 00 00       jbe    36b0 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x240>
    355e:   83 ff 06                cmp    edi,0x6
    3561:   0f 86 73 01 00 00       jbe    36da <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x26a>
    3567:   31 f6                   xor    esi,esi
    3569:   0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
    3570:   c5 f8 10 14 31          vmovups xmm2,XMMWORD PTR [rcx+rsi*1]
    3575:   c4 e3 6d 18 44 31 10 01     vinsertf128 ymm0,ymm2,XMMWORD PTR [rcx+rsi*1+0x10],0x1
    357d:   c5 f8 10 1c 32          vmovups xmm3,XMMWORD PTR [rdx+rsi*1]
    3582:   c4 e3 65 18 4c 32 10 01     vinsertf128 ymm1,ymm3,XMMWORD PTR [rdx+rsi*1+0x10],0x1
    358a:   c5 fc 58 c1             vaddps ymm0,ymm0,ymm1
    358e:   c5 f8 11 04 30          vmovups XMMWORD PTR [rax+rsi*1],xmm0
    3593:   c4 e3 7d 19 44 30 10 01     vextractf128 XMMWORD PTR [rax+rsi*1+0x10],ymm0,0x1
    359b:   48 83 c6 20             add    rsi,0x20
    359f:   4c 39 c6                cmp    rsi,r8
    35a2:   75 cc                   jne    3570 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x100>
    35a4:   8b 7c 24 cc             mov    edi,DWORD PTR [rsp-0x34]
    35a8:   39 7c 24 f0             cmp    DWORD PTR [rsp-0x10],edi
    35ac:   0f 84 c3 00 00 00       je     3675 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x205>
    35b2:   83 7c 24 c4 02          cmp    DWORD PTR [rsp-0x3c],0x2
    35b7:   89 fe                   mov    esi,edi
    35b9:   44 8b 6c 24 c8          mov    r13d,DWORD PTR [rsp-0x38]
    35be:   76 35                   jbe    35f5 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x185>
    35c0:   4c 8b 74 24 f8          mov    r14,QWORD PTR [rsp-0x8]
    35c5:   48 c1 e6 02             shl    rsi,0x2
    35c9:   4d 8d 3c 33             lea    r15,[r11+rsi*1]
    35cd:   c4 81 78 10 04 27       vmovups xmm0,XMMWORD PTR [r15+r12*1]
    35d3:   4d 01 ce                add    r14,r9
    35d6:   c4 c1 78 58 04 36       vaddps xmm0,xmm0,XMMWORD PTR [r14+rsi*1]
    35dc:   4c 01 d6                add    rsi,r10
    35df:   c5 f8 11 04 1e          vmovups XMMWORD PTR [rsi+rbx*1],xmm0
    35e4:   44 89 ee                mov    esi,r13d
    35e7:   83 e6 fc                and    esi,0xfffffffc
    35ea:   01 f7                   add    edi,esi
    35ec:   41 39 f5                cmp    r13d,esi
    35ef:   0f 84 80 00 00 00       je     3675 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x205>
    35f5:   4c 8b 7c 24 f8          mov    r15,QWORD PTR [rsp-0x8]
    35fa:   48 63 f7                movsxd rsi,edi
    35fd:   48 c1 e6 02             shl    rsi,0x2
    3601:   4d 8d 34 33             lea    r14,[r11+rsi*1]
    3605:   4d 8d 2c 32             lea    r13,[r10+rsi*1]
    3609:   49 01 f7                add    r15,rsi
    360c:   c4 81 7a 10 04 0f       vmovss xmm0,DWORD PTR [r15+r9*1]
    3612:   c4 81 7a 58 04 26       vaddss xmm0,xmm0,DWORD PTR [r14+r12*1]
    3618:   c4 c1 7a 11 44 1d 00    vmovss DWORD PTR [r13+rbx*1+0x0],xmm0
    361f:   44 8d 6f 01             lea    r13d,[rdi+0x1]
    3623:   44 39 6c 24 f0          cmp    DWORD PTR [rsp-0x10],r13d
    3628:   7e 4b                   jle    3675 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x205>
    362a:   4c 03 4c 24 f8          add    r9,QWORD PTR [rsp-0x8]
    362f:   83 c7 02                add    edi,0x2
    3632:   4c 8d 6e 04             lea    r13,[rsi+0x4]
    3636:   4f 8d 3c 2b             lea    r15,[r11+r13*1]
    363a:   c4 a1 7a 10 44 0e 04    vmovss xmm0,DWORD PTR [rsi+r9*1+0x4]
    3641:   4f 8d 34 2a             lea    r14,[r10+r13*1]
    3645:   c4 81 7a 58 04 27       vaddss xmm0,xmm0,DWORD PTR [r15+r12*1]
    364b:   c4 c1 7a 11 04 1e       vmovss DWORD PTR [r14+rbx*1],xmm0
    3651:   39 7c 24 f0             cmp    DWORD PTR [rsp-0x10],edi
    3655:   7e 1e                   jle    3675 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x205>
    3657:   48 83 c6 08             add    rsi,0x8
    365b:   4d 8d 2c 33             lea    r13,[r11+rsi*1]
    365f:   c4 c1 7a 10 04 31       vmovss xmm0,DWORD PTR [r9+rsi*1]
    3665:   c4 81 7a 58 44 25 00    vaddss xmm0,xmm0,DWORD PTR [r13+r12*1+0x0]
    366c:   49 8d 3c 32             lea    rdi,[r10+rsi*1]
    3670:   c5 fa 11 04 1f          vmovss DWORD PTR [rdi+rbx*1],xmm0
    3675:   83 44 24 f4 01          add    DWORD PTR [rsp-0xc],0x1
    367a:   48 03 44 24 e0          add    rax,QWORD PTR [rsp-0x20]
    367f:   8b 5c 24 f4             mov    ebx,DWORD PTR [rsp-0xc]
    3683:   48 03 54 24 d0          add    rdx,QWORD PTR [rsp-0x30]
    3688:   48 03 4c 24 d8          add    rcx,QWORD PTR [rsp-0x28]
    368d:   3b 5c 24 ec             cmp    ebx,DWORD PTR [rsp-0x14]
    3691:   0f 85 79 fe ff ff       jne    3510 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0xa0>
    3697:   c5 f8 77                vzeroupper 
    369a:   48 8d 65 d8             lea    rsp,[rbp-0x28]
    369e:   5b                      pop    rbx
    369f:   41 5c                   pop    r12
    36a1:   41 5d                   pop    r13
    36a3:   41 5e                   pop    r14
    36a5:   41 5f                   pop    r15
    36a7:   5d                      pop    rbp
    36a8:   c3                      ret    
    36a9:   0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
    36b0:   48 8b 7c 24 b8          mov    rdi,QWORD PTR [rsp-0x48]
    36b5:   31 f6                   xor    esi,esi
    36b7:   66 0f 1f 84 00 00 00 00 00  nop    WORD PTR [rax+rax*1+0x0]
    36c0:   c5 fa 10 04 b2          vmovss xmm0,DWORD PTR [rdx+rsi*4]
    36c5:   c5 fa 58 04 b1          vaddss xmm0,xmm0,DWORD PTR [rcx+rsi*4]
    36ca:   c5 fa 11 04 b0          vmovss DWORD PTR [rax+rsi*4],xmm0
    36cf:   48 83 c6 01             add    rsi,0x1
    36d3:   48 39 fe                cmp    rsi,rdi
    36d6:   75 e8                   jne    36c0 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x250>
    36d8:   eb 9b                   jmp    3675 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x205>
    36da:   44 8b 6c 24 f0          mov    r13d,DWORD PTR [rsp-0x10]
    36df:   31 f6                   xor    esi,esi
    36e1:   31 ff                   xor    edi,edi
    36e3:   e9 d8 fe ff ff          jmp    35c0 <_Z17ImageSumOptimizedRK5ImageIfES2_RS0_+0x150>
    36e8:   0f 1f 84 00 00 00 00 00     nop    DWORD PTR [rax+rax*1+0x0]

00000000000036f0 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_>:
    36f0:   55                      push   rbp
    36f1:   48 89 e5                mov    rbp,rsp
    36f4:   41 57                   push   r15
    36f6:   41 56                   push   r14
    36f8:   41 55                   push   r13
    36fa:   41 54                   push   r12
    36fc:   53                      push   rbx
    36fd:   48 83 e4 e0             and    rsp,0xffffffffffffffe0
    3701:   48 89 74 24 e8          mov    QWORD PTR [rsp-0x18],rsi
    3706:   44 8b 62 08             mov    r12d,DWORD PTR [rdx+0x8]
    370a:   48 89 7c 24 f0          mov    QWORD PTR [rsp-0x10],rdi
    370f:   8b 72 0c                mov    esi,DWORD PTR [rdx+0xc]
    3712:   41 8d 44 24 07          lea    eax,[r12+0x7]
    3717:   45 85 e4                test   r12d,r12d
    371a:   41 0f 49 c4             cmovns eax,r12d
    371e:   89 74 24 f8             mov    DWORD PTR [rsp-0x8],esi
    3722:   83 e0 f8                and    eax,0xfffffff8
    3725:   89 44 24 fc             mov    DWORD PTR [rsp-0x4],eax
    3729:   85 f6                   test   esi,esi
    372b:   0f 8e ee 01 00 00       jle    391f <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x22f>
    3731:   8d 70 ff                lea    esi,[rax-0x1]
    3734:   f7 d0                   not    eax
    3736:   48 89 d3                mov    rbx,rdx
    3739:   c1 ee 03                shr    esi,0x3
    373c:   45 31 c9                xor    r9d,r9d
    373f:   89 44 24 e4             mov    DWORD PTR [rsp-0x1c],eax
    3743:   83 c6 01                add    esi,0x1
    3746:   48 c1 e6 05             shl    rsi,0x5
    374a:   66 0f 1f 44 00 00       nop    WORD PTR [rax+rax*1+0x0]
    3750:   48 8b 44 24 f0          mov    rax,QWORD PTR [rsp-0x10]
    3755:   31 ff                   xor    edi,edi
    3757:   44 8b 44 24 fc          mov    r8d,DWORD PTR [rsp-0x4]
    375c:   8b 50 10                mov    edx,DWORD PTR [rax+0x10]
    375f:   41 0f af d1             imul   edx,r9d
    3763:   48 63 d2                movsxd rdx,edx
    3766:   48 03 10                add    rdx,QWORD PTR [rax]
    3769:   48 8b 44 24 e8          mov    rax,QWORD PTR [rsp-0x18]
    376e:   8b 48 10                mov    ecx,DWORD PTR [rax+0x10]
    3771:   41 0f af c9             imul   ecx,r9d
    3775:   48 63 c9                movsxd rcx,ecx
    3778:   48 03 08                add    rcx,QWORD PTR [rax]
    377b:   8b 43 10                mov    eax,DWORD PTR [rbx+0x10]
    377e:   41 0f af c1             imul   eax,r9d
    3782:   48 98                   cdqe   
    3784:   48 03 03                add    rax,QWORD PTR [rbx]
    3787:   45 85 c0                test   r8d,r8d
    378a:   7e 30                   jle    37bc <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0xcc>
    378c:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]
    3790:   c5 fc 28 14 39          vmovaps ymm2,YMMWORD PTR [rcx+rdi*1]
    3795:   c5 ec 58 04 3a          vaddps ymm0,ymm2,YMMWORD PTR [rdx+rdi*1]
    379a:   c5 fc 29 04 38          vmovaps YMMWORD PTR [rax+rdi*1],ymm0
    379f:   48 83 c7 20             add    rdi,0x20
    37a3:   48 39 f7                cmp    rdi,rsi
    37a6:   75 e8                   jne    3790 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0xa0>
    37a8:   8b 7b 0c                mov    edi,DWORD PTR [rbx+0xc]
    37ab:   48 01 f2                add    rdx,rsi
    37ae:   48 01 f1                add    rcx,rsi
    37b1:   48 01 f0                add    rax,rsi
    37b4:   44 8b 63 08             mov    r12d,DWORD PTR [rbx+0x8]
    37b8:   89 7c 24 f8             mov    DWORD PTR [rsp-0x8],edi
    37bc:   44 39 64 24 fc          cmp    DWORD PTR [rsp-0x4],r12d
    37c1:   0f 8d 46 01 00 00       jge    390d <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x21d>
    37c7:   44 89 e7                mov    edi,r12d
    37ca:   2b 7c 24 fc             sub    edi,DWORD PTR [rsp-0x4]
    37ce:   49 89 c2                mov    r10,rax
    37d1:   4c 8d 5a 04             lea    r11,[rdx+0x4]
    37d5:   4d 29 da                sub    r10,r11
    37d8:   44 8d 47 ff             lea    r8d,[rdi-0x1]
    37dc:   49 83 fa 18             cmp    r10,0x18
    37e0:   41 0f 97 c3             seta   r11b
    37e4:   41 83 f8 02             cmp    r8d,0x2
    37e8:   41 0f 97 c2             seta   r10b
    37ec:   45 84 d3                test   r11b,r10b
    37ef:   0f 84 3b 01 00 00       je     3930 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x240>
    37f5:   4c 8d 59 04             lea    r11,[rcx+0x4]
    37f9:   49 89 c2                mov    r10,rax
    37fc:   4d 29 da                sub    r10,r11
    37ff:   49 83 fa 18             cmp    r10,0x18
    3803:   0f 86 27 01 00 00       jbe    3930 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x240>
    3809:   41 83 f8 06             cmp    r8d,0x6
    380d:   0f 86 4f 01 00 00       jbe    3962 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x272>
    3813:   41 89 fa                mov    r10d,edi
    3816:   45 31 c0                xor    r8d,r8d
    3819:   41 c1 ea 03             shr    r10d,0x3
    381d:   49 c1 e2 05             shl    r10,0x5
    3821:   0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
    3828:   c4 a1 78 10 1c 02       vmovups xmm3,XMMWORD PTR [rdx+r8*1]
    382e:   c4 a3 65 18 44 02 10 01     vinsertf128 ymm0,ymm3,XMMWORD PTR [rdx+r8*1+0x10],0x1
    3836:   c4 a1 78 10 24 01       vmovups xmm4,XMMWORD PTR [rcx+r8*1]
    383c:   c4 a3 5d 18 4c 01 10 01     vinsertf128 ymm1,ymm4,XMMWORD PTR [rcx+r8*1+0x10],0x1
    3844:   c5 fc 58 c1             vaddps ymm0,ymm0,ymm1
    3848:   c4 a1 78 11 04 00       vmovups XMMWORD PTR [rax+r8*1],xmm0
    384e:   c4 a3 7d 19 44 00 10 01     vextractf128 XMMWORD PTR [rax+r8*1+0x10],ymm0,0x1
    3856:   49 83 c0 20             add    r8,0x20
    385a:   4d 39 c2                cmp    r10,r8
    385d:   75 c9                   jne    3828 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x138>
    385f:   44 8b 5c 24 fc          mov    r11d,DWORD PTR [rsp-0x4]
    3864:   41 89 ff                mov    r15d,edi
    3867:   41 83 e7 f8             and    r15d,0xfffffff8
    386b:   45 89 fa                mov    r10d,r15d
    386e:   4e 8d 04 95 00 00 00 00     lea    r8,[r10*4+0x0]
    3876:   4e 8d 34 02             lea    r14,[rdx+r8*1]
    387a:   45 01 fb                add    r11d,r15d
    387d:   4e 8d 2c 01             lea    r13,[rcx+r8*1]
    3881:   49 01 c0                add    r8,rax
    3884:   44 39 ff                cmp    edi,r15d
    3887:   0f 84 80 00 00 00       je     390d <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x21d>
    388d:   44 29 ff                sub    edi,r15d
    3890:   44 8d 7f ff             lea    r15d,[rdi-0x1]
    3894:   41 83 ff 02             cmp    r15d,0x2
    3898:   76 2d                   jbe    38c7 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x1d7>
    389a:   c4 a1 78 10 04 91       vmovups xmm0,XMMWORD PTR [rcx+r10*4]
    38a0:   c4 a1 78 58 04 92       vaddps xmm0,xmm0,XMMWORD PTR [rdx+r10*4]
    38a6:   89 fa                   mov    edx,edi
    38a8:   83 e2 fc                and    edx,0xfffffffc
    38ab:   41 01 d3                add    r11d,edx
    38ae:   c4 a1 78 11 04 90       vmovups XMMWORD PTR [rax+r10*4],xmm0
    38b4:   89 d0                   mov    eax,edx
    38b6:   48 c1 e0 02             shl    rax,0x2
    38ba:   49 01 c6                add    r14,rax
    38bd:   49 01 c5                add    r13,rax
    38c0:   49 01 c0                add    r8,rax
    38c3:   39 d7                   cmp    edi,edx
    38c5:   74 46                   je     390d <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x21d>
    38c7:   c4 c1 7a 10 06          vmovss xmm0,DWORD PTR [r14]
    38cc:   41 8d 43 01             lea    eax,[r11+0x1]
    38d0:   c4 c1 7a 58 45 00       vaddss xmm0,xmm0,DWORD PTR [r13+0x0]
    38d6:   c4 c1 7a 11 00          vmovss DWORD PTR [r8],xmm0
    38db:   41 39 c4                cmp    r12d,eax
    38de:   7e 2d                   jle    390d <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x21d>
    38e0:   c4 c1 7a 10 46 04       vmovss xmm0,DWORD PTR [r14+0x4]
    38e6:   41 83 c3 02             add    r11d,0x2
    38ea:   c4 c1 7a 58 45 04       vaddss xmm0,xmm0,DWORD PTR [r13+0x4]
    38f0:   c4 c1 7a 11 40 04       vmovss DWORD PTR [r8+0x4],xmm0
    38f6:   45 39 dc                cmp    r12d,r11d
    38f9:   7e 12                   jle    390d <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x21d>
    38fb:   c4 c1 7a 10 46 08       vmovss xmm0,DWORD PTR [r14+0x8]
    3901:   c4 c1 7a 58 45 08       vaddss xmm0,xmm0,DWORD PTR [r13+0x8]
    3907:   c4 c1 7a 11 40 08       vmovss DWORD PTR [r8+0x8],xmm0
    390d:   41 83 c1 01             add    r9d,0x1
    3911:   44 3b 4c 24 f8          cmp    r9d,DWORD PTR [rsp-0x8]
    3916:   0f 8c 34 fe ff ff       jl     3750 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x60>
    391c:   c5 f8 77                vzeroupper 
    391f:   48 8d 65 d8             lea    rsp,[rbp-0x28]
    3923:   5b                      pop    rbx
    3924:   41 5c                   pop    r12
    3926:   41 5d                   pop    r13
    3928:   41 5e                   pop    r14
    392a:   41 5f                   pop    r15
    392c:   5d                      pop    rbp
    392d:   c3                      ret    
    392e:   66 90                   xchg   ax,ax
    3930:   8b 7c 24 e4             mov    edi,DWORD PTR [rsp-0x1c]
    3934:   44 01 e7                add    edi,r12d
    3937:   4c 8d 04 bd 04 00 00 00     lea    r8,[rdi*4+0x4]
    393f:   31 ff                   xor    edi,edi
    3941:   0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
    3948:   c5 fa 10 04 39          vmovss xmm0,DWORD PTR [rcx+rdi*1]
    394d:   c5 fa 58 04 3a          vaddss xmm0,xmm0,DWORD PTR [rdx+rdi*1]
    3952:   c5 fa 11 04 38          vmovss DWORD PTR [rax+rdi*1],xmm0
    3957:   48 83 c7 04             add    rdi,0x4
    395b:   49 39 f8                cmp    r8,rdi
    395e:   75 e8                   jne    3948 <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x258>
    3960:   eb ab                   jmp    390d <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x21d>
    3962:   44 8b 5c 24 fc          mov    r11d,DWORD PTR [rsp-0x4]
    3967:   49 89 c0                mov    r8,rax
    396a:   49 89 cd                mov    r13,rcx
    396d:   49 89 d6                mov    r14,rdx
    3970:   45 31 d2                xor    r10d,r10d
    3973:   e9 22 ff ff ff          jmp    389a <_Z16ImageSumUsingAvxRK5ImageIfES2_RS0_+0x1aa>
    3978:   0f 1f 84 00 00 00 00 00     nop    DWORD PTR [rax+rax*1+0x0]
господи! сколько «мусора» в 'том коде на столь простой функции…
как раз ImageSumOptimized не самая показательная, вернее самая простая для компилятора
а что на счет Convolve 7x7 или медианы?
ну не может копилятор сам векторизировать их… :-)

Да, свёртку компилятор не векторизовал (собственно, цифры в таблице это и показывают):


Convolution::ProcessUncheckedOptimized
0000000000004310 <_ZN11Convolution25ProcessUncheckedOptimizedEii>:
    4310:   55                      push   rbp
    4311:   41 57                   push   r15
    4313:   41 56                   push   r14
    4315:   41 55                   push   r13
    4317:   41 54                   push   r12
    4319:   53                      push   rbx
    431a:   89 54 24 dc             mov    DWORD PTR [rsp-0x24],edx
    431e:   44 8b 5f 24             mov    r11d,DWORD PTR [rdi+0x24]
    4322:   c5 f8 57 c0             vxorps xmm0,xmm0,xmm0
    4326:   48 63 c6                movsxd rax,esi
    4329:   48 89 44 24 e8          mov    QWORD PTR [rsp-0x18],rax
    432e:   45 85 db                test   r11d,r11d
    4331:   48 89 7c 24 e0          mov    QWORD PTR [rsp-0x20],rdi
    4336:   0f 88 50 01 00 00       js     448c <_ZN11Convolution25ProcessUncheckedOptimizedEii+0x17c>
    433c:   44 8b 57 20             mov    r10d,DWORD PTR [rdi+0x20]
    4340:   45 85 d2                test   r10d,r10d
    4343:   0f 88 43 01 00 00       js     448c <_ZN11Convolution25ProcessUncheckedOptimizedEii+0x17c>
    4349:   48 8b 7c 24 e0          mov    rdi,QWORD PTR [rsp-0x20]
    434e:   48 8b 07                mov    rax,QWORD PTR [rdi]
    4351:   48 8b 4f 08             mov    rcx,QWORD PTR [rdi+0x8]
    4355:   44 8b 48 10             mov    r9d,DWORD PTR [rax+0x10]
    4359:   4c 8b 29                mov    r13,QWORD PTR [rcx]
    435c:   48 63 57 18             movsxd rdx,DWORD PTR [rdi+0x18]
    4360:   48 8b 00                mov    rax,QWORD PTR [rax]
    4363:   4c 63 71 10             movsxd r14,DWORD PTR [rcx+0x10]
    4367:   45 31 ff                xor    r15d,r15d
    436a:   45 85 db                test   r11d,r11d
    436d:   45 0f 48 df             cmovs  r11d,r15d
    4371:   41 83 c3 01             add    r11d,0x1
    4375:   49 8d 72 01             lea    rsi,[r10+0x1]
    4379:   89 f3                   mov    ebx,esi
    437b:   83 e3 03                and    ebx,0x3
    437e:   83 e6 fc                and    esi,0xfffffffc
    4381:   48 8b 4c 24 e8          mov    rcx,QWORD PTR [rsp-0x18]
    4386:   48 8d 0c 8d 00 00 00 00     lea    rcx,[rcx*4+0x0]
    438e:   48 c1 e2 02             shl    rdx,0x2
    4392:   48 29 d1                sub    rcx,rdx
    4395:   48 8d 14 08             lea    rdx,[rax+rcx*1]
    4399:   48 83 c2 0c             add    rdx,0xc
    439d:   48 89 54 24 f0          mov    QWORD PTR [rsp-0x10],rdx
    43a2:   8b 6c 24 dc             mov    ebp,DWORD PTR [rsp-0x24]
    43a6:   2b 6f 1c                sub    ebp,DWORD PTR [rdi+0x1c]
    43a9:   41 0f af e9             imul   ebp,r9d
    43ad:   48 01 c1                add    rcx,rax
    43b0:   48 89 4c 24 f8          mov    QWORD PTR [rsp-0x8],rcx
    43b5:   49 8d 45 0c             lea    rax,[r13+0xc]
    43b9:   c5 f8 57 c0             vxorps xmm0,xmm0,xmm0
    43bd:   eb 17                   jmp    43d6 <_ZN11Convolution25ProcessUncheckedOptimizedEii+0xc6>
    43bf:   90                      nop
    43c0:   49 83 c7 01             add    r15,0x1
    43c4:   44 01 cd                add    ebp,r9d
    43c7:   4c 01 f0                add    rax,r14
    43ca:   4d 01 f5                add    r13,r14
    43cd:   4d 39 df                cmp    r15,r11
    43d0:   0f 84 b6 00 00 00       je     448c <_ZN11Convolution25ProcessUncheckedOptimizedEii+0x17c>
    43d6:   4c 63 c5                movsxd r8,ebp
    43d9:   41 83 fa 03             cmp    r10d,0x3
    43dd:   0f 83 0d 00 00 00       jae    43f0 <_ZN11Convolution25ProcessUncheckedOptimizedEii+0xe0>
    43e3:   45 31 e4                xor    r12d,r12d
    43e6:   e9 64 00 00 00          jmp    444f <_ZN11Convolution25ProcessUncheckedOptimizedEii+0x13f>
    43eb:   0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]
    43f0:   48 8b 4c 24 f0          mov    rcx,QWORD PTR [rsp-0x10]
    43f5:   4a 8d 14 01             lea    rdx,[rcx+r8*1]
    43f9:   45 31 e4                xor    r12d,r12d
    43fc:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]
    4400:   c4 a1 7a 10 4c a2 f4    vmovss xmm1,DWORD PTR [rdx+r12*4-0xc]
    4407:   c4 a1 7a 10 54 a2 f8    vmovss xmm2,DWORD PTR [rdx+r12*4-0x8]
    440e:   c4 a1 72 59 4c a0 f4    vmulss xmm1,xmm1,DWORD PTR [rax+r12*4-0xc]
    4415:   c4 a1 6a 59 54 a0 f8    vmulss xmm2,xmm2,DWORD PTR [rax+r12*4-0x8]
    441c:   c5 fa 58 c1             vaddss xmm0,xmm0,xmm1
    4420:   c4 a1 7a 10 4c a2 fc    vmovss xmm1,DWORD PTR [rdx+r12*4-0x4]
    4427:   c4 a1 72 59 4c a0 fc    vmulss xmm1,xmm1,DWORD PTR [rax+r12*4-0x4]
    442e:   c5 fa 58 c2             vaddss xmm0,xmm0,xmm2
    4432:   c4 a1 7a 10 14 a2       vmovss xmm2,DWORD PTR [rdx+r12*4]
    4438:   c4 a1 6a 59 14 a0       vmulss xmm2,xmm2,DWORD PTR [rax+r12*4]
    443e:   c5 fa 58 c1             vaddss xmm0,xmm0,xmm1
    4442:   c5 fa 58 c2             vaddss xmm0,xmm0,xmm2
    4446:   49 83 c4 04             add    r12,0x4
    444a:   4c 39 e6                cmp    rsi,r12
    444d:   75 b1                   jne    4400 <_ZN11Convolution25ProcessUncheckedOptimizedEii+0xf0>
    444f:   48 85 db                test   rbx,rbx
    4452:   0f 84 68 ff ff ff       je     43c0 <_ZN11Convolution25ProcessUncheckedOptimizedEii+0xb0>
    4458:   4a 8d 14 a5 00 00 00 00     lea    rdx,[r12*4+0x0]
    4460:   4c 01 ea                add    rdx,r13
    4463:   4b 8d 3c a0             lea    rdi,[r8+r12*4]
    4467:   48 03 7c 24 f8          add    rdi,QWORD PTR [rsp-0x8]
    446c:   31 c9                   xor    ecx,ecx
    446e:   66 90                   xchg   ax,ax
    4470:   c5 fa 10 0c 8f          vmovss xmm1,DWORD PTR [rdi+rcx*4]
    4475:   c5 f2 59 0c 8a          vmulss xmm1,xmm1,DWORD PTR [rdx+rcx*4]
    447a:   c5 fa 58 c1             vaddss xmm0,xmm0,xmm1
    447e:   48 83 c1 01             add    rcx,0x1
    4482:   48 39 cb                cmp    rbx,rcx
    4485:   75 e9                   jne    4470 <_ZN11Convolution25ProcessUncheckedOptimizedEii+0x160>
    4487:   e9 34 ff ff ff          jmp    43c0 <_ZN11Convolution25ProcessUncheckedOptimizedEii+0xb0>
    448c:   48 8b 44 24 e0          mov    rax,QWORD PTR [rsp-0x20]
    4491:   48 8b 40 10             mov    rax,QWORD PTR [rax+0x10]
    4495:   48 63 48 10             movsxd rcx,DWORD PTR [rax+0x10]
    4499:   48 63 54 24 dc          movsxd rdx,DWORD PTR [rsp-0x24]
    449e:   48 0f af d1             imul   rdx,rcx
    44a2:   48 03 10                add    rdx,QWORD PTR [rax]
    44a5:   48 8b 44 24 e8          mov    rax,QWORD PTR [rsp-0x18]
    44aa:   c5 fa 11 04 82          vmovss DWORD PTR [rdx+rax*4],xmm0
    44af:   5b                      pop    rbx
    44b0:   41 5c                   pop    r12
    44b2:   41 5d                   pop    r13
    44b4:   41 5e                   pop    r14
    44b6:   41 5f                   pop    r15
    44b8:   5d                      pop    rbp
    44b9:   c3                      ret    
    44ba:   66 0f 1f 44 00 00       nop    WORD PTR [rax+rax*1+0x0]

А реализация медианы с классической сортировкой не векторизуема.

если вы избавитесь от класса Image с его оператором скобки и на прямую будете обрашаться к буферу
думаю все будет заметно быстрее
как это написать на на C# — не спрашивайте, не знаю :-)

а медиану сортировкой из стандартной библиотеке… были вы у меня в группе… руки бы оторвал :-)

если уж, стоит написать темплейтный класс и параметаризировать его по радиусу а не передавать его переменной в конструктор
тогда внутринии циклы станут константами 3,5,7
компилятору станет проще оптимизировать…
и не факт что C# проиграет так же сильно…
если вы избавитесь от класса Image с его оператором скобки и на прямую будете обрашаться к буферу

Вообще-то в optimized версии именно это и происходит — я работаю с указателями.


а медиану сортировкой из стандартной библиотеке… были вы у меня в группе… руки бы оторвал :-)

Преждевременные оптимизации — зло. Этот тот случай, когда больше времени уйдёт на написание кода.


если уж, стоит написать темплейтный класс и параметаризировать его по радиусу а не передавать его переменной в конструктор

Если сёрьзно думать об оптимизации, тогда берётся сортировочная сеть с фиксированным числом операций. И вот она просто замечательно векторизуется.


А можно упороться ещё дальше: мы ведь проходим скользящим окном. Нам не нужно при смещении на 1 пиксель всё пересортировывать заново. Нам нужен супер-алгоритм, который это умеет учитывать.

Зачем супер? Если сильно не замарачиваться, то проще скользащего окна + std::multiset сложно что-то придумать. Кода примерно столько же, как сейчас, плюс учет границ почти бесплатно. На больших окнах и 10К картинках для томографии (16 бит) реальные тесты давали что-то вроде 1.5 минуты против 2 часов наивной реализации.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории