Я заметил значительные накладные расходы, вызывающие функции Haskell на C, намного большие, чем накладные расходы на вызов функции C. Чтобы отделить проблему от ее сути, я написал программу, которая просто инициализирует рабочую среду Haskell, запускает цикл, который вызывает пустую функцию 100 000 000 раз и возвращает.
С помощью встроенной функции программа принимает 0,003 секунды. Вызов пустой функции, написанной на C, занимает 0.18 с. Вызов пустой функции, написанной в Haskell, занимает 15,5 секунд. (Как ни странно, если я компилирую пустой файл Haskell отдельно перед связыванием, это занимает еще несколько секунд. Подзапрос: почему это?)
Итак, похоже, что около 100-кратного замедления между вызовом функции C и вызовом функции Haskell. В чем причина этого, и есть ли способ смягчить это замедление?
Код
EDIT: Я обнаружил версию этого теста в NoFib benchmark suite,
callback002
. Там хороший пост в блоге от Edward Z. Yang упоминает этот тест в контексте планировщика GHC. Я все еще пытаюсь вырвать это сообщение в блоге вместе с Zeta очень приятным ответом. Я еще не убежден, что этого не сделать быстрее!
Чтобы скомпилировать "медленную" версию Haskell, запустите
ghc -no-hs-main -O2 -optc-O3 test.c Test.hs -o test
Чтобы скомпилировать "быструю" версию C, запустите
ghc -no-hs-main -O2 -optc-O3 test.c test2.c TestDummy.hs -o test
test.c:
#include "HsFFI.h"
extern void __stginit_Test(void);
extern void test();
int main(int argc, char *argv[]) {
hs_init(&argc, &argv);
hs_add_root(__stginit_Test);
int i;
for (i = 0; i < 100000000; i++) {
test();
}
hs_exit();
return 0;
}
test2.c:
void test() {
}
Test.hs:
{-# LANGUAGE ForeignFunctionInterface #-}
module Test where
foreign export ccall test :: ()
test :: ()
test = ()
TestDummy.hs:
module Test where