加快runhaskell

Mat*_*hid 15 haskell ghc

我有一个小的测试框架.它执行一个循环,执行以下操作:

  1. 生成一个小的Haskell源文件.

  2. 执行此操作runhaskell.该程序生成各种磁盘文件.

  3. 处理刚刚生成的磁盘文件.

这种情况发生了几十次.事实证明,这runhaskell占用了程序执行时间的绝大部分.

一方面,runhaskell设法从磁盘加载文件,标记它,解析它,进行依赖性分析,从磁盘加载20KB更多文本,标记并解析所有这些,执行完整类型推断,检查类型,desugar到Core的事实,链接编译的机器代码,并在解释器中执行该事情,所有在2秒的时间内,当你想到它时实际上非常令人印象深刻.另一方面,我仍然希望让它变得更快.;-)

编译测试器(运行上述循环的程序)产生了微小的性能差异.编译脚本链接的20KB库代码产生了相当明显的改进.但是每次调用它仍然需要大约1秒钟runhaskell.

生成的Haskell文件每个只有1KB以上,但实际上只有一部分文件发生了变化.也许编译文件并使用GHC的-e开关会更快?

或者,也许是重复创建和销毁许多操作系统进程的开销,这会减慢这种速度?每次调用都runhaskell可能导致操作系统探索系统搜索路径,找到必要的二进制文件,将其加载到内存中(当然这已经在磁盘缓存中?),将其链接到任何DLL,并将其激活.有没有什么方法可以(轻松地)保持一个GHC运行实例,而不是不断创建和销毁操作系统进程?

最终,我想总有GHC API.但正如我所理解的那样,这种噩梦难以使用,高度无证,并且在GHC的每个小点发布时都容易发生根本变化.我正在尝试执行的任务非常简单,所以我并不想让事情变得更加复杂.

建议?

更新:切换到GHC -e(即,现在编译除正在执行的一个表达式之外的所有内容)没有产生可测量的性能差异.在这一点上似乎很清楚,它是所有操作系统开销.我想知道我是否可以创建一个从测试仪到GHCi的管道,从而只使用一个操作系统进程......

Mat*_*hid 9

好吧,我有一个解决方案:我创建了一个GHCi进程并将其连接stdin到一个管道,以便我可以发送它表达式进行交互式评估.

稍后会有几个相当大的程序重构,整个测试套件现在大约需要8秒才能执行,而不是48秒.这对我有用!:-D

(对于其他任何试图这样做的人:为了爱上帝,记得把-v0开关传递给GHCi,否则你会得到GHCi欢迎横幅!很奇怪,如果你以交互方式运行GHCi,即使-v0命令提示仍然出现,但是当连接到管道时,命令提示符消失;我认为这是一个有用的设计功能而不是随机事故.)


当然,有一半我走这奇怪的路线的原因是,我想捕捉stdoutstderr一个文件.使用RunHaskell,这很容易; 只需在创建子进程时传递适当的选项.但现在所有的测试用例正在由单一的操作系统进程中运行,所以有重定向没有明显的方式stdinstdout.

我想出的解决方案是将所有测试输出定向到一个文件,并且测试之间有GHCi打印出一个魔术字符串(我希望!)不会出现在测试输出中.然后退出GHCi,啜饮文件,并查找魔术字符串,以便我可以将文件剪切成合适的块.