我对我的图书馆进行了更改,现在它的速度要慢得多,但我无法弄清楚它花费了多少时间。分析报告没有帮助。请帮我弄清楚原因是什么。
我创建了一个名为Hedis的Redis客户端库,并为其创建了一个基准程序。现在,我对库进行了一些内部更改,以清理架构。这导致性能(按所述基准测量的每秒Redis请求数)下降约2.5倍。
基准测试打开与localhost上的Redis服务器的50个网络连接。两个版本之间的连接处理方式不同:
unsafeInterleaveIO
来处理(我在广泛地描述了我的方法)
blog post here中的笔画。我有点不高兴
与架构,因此我改变了事情Chan
进行通信(在基准测试中运行150个线程)。可能相关的更多信息:
-threaded
)。forkIO
创建所有线程。 不越贵
forkOS
。剖析并没有给我一个明显的理由来说明性能下降。根据分析报告,两个版本在System.IO.hFlush
和Data.ByteString.hGetSome
上花费的时间超过99%。在两个版本中调用hFlush
和hGetSome
的次数相同。由于两种情况下网络流量也相同,因此这些功能不能成为减速的原因。
我可以在两个版本之间衡量的唯一显着差异是time
(Unix实用程序)告诉我的:慢版本(线程数是其三倍)在“sys”中花费的时间明显多于与快速版相比,“用户”。 GHC +RTS -s
标志将此报告为降低了生产力。
以下是具有+RTS -s
标志的两个版本的程序输出:
$ time ./dist/build/hedis-benchmark/hedis-benchmark +RTS -s -p
ping 33305.29 Req/s
get 25802.92 Req/s
mget 18215.94 Req/s
ping (pipelined) 268994.36 Req/s
5,118,163,904 bytes allocated in the heap
185,075,608 bytes copied during GC
4,084,384 bytes maximum residency (39 sample(s))
916,544 bytes maximum slop
10 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 7416 colls, 0 par 0.38s 0.40s 0.0001s 0.0003s
Gen 1 39 colls, 0 par 0.03s 0.03s 0.0007s 0.0009s
INIT time 0.00s ( 0.00s elapsed)
MUT time 7.93s ( 12.34s elapsed)
GC time 0.41s ( 0.43s elapsed)
RP time 0.00s ( 0.00s elapsed)
PROF time 0.00s ( 0.00s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 8.33s ( 12.76s elapsed)
%GC time 4.9% (3.3% elapsed)
Alloc rate 645,587,554 bytes per MUT second
Productivity 95.1% of total user, 62.1% of total elapsed
real 0m12.772s
user 0m8.334s
sys 0m4.424s
$ time ./dist/build/hedis-benchmark/hedis-benchmark +RTS -s -p
ping 11457.83 Req/s
get 11169.64 Req/s
mget 8446.96 Req/s
ping (pipelined) 130114.31 Req/s
6,053,055,680 bytes allocated in the heap
1,184,574,408 bytes copied during GC
9,750,264 bytes maximum residency (198 sample(s))
2,872,280 bytes maximum slop
26 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 9105 colls, 0 par 2.11s 2.14s 0.0002s 0.0006s
Gen 1 198 colls, 0 par 0.23s 0.24s 0.0012s 0.0093s
INIT time 0.00s ( 0.00s elapsed)
MUT time 10.99s ( 27.92s elapsed)
GC time 2.34s ( 2.38s elapsed)
RP time 0.00s ( 0.00s elapsed)
PROF time 0.00s ( 0.00s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 13.33s ( 30.30s elapsed)
%GC time 17.6% (7.8% elapsed)
Alloc rate 550,656,490 bytes per MUT second
Productivity 82.4% of total user, 36.3% of total elapsed
real 0m30.305s
user 0m13.333s
sys 0m16.964s
您是否有任何想法或提示可能会产生额外的时间?
答案 0 :(得分:3)
根据分析报告,大部分时间都花在hFlush
和hGetSome
上。根据{{1}},慢版本需要更多的系统时间。因此,我的假设是,无论是等待更多输入还是锁定和解锁线程,都会花费大量时间来阻止和等待。
这是我要做的第一件事:用time
编译代码,看看会发生什么。线程运行时使用完全不同的IO管理器,我强烈怀疑这一单一更改将解决您的问题。
答案 1 :(得分:2)
我的猜测会与Chan
的开销有关。
我的第一个想法是增加了GC的时间,但这似乎并非如此。所以我的第二个想法是,使用Chan
(在MVar
之上实现)所涉及的所有锁定和解锁都可能是问题所在。但这仍然是一个猜测。
您可以尝试TChan
(即STM),看看是否会产生丝毫差异。 (也许你可以编写一个小骨架来比较两者,看看问题出在哪里,而不是重新实现你的“真实”代码。)
除此之外,我没有想法。