2014-02-09 6 views
4

Внутри snappy имеется раздел с условной компиляцией, который выбирает указатель dereferencing a reinterpret_cast'ed как лучшую реализацию для чтения и записи потенциально невыровненных 16, 32 и 64-битных целых чисел на архитектурах, которые, как известно, поддерживают такие операции (например, x86) , Резерв для других архитектур заключается в использовании memcpy based implementation.Допустимо использует случаи для reinterpret_cast для unaligned доступа к памяти vs memcpy?

Мое понимание заключается в том, что реализация reinterpret_cast демонстрирует неопределенное поведение, а дефинирующий детектив clang undefined действительно отмечает это.

Что меня озадачивает, хотя это: почему бы просто не использовать реализацию на основе memcpy? Я бы ожидал, что все, кроме большинства сломанных компиляторов, будут использовать intrinsics для реализации этих вызовов memcpy, поскольку размер известен во время компиляции. На самом деле я ожидал бы идентичный код из обеих реализаций на любой современной инструментальной цепочке.

Однако я также признаю, что мгновенный был написан людьми, которые знают, о чем они. Поэтому мне остается задаться вопросом, есть ли еще какое-то преимущество в использовании механизма reinterpret_cast, который перевешивает его неопределенное поведение. Не хотите, чтобы производительность зависела от качества реализации компилятора? Что-то еще я не рассматривал?

+1

Звучит как минное поле. Существует не собственный язык, правильный способ даже * получить * объект на неуравновешенном адресе в первую очередь, поэтому единственный пример использования для этого, который я вижу, - это ввод-вывод, поэтому этот код выглядит как обертывание такие вещи, как «deserialize int». –

+0

@KerrekSB Да, это определенно IO или протокол взлома протокола/формата. Тем не менее, см. 3.9.2 [основные типы], где он явно заявляет, что вы можете округлить допустимые экземпляры тривиально-скопируемых типов (которые, безусловно, являются явными типами ширины), через массивы символов без ссылки на выравнивание байтов массива символов. Таким образом, реализация memcpy определенно определяется поведением. И reinterpret_cast определенно не определен. – acm

+0

Замечания, прилагаемые к [этой фиксации] (https://code.google.com/p/snappy/source/detail?r=59&path=/trunk/snappy-stubs-internal.h), являются интересными. По-видимому, это действительно влияет на производительность. –

ответ

2

Не зная программиста (-ов), который написал этот код в первую очередь, я сомневаюсь, что вы можете получить действительно авторитетный ответ.

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

В то время как умные современные компиляторы оптимизируют memcpy, более старые могут не быть. Согласованная производительность может быть очень важна для этой библиотеки, поэтому они, похоже, пожертвовали некоторой корректностью (поскольку reinterpret_cast представляется потенциально UB) в пользу получения более последовательных результатов в более широком наборе компиляторов.

-1

Причина в том, что быстрее (на x86) загружать int из неравномерного адреса, чем копировать его, а затем загружать.

Накладные расходы на неравновесную нагрузку составляют около 2 раз. Память сводится к 4 байтовым чтениям, 4 байта (или 32 бит записи, в зависимости от компилятора), а затем вам по-прежнему нужна нагрузка. В лучшем случае оптимизатор может заметить, что чтение после чтения является избыточным.

Лично я бы реализовал безопасный метод как 4 байтовые нагрузки со сдвигами.

+1

Я обнаружил, что во многих случаях, которые я рассмотрел, две стратегии производят идентичный код для x86, используя GCC 4.8.1 в таргетинге на Linux x86_64. – acm

+1

На самом деле использование стратегии memcpy позволяет генерировать более эффективный код, потому что с использованием метода reinterpret_cast вам необходимо использовать -fno-strict-aliasing, тогда как вы не используете memcpy. – acm