По-видимому, MSVС++ 2017 toolset v141 (конфигурация релиза x64) не использует инструкцию сборки FYL2X x86_64 с помощью встроенного C/С++, но вместо того, чтобы использовать С++ log() или log2(), возникает реальный вызов которая, по-видимому, реализует приближение логарифма (без использования FYL2X). Производительность, которую я измерил, также странная: log() (натуральный логарифм) в 1.7667 раз быстрее, чем log2() (логарифм базы 2), хотя логарифм базы 2 должен быть проще для процессора, поскольку он хранит экспоненту в двоичном формате (и мантисса тоже), и, похоже, почему команда CPU FYL2X вычисляет логарифм базы 2 (умноженный на параметр).
Вот код, используемый для измерений:
#include <chrono>
#include <cmath>
#include <cstdio>
const int64_t cnLogs = 100 * 1000 * 1000;
void BenchmarkLog2() {
double sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for(int64_t i=1; i<=cnLogs; i++) {
sum += std::log2(double(i));
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
double nSec = 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
printf("Log2: %.3lf Ops/sec calculated %.3lf\n", cnLogs / nSec, sum);
}
void BenchmarkLn() {
double sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for (int64_t i = 1; i <= cnLogs; i++) {
sum += std::log(double(i));
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
double nSec = 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
printf("Ln: %.3lf Ops/sec calculated %.3lf\n", cnLogs / nSec, sum);
}
int main() {
BenchmarkLog2();
BenchmarkLn();
return 0;
}
Выход для Ryzen 1800X:
Log2: 95152910.728 Ops/sec calculated 2513272986.435
Ln: 168109607.464 Ops/sec calculated 1742068084.525
Чтобы разъяснить эти явления (без использования FYL2X и странной разницы в производительности), я также хотел бы проверить производительность FYL2X, а если быстрее, используйте его вместо функций <cmath>. MSVС++ не разрешает встроенную сборку на x64, поэтому необходима функция файла сборки, которая использует FYL2X.
Не могли бы вы ответить на ассемблерный код для такой функции, которая использует FYL2X или лучшую инструкцию, выполняющую логарифм (без необходимости конкретной базы), если есть какие-либо новые процессоры x86_64?