Вопрос

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

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

  • Существует ли компилятор и ОС независимый способ написания кода, чтобы воспользоваться инструкциями SSE? Мне нравятся внутреннюю внутреннюю часть VC ++, которая включает в себя операции SSE, но я не нашел никаких решений Cross Compiler.

  • Мне все еще нужно поддержать некоторые процессоры, которые либо не имеют, либо ограниченную поддержку SSE (например, Intel Celeron). Есть ли какой -то способ избежать необходимости создавать разные версии программы, например, наличие какого -то «линкера времени выполнения», который ссылается на базовый или оптимизированный код SSE, основанный на процессоре, запускающем его при запуске процесса?

  • А как насчет других расширений процессора, рассмотрения наборов инструкций различных шоу Intel и AMD CPU, которые есть несколько из них?

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

Решение

Для вашего второго пункта есть несколько решений, если вы можете разделить различия на разные функции:

  • Простые старые указатели функций C
  • динамическое связывание (которое обычно опирается на указатели функции C)
  • Если вы используете C ++, наличие разных классов, которые представляют поддержку различных архитектур и использование виртуальных функций, может очень помочь в этом.

Обратите внимание, что, поскольку вы будете полагаться на вызовы косвенных функций, функции, которые абстрагируют различные операции, обычно должны представлять функциональность несколько более высокого уровня, или вы можете потерять все, что вы получаете из оптимизированной инструкции в накладных расходах на вызов (другими словами. Tbract Индивидуальные операции SSE - абстрактная работа, которую вы выполняете).

Вот пример с использованием указателей функций:

typedef int (*scale_func_ptr)( int scalar, int* pData, int count);


int non_sse_scale( int scalar, int* pData, int count)
{
    // do whatever work needs done, without SSE so it'll work on older CPUs

    return 0;
}

int sse_scale( int scalar, in pData, int count)
{
    // equivalent code, but uses SSE

    return 0;
}


// at initialization

scale_func_ptr scale_func = non_sse_scale;

if (useSSE) {
    scale_func = sse_scale;
}


// now, when you want to do the work:

scale_func( 12, theData_ptr, 512);  // this will call the routine that tailored to SSE 
                                    // if the CPU supports it, otherwise calls the non-SSE
                                    // version of the function

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

Хорошее чтение на эту тему: Остановить войну набора инструкций

Краткий обзор: Извините, невозможно решить вашу проблему простым и наиболее совместимым (Intel против AMD).

Внутренняя собственность SSE работает с Visual C ++, GCC и компилятором Intel. В наши дни нет проблем с ними.

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

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

В ответ на ваш комментарий:

Так эффективно, пока я не пытаюсь на самом деле выполнять код, содержащий неподдерживаемые инструкции, я в порядке, и я могу сойти с рук с «if (see2supported) {...} else {...}» типа?

Зависит от. Это нормально для инструкций SSE существовать в бинарном языке, если они не выполнены. У ЦП нет проблем с этим.

Однако, если вы включите поддержку SSE в компиляторе, это, скорее всего, обменивается ряд «нормальных» инструкций для их эквивалентов SSE (например, скалярные с плавающей точкой), так что даже куски вашего обычного не-SSE кода будут взорвать На процессоре, который не поддерживает его.

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

Вместо того, чтобы вручную кодировать альтернативную реализацию SSE в ваш скалярный код, я настоятельно рекомендую вам взглянуть на Opencl. Анкет Это переносная, кроссплатформенная система, нейтральная, кроссплатформенная система для вычислений для интенсивных приложений (и является очень совместимым с модными словами!). Вы можете написать свой алгоритм в подмножестве C99, предназначенного для векторизованных операций, что намного проще, чем SSE вручную. И самое главное, OpenCl генерирует лучшую реализацию во время выполнения, чтобы выполнить либо на графическом процессоре или же на процессоре. Так что в основном вы получаете код SSE, написанный для вас.

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

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

Существует ли компилятор и ОС независимый способ написания кода, чтобы воспользоваться инструкциями SSE? Мне нравятся внутреннюю внутреннюю часть VC ++, которая включает в себя операции SSE, но я не нашел никаких решений Cross Compiler.

Да. Внутренние SSE были по существу стандартизированы Intel, поэтому те же функции работают одинаково между Windows, Linux и Mac (в частности, с визуальным C ++ и GNU G ++).

Мне все еще нужно поддержать некоторые процессоры, которые либо не имеют, либо ограниченную поддержку SSE (например, Intel Celeron). Есть ли какой -то способ избежать необходимости создавать разные версии программы, например, наличие какого -то «линкера времени выполнения», который ссылается на базовый или оптимизированный код SSE, основанный на процессоре, запускающем его при запуске процесса?

Вы могли бы сделать это (например. dlopen()) но это очень сложное решение. Гораздо проще было бы (в C) определить интерфейс функции и вызов соответствующей версии оптимизированной функции через указатель функции или в C ++ для использования различных классов реализации, в зависимости от обнаруженного ЦП.

С OpenCl это не обязательно делать это, так как код генерируется во время выполнения для данной архитектуры.

А как насчет других расширений процессора, рассмотрения наборов инструкций различных шоу Intel и AMD CPU, которые есть несколько из них?

В рамках набора инструкций SSE есть много вкусов. Может быть довольно сложно кодировать один и тот же алгоритм в разных подмножествах SSE, когда определенные инструкции отсутствуют. Я предлагаю (по крайней мере, с самого начала), что вы выбираете минимальный поддерживаемый уровень, такой как SSE2, и возвращаетесь к скалярной реализации на старых машинах.

Это также идеальная ситуация для тестирования на единицу/регрессии, что очень важно, чтобы ваши различные реализации давали одинаковые результаты. Иметь тестовый набор входных данных и известные хорошие выходные данные и запустите одни и те же данные через обе версии функции обработки. Вам может потребоваться точный тест для прохождения (т.е. разница Epsilon между результатом и правильным ответом ниже 1e6, Например). Это очень поможет в отладке, и если вы создаете время с высоким разрешением в свою структуру тестирования, вы можете сравнить улучшения производительности одновременно.

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