WedX - журнал о программировании и компьютерных науках

Встраивание ассемблера в С++ приемлемо?

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

inline __int64 GetCpuClocks()
{

    // Counter
    struct { int32 low, high; } counter;

    // Use RDTSC instruction to get clocks count
    __asm push EAX
    __asm push EDX
    __asm __emit 0fh __asm __emit 031h // RDTSC
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    // Return result
    return *(__int64 *)(&counter);

}

(Вышеупомянутая функция пришла из другого сообщения SO, которое я видел)

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

(Предположим, что ваша архитектура будет исправлена ​​и известна)

РЕДАКТИРОВАТЬ Я только что нашел это, вот на что я намекаю:

https://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-CC

EDIT2 Это больше нацелено на Linux и x86 - это просто общий вопрос С++/ассемблера (или я так думал).

11.12.2012

  • Вы конкретно спрашиваете о Visual C++? Я предполагаю, что другие компиляторы могут иметь другие ограничения. 12.12.2012
  • @Robᵩ Нет, во всяком случае, я стремился к Linux, ICC и G++. Я только что схватил первую попавшуюся функцию на ассемблере. 12.12.2012
  • Это может быть немного OT, но если переход и возврат не влекут за собой слишком больших штрафов, рассмотрите возможность написания ассемблера на чистом ассемблере (в отдельной единице компиляции), чтобы сделать ваш код более переносимым. Избегая встраивания, вы иногда можете уменьшить задержку за счет более эффективного использования кеша. Однако это более важно для встроенных платформ. 12.12.2012

Ответы:


1

Я хотел бы ответить на подвопрос:

Создает ли это больше проблем, чем решает, или это приемлемо для конкретных небольших задач?

Это определенно так! Используя встроенный ассемблер, вы берете у компилятора возможность оптимизировать код. Он не может выполнять подстановку частичных выражений или любую другую причудливую оптимизацию. Очень, очень сложно создать код лучше, чем тот, который компилятор выдает с -O3. И в качестве бонуса, код становится еще лучше со следующей версией компилятора (при условии, что следующая версия компилятора не сломает его ;)).

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

В качестве анекдотической ссылки я хотел бы эту публикацию Линуса Торвальдса , относящийся к реализации SHA1 в git, которая превосходит оптимизированный вручную SHA1 в libcrypt.

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


О фрагменте и о том, что сказали другие. Особенно с такими функциями вы получите штраф за производительность. Во встроенном ассемблере вы должны быть очень осторожны, чтобы регистры сохранялись в том состоянии, в котором они предполагаются компилятором (push/pop, как указано выше). В то время как если вы пишете код нормально, компилятор может позаботиться и оставить именно те переменные, для которых имеет смысл в регистрах и те, которые не помещаются в стеке.

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

11.12.2012
  • Конечно, вы могли бы возразить, что компилятор не может быть потрясающим во всем. Таким образом, чтобы компенсировать широкий спектр случаев, которые он может обрабатывать, вероятно, есть много областей, где для небольшой конкретной задачи программист мог бы написать меньше инструкций asm? 12.12.2012
  • @ user997112 Какие случаи вы имеете в виду? Думая обо всем, что связано с числами, вы, вероятно, не сможете их сократить. Также обратите внимание, что я поменял ссылку, моя исходная на самом деле включала встроенный ASM. 12.12.2012
  • Я ничего не имею в виду, но было бы, безусловно, полезно, если бы можно было выяснить, есть ли области, в которых компиляторы плохи. 12.12.2012
  • Конечно, вы всегда можете посмотреть на вывод ASM (у большинства компиляторов есть флаг командной строки, чтобы сохранить его в выходном каталоге) и сравнить с тем, что вы написали бы. Обязательно сделайте это с -O3. И удачи в поиске вашего кода;) [обязательно включите аннотации строк] 12.12.2012
  • На самом деле очень мало областей, в которых люди могут превзойти компилятор. Компилятор, который вы используете в примере, имеет встроенные функции компилятора для всех интересных инструкций, которые могут нам понадобиться, включая чтение счетчиков производительности ЦП. Одна из проблем со встроенным ассемблером в обычной функции заключается в том, что он мешает оптимизации окружающего кода компилятором, что затрудняет достижение чистого выигрыша. И, конечно же, ассемблерный код обеспечивает нулевую переносимость кода. 12.12.2012

  • 2

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

    В вашем примере это инструкции __asm push EAX и __asm pop EAX.

    Реальный ответ, я полагаю, заключается в том, что вам нужно знать достаточно о том, что делает asm, чтобы быть уверенным, что вы можете обращаться с ним как с черным ящиком. :)

    11.12.2012
  • Итак, в основном убедитесь, что состояние, в котором вы начинаете, является состоянием, в котором вы закончите? Что, если вы хотите вернуть вычисление из ассемблера, как вы это сделаете? 12.12.2012
  • Да, убедитесь, что вы не связываетесь с государством. Я думаю, что возврат значения будет зависеть от компилятора. 12.12.2012
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]