SSE SSE2 и SSE3 для GNU C++

Обновление: теперь мы также рассматриваем этот вопрос в эпизоде ​​ AskFirebase .

Загрузка многих объектов из Firebase не должна быть медленной, поскольку вы можете конвейерно запросить запросы. Но ваш код делает это невозможным, что действительно приведет к субоптимальной производительности.

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

Your app                     Firebase 
                             Database

        -- request item 1 -->
                               S  L
                               e  o
                               r  a
                               v  d
                               e  i
        <-  return item  1 --  r  n
                                  g
        -- request item 2 -->
                               S  L
                               e  o
                               r  a
                               v  d
                               e  i
                               r  n
        <-  return item  2 --     g
        -- request item 3 -->
                 .
                 .
                 .
        -- request item 30-->
                               S  L
                               e  o
                               r  a
                               v  d
                               e  i
                               r  n
                                  g
        <-  return item 30 --

В этом сценарии вы ожидаете 30 раз ваше время в оба конца + 30 раз больше времени, необходимого для загрузки данных с диска. Если (для простоты) мы говорим, что roundtrips занимают 1 секунду, а загрузка элемента с диска также занимает одну секунду, что меньше, чем 30 * (1 + 1) = 60 секунд.

В приложениях Firebase вы если вы отправите все запросы (или, по крайней мере, разумное число из них) за один раз:

Your app                     Firebase 
                             Database

        -- request item 1 -->
        -- request item 2 -->  S  L
        -- request item 3 -->  e  o
                 .             r  a
                 .             v  d
                 .             e  i
        -- request item 30-->  r  n
                                  g
        <-  return item  1 --     
        <-  return item  2 --      
        <-  return item  3 --
                 .
                 .
                 .
        <-  return item 30 --

Если мы снова примем 1-й кругооборот и 1 секунду загрузки, вы ожидаете 30 * 1 + 1 = 31 секунд.

Итак: все запросы проходят через одно и то же соединение. Учитывая это, единственная разница между get(1), get(2), get(3) и getAll([1,2,3]) - это некоторые накладные расходы для кадров.

Я установил jsbin, чтобы продемонстрировать поведение . Модель данных очень проста, но это показывает разницу.

function loadVideosSequential(videoIds) {
  if (videoIds.length > 0) {
    db.child('videos').child(videoIds[0]).once('value', snapshot => {
      if (videoIds.length > 1) {
        loadVideosSequential(videoIds.splice(1), callback)
      }
    });
  }
}

function loadVideosParallel(videoIds) {
  Promise.all(
    videoIds.map(id => db.child('videos').child(id).once('value'))
  );
}

Для сравнения: последовательная загрузка 64 элементов занимает 3,8 секунды в моей системе, а загрузка их конвейерно (так как клиент Firebase выполняется изначально) требуется 600 мс. Точные цифры будут зависеть от вашего соединения (латентность и пропускная способность), но конвейерная версия всегда должна быть значительно быстрее.

54
задан yoitsfrancis 30 August 2009 в 18:46
поделиться

4 ответа

Извините не знайте об учебном руководстве.

Ваш лучший выбор (по моему скромному мнению), состоит в том, чтобы использовать SSE через "внутреннюю" Intel функций, обеспечивает для обертывания (обычно) единственных инструкций SSE. Они сделаны доступными через ряд, включают файлы, названные *mmintrin.h, например, xmmintrin.h является исходной системой команд SSE.

Начинаются знакомый с контентом Оптимизации Intel , Справочник является хорошей идеей (см. раздел 4.3.1.2 для примера intrinsics), и разделы SIMD являются существенным чтением. Справочники системы команд довольно полезны также, в документации той каждой инструкции включает "внутреннюю" функцию, которой она соответствует.

Делают , проводят некоторое время, осматривая ассемблер, произведенный компилятором из intrinsics (Вы изучите много), и на профилировании/измерении производительности (Вы постараетесь не напрасно тратить время код луга SSE для небольшого возврата на усилии).

Обновление 31.05.2011: существует некоторое очень хорошее покрытие intrinsics и векторизации в Вуали Agner оптимизация PDFs ( спасибо ), хотя это немного распространено о (например, раздел 12 из сначала один и раздел 5 из 114-секундного ). Это не точно учебный материал (на самом деле существуют "эти, руководства не являются для новичков" предупреждением), но они действительно справедливо рассматривают SIMD (используемый ли через asm, intrinsics или векторизацию компилятора) как всего одна часть большей панели инструментов оптимизации.

Обновление 04.10.2012: А миленькая Статья в журнале Linux на gcc векторе intrinsics заслуживает упоминания здесь. Более общий, чем просто SSE (покрывает PPC и расширения ARM также). Существует хороший набор ссылок на последняя страница , которая привлекла мое внимание к Intel "intrinsics руководство" .

59
ответ дан Community 7 November 2019 в 08:01
поделиться

Проверьте-mtune, и - идут опции,-msse*, и-mfpmath, конечно. Все те позволяют GCC сделать определенную для SSE оптимизацию.

Что-либо кроме того - область Ассемблера, я боюсь.

GCC Руководство Онлайн - i386 и x86_64 Опции

8
ответ дан DevSolar 7 November 2019 в 08:01
поделиться

Простое учебное руководство? Не то, чтобы я знаю о.

, Но любая информация об использовании MMX или любой версии SSE будет полезно для изучения, ли для GCC или для ICC или VC.

Для приобретения знаний о векторных расширениях GCC введите "информацию gcc" и перейдите к Узлу: Векторные Расширения.

1
ответ дан Zan Lynx 7 November 2019 в 08:01
поделиться

Самая простая оптимизация для использования должна позволить gcc испускать код SSE.

Флаги:-msse,-msse2,-msse3, - идут =,-mfpmath=sse

Для более краткого списка приблизительно 386 опций см. http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/i386-and-x86_002d64-Options.html#i386-and-x86_002d64-Options, более точная документация для Вашей определенной версии компилятора там: http://gcc.gnu.org/onlinedocs/.

Для оптимизации всегда проверяйте Вуаль Agner: http://agner.org/optimize/. Я думаю, что у него нет учебных руководств SSE для intrinsics, но он имеет некоторые действительно аккуратные приемы C++ станд. и также предоставляет большую информацию о кодировании блока SSE (который может часто записываться к intrinsics).

20
ответ дан Sebastian Mach 7 November 2019 в 08:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: