2008-10-02 16 views
8

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

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

+0

Duplicate вопрос. См. [.NET Integer vs Int16?] (Http://stackoverflow.com/questions/129023/net-integer-vs-int16#137625) (Он помечен как .Net, но он применяется так же, как и об аппаратной архитектуре.) – 2008-10-02 16:18:31

+4

@JonAdams: это абсолютно не дублируется, так как .NET является собственной структурой, и все, что справедливо для .NET, может быть недействительным ни для чего другого, кроме .NET. На некоторых процессорах 32 бит операционных может быть быстрее в .NET (так как .NET был оптимизирован для этого), но при написании простого кода C 64-разрядные операционные системы могут быть намного быстрее, чем 32-битные операционные системы на этом CPU (поскольку компилятор C может иметь возможность оптимизировать код намного лучше для 64 бит, чем для 32 бит). – Mecki 2012-08-24 16:53:23

ответ

12

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

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

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

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

+1

Следует отметить, что stdint.h в C99 имеет типы int_fastN_t и uint_fastN_t, где N равно 8/16/32/64 (не все из них всегда доступны). boost имеет эквивалент для C++, а g ++ также включает stdint.h. Которые должны быть самыми быстрыми типами с минимальным требуемым размером. – 2008-10-02 16:48:25

12

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

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

3

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

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

1

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

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

7

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

Если вы являетесь номером, хрустящим на очень большом количестве данных, вы должны прочитать What Every Programmer Should Know About Memory Ульрихом Дреппером. Сосредоточьтесь на главе 6, о максимизации эффективности кэша данных.

0

Когда вы говорите, что 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 для параллельной обработки данных без распаковки после параллельной загрузки.

3

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

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

+0

Умное использование фразы «короткая работа» – dddJewelsbbb 2017-05-16 17:40:49

3

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

Также x86 CPU всегда загружают целую строку кэша из памяти, если она еще не находится в кеше, и в то время как длина кеша больше 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% производительности? Я так не думаю.