Расходы переводчика, и просто , будучи переводчиком, объясняют большую часть средней разницы. У меня нет объяснения более высокой дисперсии.
R - интерпретируемый язык, а не JIT, скомпилированный для машинного кода, такого как Java, или заблаговременно, как C. ( IЯ не знаю много о внутренностях R, только о процессорах и производительности, поэтому я делаю много предположений здесь .)
Код, который работает на реальном оборудовании процессора интерпретатор R , не совсем ваша R-программа.
Управляющие зависимости в R-программе (например, if()
) становятся data зависимостями в интерпретаторе. В настоящее время выполняется только данные для интерпретатора, работающего на реальном CPU.
Различные операции в программе R становятся зависимостями управления в интерпретаторе. Например, вычисляя myvec[i]
, оператор +
, вероятно, будет выполняться двумя различными функциями в интерпретаторе. И отдельная функция для >
и if()
операторов.
Классический цикл интерпретатора основан на косвенной ветви, которая отправляется из таблицы указателей функций. Вместо того, чтобы быть выбранным / не принятым, ЦПУ необходим прогноз для одного из многих недавно использованных целевых адресов. Я не знаю, использует ли R одну непрямую ветвь, подобную этой, или пытается придумать что-то более похожее на то, чтобы конец каждой отправки блока интерпретатора переходил к следующей, вместо того, чтобы вернуться к главному циклу отправки.
СовременныйПроцессоры Intel (такие как Haswell и более поздние) имеют прогноз IT-TAGE (длина непрямой TAgged GEometric истории). Состояние "занято / не принято" в предыдущих ветвях на пути выполнения используется в качестве индекса в таблице прогнозов. Это в основном решает проблему предсказания ветвления интерпретатора, позволяя ему делать удивительно хорошую работу, особенно когда интерпретируемый код (код R в вашем случае) повторяет одно и то же.
Взятие if()
* * приводит к необходимости делатьразличные операции, поэтому делает на самом деле все же делает некоторые переходы в интерпретаторе R более или менее предсказуемыми в зависимости от данных. Но, конечно, как интерпретатор, он делает много больше работына каждом шаге, чем простой цикл машинного кода над массивом.
Таким образом, дополнительные ошибочные прогнозы веток составляют гораздо меньшую долю общего времени из-за издержек интерпретатора.
Конечно, оба ваших теста выполняются с одним и тем же интерпретатором на одном и том же оборудовании. Я не знаю, какой у вас процессор.
Если Intel старше, чем Haswell илиAMD старше, чем Zen, вы можете получить много неверных прогнозов даже с отсортированным массивом, если шаблон не достаточно прост для косвенного предиктора истории ветвления, чтобы на него можно было привязаться. Это скрыло бы разницу в большем количестве шума.
Поскольку вы видите довольно четкую разницу, я предполагаю, что процессор не слишком сильно ошибается в сортированном случае, поэтому есть место для негохуже в несортированном случае.