unicode collat​​ion NIF运行速度比Pure Erlang实现慢

时间:2016-01-01 14:47:41

标签: c erlang erlang-nif

我试图通过将其重写为NIF实现来优化现有的unicode整理库(用Erlang编写)。主要原因是因为整理是CPU密集型操作。

实施链接:https://github.com/abhi-bit/merger

通过基于Pure Erlang的优先级队列对1M行进行Unicode排序:

erlc *.erl; ERL_LIBS="..:$ERL_LIBS" erl -noshell -s perf_merger main 1000000 -s init stop
Queue size: 1000000
15871.965 ms

通过基于NIF的二进制堆对1M行进行Unicode排序:

eprof

这很不寻常,我预计它可能会快10倍。

我开启了fprof / eprof,但在NIF模块方面它们并没有多大用处,下面是FUNCTION CALLS % TIME [uS / CALLS] -------- ----- --- ---- [----------] merger:new/0 1 0.00 0 [ 0.00] merger:new/2 1 0.00 0 [ 0.00] merger:size/1 100002 0.31 19928 [ 0.20] merger:in/3 100000 3.29 210620 [ 2.11] erlang:put/2 2000000 6.63 424292 [ 0.21] merger:out/1 100000 14.35 918834 [ 9.19] 关于突出功能的说法

$ make
gcc -I/usr/local/Cellar/icu4c/55.1/include  -L/usr/local/Cellar/icu4c/55.1/lib  min_heap.c collate_json.c kway_merge.c kway_merge_test.c -o output -licui18n -licuuc -licudata
./output
Merging 1 arrays each of size 1000000
mergeKArrays took 84.626ms

我确定,NIF的实现可以更快,因为我使用动态数组实现了基于二进制堆的unicode整理的纯C实现,并且速度要快得多。

perf top

我在这里遇到的具体问题:

  • 由于Erlang< - >而预计会减速多少? NIF模块中的C通信?在这种情况下,纯C和NIF实现之间的减速可能是30倍或更多
  • 哪些工具可用于调试与NIF相关的减速(如本例所示)?我尝试使用System.ApplicationException: Tried to apply event with sequence number 180 to aggregate root with ID 55b43b9e-cd9a-4db9-9b86-78feb7043051 with current sequence number 15. Expected an event with sequence number 16.查看函数调用,顶部的(显示一些十六进制地址)来自" beam.smp"。
  • 我应该考虑优化NIF的哪些方面?例如:我听说人们应该保持数据在Erlang和C之间传输,反之亦然,是否需要考虑更多这样的领域?

1 个答案:

答案 0 :(得分:3)

呼叫NIF的开销很小。当Erlang运行时加载一个加载NIF的模块时,它会用模拟器指令修补模块的波束代码以调用NIF。在调用实现NIF的C函数之前,指令本身只执行少量设置。这不是造成性能问题的区域。

分析NIF与分析任何其他C / C ++代码非常相似。从您的Makefile判断,您似乎正在OS X上开发此代码。在该平台上,假设您已安装XCode,您可以将Instruments application与CPU Samples工具一起使用,以查看代码花费最多的位置它的时间。在Linux上,您可以使用callgrind tool of valgrindErlang emulator built with valgrind support来衡量代码。

例如,如果您在代码中使用这些工具,那么您会发现perf_merger:main/1大部分时间都花在merger_nif_heap_get上,而这会花费相当多的时间在CollateJSON。该函数似乎调用了convertUTF8toUCharcreateStringFromJSON。你的NIF似乎也执行了大量的内存分配。这些是您应该关注的领域,以加快您的代码。