На 32-битных процессорах, является ли «целочисленный» тип более эффективным, чем «короткий»?

В 32-битном ЦП целое число составляет 4 байта, а короткое целое – 2 байта. Если я пишу приложение на C / C ++, которое использует много числовых значений, которые всегда будут соответствовать предоставленному диапазону короткого целого числа, эффективнее ли использовать 4 байтовых целых числа или 2 байтовых целых числа?

Я слышал, что он предположил, что 4 байтовых целых числа более эффективны, так как это соответствует пропускной способности шины из памяти в CPU. Однако, если я объединю два коротких целых числа, будет ли пакет ЦП одновременно поддерживать оба значения за один проход параллельно (таким образом, охватывая ширину полосы 4 байта шины)?

Да, вы должны обязательно использовать 32-битное целое число в 32-битном ЦП, иначе он может замаскировать неиспользуемые биты (т. Е. Он будет всегда выполнять математику в 32 бита, а затем преобразовать ответ в 16 бит)

Он не будет выполнять сразу две 16-битные операции, но если вы сами напишите код, и вы уверены, что он не переполнится, вы можете сделать это сами.

Изменить : я должен добавить, что это также зависит от вашего определения «эффективный». Хотя он сможет выполнять 32-битные операции быстрее, вы, конечно, будете использовать вдвое больше памяти.

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

Если у вас большой массив чисел, то идите с минимальным размером, который работает. Будет более эффективно работать с массивом из 16 бит шорт, чем 32-битных ints, так как вы получите вдвое больше плотности кеша. Стоимость любого расширения знака, который должен выполнять процессор для работы с 16-битными значениями в 32-битных регистрах, тривиально незначительна по сравнению со стоимостью промаха в кэше.

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

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

Если вы набираете номер на большом количестве данных, вы должны прочитать « Каждый программист должен знать о памяти » Ульриха Дреппера. Сосредоточьтесь на главе 6, о максимизации эффективности кэша данных.

32-битный процессор – это центральный процессор, который обычно работает с 32-битными значениями внутри, но это не означает, что он работает медленнее при выполнении той же операции по значению 8/16 бит. x86, например, все еще обратная совместимость до 8086, может работать на долях регистра. Это означает, что даже если регистр имеет ширину в 32 бит, он может работать только на первом 16 или первом 8 бит этого регистра, и вообще не будет замедления. Эта концепция даже была принята x86_64, где регистры 64 бит, но они все еще могут работать только на первых 32, 16 или 8 бит.

Кроме того, x86-процессоры всегда загружают целую строку кэша из памяти, если она еще не находится в кеше, а длина кеша больше 4 байта (для 32-битных процессоров – 8 или 16 байт) и, следовательно, загрузка 2 байта из памяти одинаково быстро, как загрузка 4 байта из памяти. Если обрабатывать многие значения из памяти, 16-разрядные значения могут быть намного быстрее, чем 32-битные значения, так как меньше переносов памяти. Если строка кэша составляет 8 байт, в строке кэша есть четыре 16-битных значения, но только два 32-битных значения, поэтому при использовании 16-битных ints у вас есть один доступ к памяти каждые четыре значения, используя 32-битные ints, у вас есть одно каждые два значения , что приводит к удвоенному количеству передач для обработки большого массива int.

Другие процессоры, например PPC, не могут обрабатывать только часть регистра, они всегда обрабатывают полный регистр. Однако у этих ЦП обычно есть специальные операции загрузки, которые позволяют им, например, загружать 16-битное значение из памяти, расширять его до 32 бит и записывать в регистр. Позже они имеют специальную операцию хранения, которая берет значение из регистра и сохраняет только последние 16 бит в памяти; для обеих операций требуется только один цикл ЦП, так же, как потребуется 32-разрядная загрузка / хранилище, поэтому также нет разницы в скорости. И поскольку PPC может выполнять только арифметические операции с регистрами (в отличие от x86, который также может работать непосредственно в памяти), эта процедура загрузки / хранения имеет место, независимо от того, используете ли вы 32-битные int или 16-битные int.

Единственным недостатком, если вы связываете несколько операций с 32-битным процессором, который может работать только на полных регистрах, является то, что 32-разрядный результат последней операции может быть «сокращен» до 16 бит до выполнения следующей операции, иначе результат может быть неправильным. Такой снимок – это всего лишь один цикл ЦП, хотя (простая операция И), и компиляторы очень хорошо разбираются, когда такой откат действительно необходим, и когда он его покидает, не окажет никакого влияния на конечный результат , поэтому такое сокращение не выполняется после каждой инструкции, оно выполняется только в том случае, если оно действительно неизбежно. Некоторые процессоры предлагают различные «расширенные» инструкции, которые делают такое сокращение ненужным, и я видел много кода в моей жизни, где я ожидал такого сокращения, но, глядя на сгенерированный код сборки, компилятор нашел способ полностью избегайте этого.

Поэтому, если вы ожидаете общего правила здесь, я должен буду вас разочаровать. Нельзя даже точно сказать, что 16-битные операции одинаково быстры для 32-разрядных операций, и никто не может точно сказать, что 32-разрядные операции всегда будут быстрее. Это зависит и от того, что именно делает ваш код с этими номерами и как он это делает. Я видел тесты, в которых 32-разрядные операции выполнялись быстрее на некоторых 32-битных ЦП, чем один и тот же код с 16-разрядными операциями, однако я также уже видел, что противоположное значение истинно. Даже переключение с одного компилятора на другой или обновление версии вашего компилятора может уже все снова развернуться. Я могу только сказать следующее: тот, кто утверждает, что работа с шортами значительно медленнее, чем работа с ints, должен предоставить примерный исходный код для этой заявки и назвать CPU и компилятор, который он использовал для тестирования, поскольку я никогда не испытывал ничего подобного внутри о последних 10 лет. Могут быть ситуации, когда работа с ints может быть на 1-5% быстрее, но все, что ниже 10%, не является «значительным», и вопрос в том, стоит ли в два раза потерять память в некоторых случаях только потому, что может купить вас 2% производительности? Я так не думаю.

Это зависит. Если вы связаны с CPU, 32-разрядные операции с 32-битным процессором будут быстрее, чем 16 бит. Если вы связаны с памятью (особенно если у вас слишком много промахов в кэше L2), используйте наименьшие данные, которые вы можете вдавить.

Вы можете узнать, какой из них вы используете профилировщик, который будет измерять как провалы CPU, так и L2, такие как Intel VTune . Вы будете запускать свое приложение 2 раза с одинаковой нагрузкой, и оно объединит 2 прогона в одно представление о горячих точках в вашем приложении, и вы можете увидеть для каждой строки кода, сколько циклов было потрачено на эту строку. Если на дорогой строке кода вы видите 0 промахов кеша, вы связаны с ЦП. Если вы видите тонны промахов, вы связаны с памятью.

Не слушайте совет, попробуйте.

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

Если вы работаете с большим набором данных, наибольшую озабоченность вызывают проблемы с памятью. Хорошей моделью в этом случае является предположить, что процессор бесконечно быстр, и тратите свое время на беспокойство о том, сколько данных нужно переместить в / из памяти. Фактически, процессоры теперь настолько быстры, что иногда более эффективно кодировать (например, сжимать) данные. Таким образом, процессор (потенциально много) работает (декодирование / кодирование), но пропускная способность памяти существенно уменьшается.

Таким образом, если ваш dataset большой, вам, вероятно, лучше использовать 16-битные целые числа. Если ваш список отсортирован, вы можете разработать схему кодирования, которая включает в себя дифференциальную кодировку или длину строки, что еще больше сократит пропускную способность памяти.

Когда вы скажете 32bit, я предполагаю, что вы имеете в виду x86. 16-разрядная арифметика довольно медленная: префикс размера операнда делает декодирование очень медленным. Поэтому не делайте переменные temp short int или int16_t.

Однако x86 может эффективно загружать 16 и 8 битных целых чисел в 32 или 64-битные регистры. (movzx / movsx: ноль и расширение знака). Поэтому не стесняйтесь использовать short int для массивов и структурных полей, но убедитесь, что вы используете int или long для ваших временных переменных.

Однако, если я объединю два коротких целых числа, будет ли пакет ЦП одновременно поддерживать оба значения за один проход параллельно (таким образом, охватывая ширину полосы 4 байта шины)?

Это вздор. инструкции загрузки / хранения взаимодействуют с кешем L1, а ограничивающим фактором является количество операций; ширина не имеет значения. например, на нагрузку core2: 1 и 1 магазин за цикл, независимо от ширины. Кэш L1 имеет 128 или 256-битный путь к кэшу L2.

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

Interesting Posts

Элемент списка ListView с помощью настраиваемого селектора

Угловая: вызов функции controllerа внутри функции директивной ссылки с использованием &

Получение IP-адреса текущего компьютера с использованием Java

Получить текст из буфера обмена с помощью GetText – избежать ошибки в пустом буфере обмена

Как удалить большое количество записей из истории url в Firefox?

Как получить сертификат отпечатка SHA-1 в Android Studio для режима отладки?

Каков самый быстрый способ преобразования float в байт ?

Не удается подключиться к определенным сайтам

Как мне зарегистрироваться на C # без использования сторонних библиотек?

Преобразование данных электронной таблицы Excel

Строковая интерполяция в представлении «Бритва»?

Запретить добавление суффикса к ресурсам при загрузке страницы

Есть ли способ заставить Windows 7 индексировать общие сетевые диски?

Установка .Net Framework 3.5 с пакетом обновления 1 (SP1) для Windows 8 x64 завершается с ошибкой и сбой при 65.8% с кодом ошибки 0x800f081f

Невозможно установить заголовок в JSP. Ответ уже сделан

Давайте будем гением компьютера.