Я хотел бы узнать если процессору легче сравнивать с нулем чем с другими цифрами, и если так, как это можно показать, кодом чтоли? Или както это аргументировать..
посмотри в сторону инструкции OR (!) и её применения для сравнения с нулем. зы: пример: or eax, eax смотри, какие флаги изменятся.
Если я правильно понял вопрос, то с нулем можно сравнивать так: "test eax, eax". Это аналогично "cmp eax, 0", однако занимает меньше памяти. Время выполнения, кажется, одинаковое.
Я давненько не занимаюсь ассемблером и уже подзабыл его, поэтому прошу вас както прокомментировать это. Я не уверен что это вообще правда.. Если это правда - я бы хотел знать почему именно, в нескольких словах, а если по подробнее - то еще лучше, надеюсь на ответ. Если есть линк на какойто ресурс где можно понять разницу - было бы замечательно..
Например, есть два числа, первое число это ноль, второе скажем 2239823. Производится (скажем) миллион итераций и внутри каждой итерации происходит сравнение случайного числа на равность с нулем. Неужели если бы происходило сравнение на равность со вторым числом (в нашем случае с 2239823) скорость была бы такая же высокая как в первый раз когда происходило сравнение (случайного числа) с нулем?
Что-то я не совсем понял вопрос. Инструкции "cmp eax, 0" и "cmp eax, 2239823" работают равное время, если ты об этом. Время работы инструкций можно посмотреть здесь: http://wasm.ru/article.php?article=1010029
Нет. Все дело в реализации механизмов. Для сравнения с любым числом чаще всего используется вычитание без изменения операндов (cmp). Согласитесь, что реализация команды вычитания на алгебре логике гораздо сложнее 1 команды алгебра логики (допустим or). Выборку и формирование мопов можно отбросить. Роль играет лишь непосредственная скорость выполнения команды. А у or она значительно выше. Другое дело, что or годится лишь для проверки на 0. т.к. 0 or 0 = 0 в результате операции получился 0 и возводится zf. Отсюда и ноги растут.
Теоретически рассуждения вполне правильные, но на практике "cmp регистр, число" работает 1 такт и "or регистр, регистр" работает 1 такт. Выигрыш от использования or/test получается только по размеру кода. Конечно размер кода может повлиять на время выполнения инструкции - используя более длинные инструкции можно вылезти за границы кеша и получится дополнительная задержка. Но это уже совсем другой вопрос. test - это такая же логическая команда как or (это and без записи результата). Разговор идет, как я понимаю, о сравнении cmp и or/test. А что использовать or или test - это уже скорее вопрос вкуса. Например, программисты Microsoft обычно используют or, а я обычно использую test.
Во-первых, процессор это тактируемое устройство, поэтому несмотря на то, что логические операции физически выполняются быстрее арифметических (отсутствует задержка распространения переноса), тем не менее величина такта или частота ядра выбираются так, чтобы основные арифметические операции add\sub\cmp выполнялись за один такт. Поэтому латентность операций add\sub\cmp и or\xor\and\test одинакова и составляет 1 такт. Во-вторых, современные компы являются суперскалярными, т.е. они могут выполнять несколько независимых операций одновременно и спекулятивно изменять порядок выполнения операций. Поэтому операции cmp и test, не изменяющие значения регистра, имеют преимущество перед sub и or\and, т.к. не вносят зависимости последующих операций, использующих данный регистр. Фактически при операции OR значение регистра не изменяется, точнее сказать остается тем же, но процессор не различает операций типа or eax,eax и or eax,edx и в обоих случаях считает, что значение регистра-приемника изменилось и поэтому не может выполнить другие операции, читающие eax до или одновременно c or eax,eax. А вот в случае с test может, т.к. eax при этом не изменяется и проц об этом "знает". Поэтому во всех мануалах по оптимизации для проверки на 0 рекомендуют использовать test, а не or. Cmp тоже не изменяет регистра, но по размеру на 1 байт длиннее test, поэтому test предпочтительнее
iley Опа. Вот тут ты меня не понял. Я не говорил про test и or. test - это and без изменения операндов. Я же говорил про cmp - sub без изменения операндов. Время выполнения test и cmp разные. Логика разная.
max7C4 Это ты не понял Время выполнения test и cmp в пикосекундах действительно разное, но в тактах оно одинаковое. Пусть комп имеет частоту 1Ггц, т.е. величина такта = 1нс. Если согласно мануалу операции add\sub\cmp имеют латентность 1 такт, то они заведомо должны выполняться за время < 1нс, пусть например за 0.8-0.9 нс, а быстрые and\test, не требующие ожидания распространения переноса, скажем за 0.3-0.5 нс. Ну и что из этого ? Комп все равно все действия выполняет с привязкой к началу такта, т.е. с интервалом в 1нс, поэтому ему совершенно без разницы за какое время реально будет готов результат - за 0.8-0.9 или за 0.3-0.5 нс, т.к. в любом случае этот результат будет использован только через 1нс. Вывод: задержки (латентности) операций измеряются в тактах и для всех современных компов латентности add\sub и and\or одинаковы и составляют 1 такт.
Да, а почему бы и не 7-8 или 100-200 Совет: кончай курить, вставай на лыжи Загляни в официальные мануалы по оптимизации от Intel и\или AMD, или в instruction_tables.pdf А.Фога. Только не падай в обморок, когда увидишь латентности = 0.5 такта в P4 model <= 2 - это все конвеерная туфта и реальная латентность = 1 такт как во всех нормальных процах. Ну а 3-4 это латентность операций с памятью - 3 такта на загрузку операнда и 1 такт на исполнение
С нулем сравнить проще всего потому, что для этого вообще не требуется операций. А флаг нуля автоматически выставляетс для ряда инструкций. У Агнера Фога так у nop латентность 0,25 =) 2 Алу при этом каждый работает на удвоенной точности. Т.е если не зависит от вычисления предыдущей команды на данном алу, то может считаться паралельно. У последних процов так три алу. Что касается sub и and И cmp, test. cmp test не изменяют регистры. Поэтому они поддаются паралеливанию. Что касается sub и and то тут зависит от проца может он распознать этот случий или нет.
Не наговаривай на Фога 0.25 это не латентность, а условное значение throughput (см.примечание "A value of 0.25 indicates 4 instructions per clock cycle"). А говорить о латентности NOP, вообще не имеет смысла, т.к. она не влияет ни на какие последующие операции, поэтому ее "эффективная" латентность = 0 (также как и предсказанных jcc). Поэтому у Фога и AMD указывается латентность NOP = 0. Однако в отличие от атланов, в которых NOP вообще не исполняются, а просто помечаются выполненными в планировщиках, во всех пеньках NOP реально поступают на "исполнение" в АЛУ, поэтому Intel "честно" указывает для них латентность = 0.5 (т.е. время в течение которого NOP реально "занимает" АЛУ и соотв-но не дает выполниться другим операциям на данном АЛУ). Да, но только у атлонов и Core2, и работают они ес-но на частоте ядра, а не на "удвоенной" как в P4 Теоретически да, но реально в современных процах x86 специальный анализ операндов производится только для случая обнуления регистра командами sub\xor\pxor\xorps\xorpd r,r. Другие случаи не анализируются, поэтому команды or r,r и add\sub r,0 фактически не меняют значения регистра, но формально изменяют и поэтому "придерживают" следующие операции, читающие этот регистр. А команды типа and r,0 и т.п. фактически не зависят от значения регистра, но формально зависят и поэтому вынуждены ждать пока выполнится пред.операция, изменяющая этот регистр
leo Сорри за оффтоп: книгу бы тебе написать. Или на крайний случай статью хоть и на тот же васм. Очень была бы полезная штука, ИМХО
уже есть несколько хороших статей/книг. Агнер Фог пишет неплохо. На ixbt.com есть несколько статей - "Современные десктопные процессоры архитектуры x86_ общие принципы работы", "Обзор микроархитектур современных десктопных процессоров" например. Еще у КК есть книжка, правда там ногого нет, а что есть в том ошибок не избежал, но на русском я книжек больше не видел.