我试图通过将其重写为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
我在这里遇到的具体问题:
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"。答案 0 :(得分:3)
呼叫NIF的开销很小。当Erlang运行时加载一个加载NIF的模块时,它会用模拟器指令修补模块的波束代码以调用NIF。在调用实现NIF的C函数之前,指令本身只执行少量设置。这不是造成性能问题的区域。
分析NIF与分析任何其他C / C ++代码非常相似。从您的Makefile判断,您似乎正在OS X上开发此代码。在该平台上,假设您已安装XCode,您可以将Instruments application与CPU Samples工具一起使用,以查看代码花费最多的位置它的时间。在Linux上,您可以使用callgrind tool of valgrind和Erlang emulator built with valgrind support来衡量代码。
例如,如果您在代码中使用这些工具,那么您会发现perf_merger:main/1
大部分时间都花在merger_nif_heap_get
上,而这会花费相当多的时间在CollateJSON
。该函数似乎调用了convertUTF8toUChar
和createStringFromJSON
。你的NIF似乎也执行了大量的内存分配。这些是您应该关注的领域,以加快您的代码。