Битовые поля: Набор по сравнению с тестом-и-набором (для производительности)

Добавление ответа для соответствия последнему стандарту ECMAScript 6.

Посмотрите эту страницу, чтобы прочитать ее с примерами.

И довольно вкусное предостережение: эта удивительная новая функциональность будет работать практически с любым итеративным объектом! Из MDN:

Оператор for ... of создает цикл, повторяющийся по итерируемым объектам (включая Array, Map, Set, String, TypedArray, arguments объект и т. Д.) ...

Так, например, вы можете использовать:

for (let item of myArr) {
    console.log(item);
} 

Хотя, чтобы прояснить, что вы регистрируете объект, мне было бы немного приятнее следующему человеку прочитать ваш код, переименовав "item" to "obj", создавая это:

for (let obj of myArr) {
    console.log(obj);
} 

Зачем переименовывать переменную? Что ж, хотя мы используем термин «элемент» для обозначения любого общего элемента в массиве, ваш массив содержит только объектов. Если вы знаете или ожидаете, что этот массив будет содержать только каждый содержащий объекты, вы можете назвать переменную на основе типа элемента элемента (то есть объекта), который содержится в массиве.

Удачного кодирования!

6
задан finnw 8 June 2009 в 11:50
поделиться

9 ответов

Тест перед установкой действительно имеет значение, но насколько это зависит от ваших сценариев использования.

В любом случае данные попадут в строку кэша (например, просто запись или проверка и установка).

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

Теперь учтите, что ваш код искажает огромные объемы данных, и вы обращаетесь к каждому фрагменту данных только один раз или дважды. В таком случае можно предположить, что большинство обращений к памяти - это промахи кеша. Что произойдет, если большинство ваших строк кэша загрязнены в точке, где происходит промах кеша, и большинство строк кэша загрязнены?

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

Это может не иметь значения для одного ядра ЦП, поскольку в наши дни память работает быстро, но другой ЦП (надеюсь) будет выполнять и другую работу. Вы можете быть уверены, что другое ядро ​​ЦП выполнит все немного быстрее, если шина не занята перемещением строк кэша внутрь и наружу.

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

По поводу ветки: Конечно: дорого, но кеш-промах намного хуже! Кроме того, если вам повезет, процессор будет использовать функции выполнения вне очереди, чтобы компенсировать промахи кеша с затратами на ветку.

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

  • Обход кеша: архитектура x86 имеет невременные нагрузки и сохраняет для с этой целью. Они спрятаны где-то в наборах инструкций SSE и могут использоваться на языке c через встроенные функции.

  • (Только для экспертов): используйте несколько строк встроенного ассемблера, который заменяет функцию test-and-set ассемблером, использующим инструкцию CMOV (условное перемещение). Это не только сохранит чистоту ваших строк кэша, но и предотвратит ветвление. Теперь CMOV является медленной инструкцией и превосходит ветвление только в том случае, если ветвления невозможно предсказать. Так что вам лучше протестировать свой код.

10
ответ дан 8 December 2019 в 14:46
поделиться

Это интересный вопрос, и ответ Нильса о строках кеша - определенно отличный совет.

Я хотел бы подчеркнуть важность кода профилирования для измерения реальной производительности - можете ли вы измерить, как часто этот флаг уже будет установлен в данных, с которыми вы сталкиваетесь? Производительность может сильно измениться в зависимости от ответа.

Ради удовольствия, Я использовал ваш код, чтобы провести небольшое сравнение набора и теста затем набора для массива из 50 миллионов элементов, заполненного различными пропорциями единиц. Вот график:

comparison of set vs. test-then-set
(источник: natekohl.net )

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

3
ответ дан 8 December 2019 в 14:46
поделиться

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

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

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

1
ответ дан 8 December 2019 в 14:46
поделиться

Either approach will require that the data is loaded into the cache, so your only saving will be a difference between a read/write and a write.

I don't see how this change could make your code slower with larger data sets, so you're likely safe enough on that front.

It smells a little like a premature-optimistaion to me. (Unless your profiling has identified this as a bottleneck)

As with all things performance related the best way to be sure of the effect of a code change is to measure it. You should be able to create a large amount of test data relatively easily.

0
ответ дан 8 December 2019 в 14:46
поделиться

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

Но, как уже указывалось, это пахнет микрооптимизацией.

0
ответ дан 8 December 2019 в 14:46
поделиться

Вы всегда можете профилировать, но я почти уверен, что первая версия одновременно быстрее и менее непонятно.

0
ответ дан 8 December 2019 в 14:46
поделиться

Это мои интерпретации вашего требования,

  • у вас есть флаг, инициализированный отдельно
  • , он устанавливается только один раз (в 1) и не сбрасывается после этого
  • Но это попытка установки будет предпринята много раз для одного и того же флага
  • И у вас много экземпляров этих флагов (каждый из которых требует одинаковой обработки)

Предполагая, что

  • оптимизация пространства имеет гораздо меньший вес, чем оптимизация времени ,

Я предлагаю следующее.

  • Во-первых, в 32-битных системах полезно использовать 32-битные целые числа, если вас беспокоит время доступа
  • Если вы пропустите проверку флага «слово», запись будет довольно быстрой. Но, учитывая, что у вас очень большое количество флагов, которые вы будете продолжать проверять и устанавливать, если они еще не установлены, было бы лучше оставить условную проверку.
  • Но, сказав это, если ваша платформа выполняет параллельные операции (например, запись на диск обычно может быть отправлена ​​параллельно с выполнением вашего кода), было бы целесообразно пропустить проверку.
2
ответ дан 8 December 2019 в 14:46
поделиться

Тест перед установкой не имеет никакого смысла - код без теста чище и к тому же немного быстрее.

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

0
ответ дан 8 December 2019 в 14:46
поделиться

Поскольку никто не сказал этого, я скажу.

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

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

0
ответ дан 8 December 2019 в 14:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: