У нас есть решатель CFD, и при запуске симуляции на некоторых машинах было обнаружено, что на некоторых машинах необычайно медленный, но не другие. Используя Intel VTune, было обнаружено, что следующая строка была проблемой (в Fortran):
RHOV= RHO_INF*((1.0_wp - COEFF*EXP(F0)))**(1.0_wp/(GAMM - 1.0_wp))
Свернув в VTune, проблема была связана с конвейером call pow
, и при трассировке стека она показала, что использует __slowpow()
. После некоторого поиска на этой странице появилось жалобы на то же самое.
На машине с версией libc версии 2.12 симуляция заняла 18 секунд. На машине с версией libc версии 2.14 симуляция заняла 0 секунд.
Основываясь на информации на вышеупомянутой странице, проблема возникает, когда база pow()
близка к 1.0. Итак, мы сделали еще один простой тест, в котором мы масштабировали базу на произвольное число до pow()
, а затем делили на число, поднятое до экспоненты после вызова pow()
. Это снизило время выполнения с 18 секунд до 0 секунд с помощью libc 2.12.
Однако нецелесообразно поместить все это в код, где мы делаем a**b
. Как можно было бы заменить функцию pow()
в libc? Например, я хотел бы, чтобы сборная строка call pow
, сгенерированная компилятором Fortran, вызывала пользовательскую функцию pow()
, которую мы пишем, которая выполняет масштабирование, вызывает libc pow()
, а затем делит на масштабирование. Как создать прозрачный для компилятора промежуточный уровень?
Edit
Чтобы уточнить, мы ищем что-то вроде (псевдокода):
double pow(a,b) {
a *= 5.0
tmp = pow_from_libc(a,b)
return tmp/pow_from_libc(5.0, b)
}
Можно ли загрузить pow
из libc и переименовать его в нашей пользовательской функции, чтобы избежать конфликтов имен? Если файл customPow.o
может переименовать pow
из libc, что произойдет, если libc по-прежнему необходим для других вещей? Это вызовет конфликт имен между pow
в customPow.o
и pow
в libc?