Установить точку останова на __scalbn
. Запустите вашу программу. Посмотрите на след (в GDB, bt
) . Дерево вызовов покажет, что exp()
является родительской функцией для __scalbn
.
Если функция имеет несколько вызывающих, первое попадание может не быть из "горячей" функции, которую вы профилируете.
Чтобы узнать, какая функция высшего уровня (включая ее дочерние элементы) отвечает за использование большого количества времени, см. linux perf: как интерпретировать и находить горячие точки . При нисходящем профилировании можно найти дорогие функции, которые выполняют всю свою работу при вызове других функций, даже если эти другие функции также имеют «невинных» вызывающих. (Например, memcpy
интенсивно используется и часто неизбежен, но вы хотели бы найти вызывающих абонентов, которые используют его слишком часто и могут быть оптимизированы лучше. Или вообще не вызваны.)
И, кстати, да, математическая реализация glibc lib exp()
внутренне использует __scalbn
. Я не уверен, насколько плоха реализация, но я не вижу версию asm для x86-64, только эту версию на чистом C. https://code.woboq.org/userspace/glibc/sysdeps/ieee754/dbl-64/wordsize-64/s_scalbn.c.html. (Для __scalbnl(long double)
есть https://code.woboq.org/userspace/glibc/sysdeps/x86_64/fpu/s_scalbnl.S.html, с использованием инструкции x87 fscale
для 80-разрядных операций с плавающей запятой. Но есть только файлы as38 i386 для других размеров. И IA-64 (Itanium) , но не x86-64).
glibc имеет некоторый векторизованный EXP-код, хотя, как и в SSE4 SVML-версии https://code.woboq.org/userspace/glibc/sysdeps/x86_64/fpu/multiarch/svml_d_exp2_core_sse4.S.html#_ZGVbN2v_exp_sse4.
Если вам нужна более высокая производительность exp()
без идеальной точности, см. Самая быстрая реализация экспоненциальной функции с использованием AVX (это для float
, а не double
. Я забываю, если есть ответ SO с двойная версия).
Также связано: Эффективная реализация log2 (__m256d) в AVX2 .