JLBH – Java延迟基准线束介绍
在這篇文章中:
- 什么是JLBH
- 我們為什么寫JLBH
- JMH和JLBH之間的區別
- 快速入門指南
什么是JLBH?
JLBH是可用于測量Java程序中的延遲的工具。 它具有以下功能:
- 旨在運行比微型基準測試更大的代碼。
- 適用于使用異步活動(如生產者使用者模式)的程序。
- 能夠對計劃中的各個點進行基準測試
- 能夠將吞吐量調整為基準
- 調整協調遺漏,即,如果迭代的端到端延遲相互影響,則會相互影響
- 報告并運行自己的抖動線程
為什么我們寫JLBH?
之所以寫JLBH是因為我們需要一種基準測試Chronicle-FIX的方法。 我們創建它是為了對軟件中的問題進行基準測試和診斷。 事實證明,它非常有用,現在可以在Chronicle開源庫中使用。
Chronicle-FIX是一種超低延遲Java修復引擎。 例如,它保證了延遲,即將NewOrderSingle消息解析到對象模型中的過程不會超過6us,直到第99.9個百分點。 實際上,我們需要一直沿百分位數范圍進行測量。
這是延遲/百分位數典型配置文件。
50 ? ? -> 1.5us90 ? ? -> 2us99 ? ? -> 2us99.9 ? -> 6us99.99 ?-> 12us99.999 -> 35usWorst ?-> 500usChronicle Fix通過各種吞吐量(從10k消息/秒到100k消息/秒)保證了這些延遲。 因此,我們需要一個測試工具,可以輕松地改變吞吐量。
我們還需要考慮協調遺漏。 換句話說,我們不能僅僅忽略慢速運行對后續運行的影響。 如果運行A慢且導致運行B延遲,即使運行B在自己的運行中沒有任何延遲,則仍必須記錄該延遲的事實。
我們需要嘗試區分OS抖動,JVM抖動和由我們自己的代碼引起的抖動。 因此,我們添加了一個具有抖動線程的選項,該線程除了在JVM中采樣抖動外什么也不做。 這將顯示OS抖動的組合,例如線程調度和常規OS中斷以及全局JVM事件(例如GC暫停)。
我們需要將延遲最好地分配給單個例程甚至代碼行,因此我們還創造了將自定義采樣添加到程序中的可能性。 NanoSamplers的添加幾乎沒有增加基準測試的開銷,并且使您可以觀察程序在哪里引入延遲。
這是我們用來測量Chronicle-FIX的基準的示意圖。
我們最終得到如下結果:
這是典型的運行:
Run time: 100.001s Correcting for co-ordinated:true Target throughput:50000/s = 1 message every 20us End to End: (5,000,000)? ? ? ? ? ? ? ? ? ? ? ? ?50/90 99/99.9 99.99/99.999 - worst was 11 / 15? 17 / 20? 121 / 385 - 541 Acceptor:1 init2AcceptNetwork (4,998,804)? ? ? ?50/90 99/99.9 99.99/99.999 - worst was 9.0 / 13? 15 / 17? 21 / 96 - 541 Acceptor:1.1 init2AcceptorNetwork(M) (1,196)? ? 50/90 99/99.9 99.99 - worst was 22 / 113? 385 / 401? 401 - 401 Acceptor:2 socket->parse (4,998,875)? ? ? ? ? ? 50/90 99/99.9 99.99/99.999 - worst was 0.078 / 0.090? 0.11 / 0.17? 1.8 / 2.1 - 13 Acceptor:2.0 remaining after read (20,649,126)? 50/90 99/99.9 99.99/99.999 99.9999/worst was 0.001 / 0.001? 0.001 / 0.001? 0.001 / 1,800? 3,600 / 4,590 Acceptor:2.1 parse initial (5,000,100)? ? ? ? ? 50/90 99/99.9 99.99/99.999 - worst was 0.057 / 0.061? 0.074 / 0.094? 1.0 / 1.9 - 4.7 Acceptor:2.5 write To Queue (5,000,100)? ? ? ? ?50/90 99/99.9 99.99/99.999 - worst was 0.39 / 0.49? 0.69 / 2.1? 2.5 / 3.4 - 418 Acceptor:2.9 end of inital parse (5,000,000)? ? 50/90 99/99.9 99.99/99.999 - worst was 0.17 / 0.20? 0.22 / 0.91? 2.0 / 2.2 - 7.6 Acceptor:2.95 on mid (5,000,000)? ? ? ? ? ? ? ? 50/90 99/99.9 99.99/99.999 - worst was 0.086 / 0.10? 0.11 / 0.13? 1.4 / 2.0 - 84 Acceptor:3 parse NOS (5,000,000)? ? ? ? ? ? ? ? 50/90 99/99.9 99.99/99.999 - worst was 0.33 / 0.38? 0.41 / 2.0? 2.2 / 2.6 - 5.5 Acceptor:3.5 total parse (5,000,000)? ? ? ? ? ? 50/90 99/99.9 99.99/99.999 - worst was 1.1 / 1.2? 1.8 / 3.0? 3.5 / 5.8 - 418 Acceptor:3.6 time on server (4,998,804)? ? ? ? ?50/90 99/99.9 99.99/99.999 - worst was 1.1 / 1.2? 1.8 / 3.1? 3.8 / 6.0 - 418 Acceptor:4 NOS processed (5,000,000)? ? ? ? ? ? 50/90 99/99.9 99.99/99.999 - worst was 0.21 / 0.23? 0.34 / 1.9? 2.1 / 2.8 - 121 Jitter (5,000,000)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 50/90 99/99.9 99.99/99.999 - worst was 0.035 / 0.035? 0.035 / 0.037? 0.75 / 1.1 - 3.3 OS Jitter (108,141)? ? ? ? ? ? ? ? ? ? ? ? ? ? ?50/90 99/99.9 99.99 - worst was 1.2 / 1.4? 2.5 / 4.5? 209 - 217在基準測試結束時匯總了所有樣本的所有樣本,這里有幾個:
-------------------------------- SUMMARY (Acceptor:2.95 on mid)---------------------- Percentile ? ? run1 ? ? ?run2 ? ? ?run3 ? run4? ? ? ? ?run5 ? ? % Variation var(log) 50: ? ? ? ? ? 0.09 ? ? ?0.09 ? ? ?0.09 ? ?0.09? ? ? ? ?0.09? ? ? ? ?0.00? ? ? ? 3.32 90: ? ? ? ? ? 0.10 ? ? ?0.10 ? ? ?0.10 ? ?0.10? ? ? ? ?0.10? ? ? ? ?0.00? ? ? ? 3.58 99: ? ? ? ? ? 0.11 ? ? ?0.11 ? ? ?0.11 ? ?0.11? ? ? ? ?0.11? ? ? ? ?2.45? ? ? ? 3.69 99.9: ? ? ? ? 0.13 ? ? ?0.13 ? ? ?0.62 ? ?0.78? ? ? ? ?0.13? ? ? ? 76.71? ? ? ? 6.01 99.99: ? ? ? ?1.50 ? ? ?1.38 ? ? ?1.82 ? ?1.89? ? ? ? ?1.70? ? ? ? 19.88? ? ? ? 9.30 worst: ? ? ? ?1.95 ? ? ?2.02 ? ? ?2.11 ? ?2.24? ? ? ? ?2.24? ? ? ? ?6.90? ? ? ? 9.90 ------------------------------------------------------------------------------------- -------------------------------- SUMMARY (Acceptor:3 parse NOS)---------------------- Percentile? ?run1 ? run2 ? ?run3 ? ?run4? ? ? ? ?run5? ? ? % Variation? ?var(log) 50: ? ? ? ? ?0.33 ? 0.33 ? ?0.34 ? ?0.36? ? ? ? ?0.36? ? ? ? ?6.11? ? ? ? 5.75 90: ? ? ? ? ?0.38 ? 0.38 ? ?0.46 ? ?0.46? ? ? ? ?0.46? ? ? ? 12.42? ? ? ? 6.24 99: ? ? ? ? ?0.41 ? 0.41 ? ?0.50 ? ?0.53? ? ? ? ?0.50? ? ? ? 16.39? ? ? ? 6.47 99.9: ? ? ? ?2.11 ? 2.02 ? ?2.11 ? ?2.11? ? ? ? ?2.11? ? ? ? ?3.08? ? ? ? 9.76 99.99: ? ? ? 2.37 ? 2.24 ? ?2.37 ? ?2.37? ? ? ? ?2.37? ? ? ? ?3.67? ? ? ?10.05 worst: ? ? ? 2.88 ? 2.62 ? ?3.14 ? ?3.14? ? ? ? ?2.88? ? ? ? 11.51? ? ? ?10.67-------------------------------------------------------------------------------------使用JLBH,我們既可以根據規范中的標準對我們的應用程序進行基準測試,也可以診斷一些延遲峰值。
通過改變基準測試的吞吐量和運行時間,尤其是通過向代碼模式中的各個點添加采樣開始出現,這導致了延遲源。 一個特殊的例子是DateTimeFormatter出現了一個TLB緩存未命中的問題,但這將是另一篇文章的主題。
JMH和JLBH之間的區別
我希望閱讀本文的大多數人都熟悉JMH (Java MicroBenchmarking Harness),這是用于微基準測試的出色工具,如果您尚未使用過,它是每個Java開發人員都應該在自己的儲物柜中擁有的有價值的工具。 特別是那些與測量延遲有關的人。
正如您將從JLBH設計中看到的那樣,其中許多設計都是受JMH啟發的。
因此,如果JMH如此出色,為什么我們必須創建另一個基準測試工具?
我想從高層次上來說答案就是名字。 J M H直接針對微型基準測試,而JLBH則在大型程序中尋找延遲。
不僅如此。 在閱讀了最后一節之后,您會發現出于某些問題,您可能出于多種原因而選擇JLBH而不是JMH。
順便說一句,盡管您始終可以使用JLBH而不是JMH,但是如果您有一個真正的微型基準,并且希望盡可能干凈地,準確地進行測量,我總是建議您使用JMH而不是JLBH。 JMH是一個非常復雜的工具,它確實做得很好,例如,JMH每次運行都會派生JVM,而JLBH目前還不支持。
在JMH上使用JLBH時:
- 如果要查看您的代碼在上下文中運行。 JMH的本質是對代碼進行非常小的采樣,例如,在FIX引擎的情況下,僅進行解析,然后將其隔離計時。 在我們的測試中,在上下文環境中(即作為修復引擎的一部分)進行完全相同的修復解析所花費的時間是在上下文環境中(即在微基準測試中)進行時所花費的時間的兩倍。 在我的“延遲”示例項目DateSerialise中,我有一個很好的例子,其中演示了序列化Date對象在TCP調用中運行時所花費的時間可能是原來的兩倍。 其原因全與CPU緩存有關,我們將在以后的博客中再次討論。
- 如果要考慮協調遺漏。 在JMH中,根據設計,所有迭代都是相互獨立的,因此,如果代碼的一個迭代緩慢,則不會對下一個迭代產生影響。 在我的Latency示例SimpleSpike中,我們可以看到一個很好的例子,在該例子中,我們看到了協調遺漏的巨大影響。 考慮到協調的遺漏時,幾乎總是應該對現實世界中的示例進行衡量。
例如,假設您正在等待火車,但由于前面的火車晚了,因此在車站延遲了一個小時。 讓我們想象一下,您晚點一個小時上火車,而火車通常需要半個小時才能到達目的地。 如果您沒有考慮到協調遺漏,即使您在出發前在車站等了一個小時,您的旅程也花費了正確的時間,因此您不會認為自己遭受了任何延誤! - 如果要在測試中改變吞吐量 。 JLBH允許您將吞吐量設置為基準測試的參數。 事實是,沒有定義的吞吐量,延遲幾乎沒有意義,因此,能夠在延遲配置文件上查看更改吞吐量的結果非常重要。 JMH不允許您設置吞吐量。 (實際上,這與JMH沒有考慮到協調的遺漏是相輔相成的。)
- 您希望能夠對代碼中的各個點進行采樣。 端到端延遲是一個很好的起點,但那又如何呢? 您需要能夠記錄代碼中許多點的延遲配置文件。 使用JLBH,您可以在程序中花費很少的開銷將探針添加到代碼中的任何位置。 JMH的設計使您只能從方法開始(@Benchmark)到結束進行測量。
- 您要測量OS和JVM的全局延遲。 JLBH運行一個單獨的抖動線程。 這與您的程序并行運行,除了通過重復調用System.nanoTime()來采樣延遲外,什么也沒有做。 盡管這本身并不能告訴您太多信息,但這可以表明基準測試期間JVM的運行情況。 另外,您可以添加一個不執行任何操作的探針(稍后將對此進行說明),您可以在其中運行運行基準測試的代碼的線程中采樣延遲。 JMH沒有這種功能。
如前所述,如果您不想使用這些功能中的一項或多項,而不是JMH而不是JLBH。
快速入門指南
可以在Chronicle-Core庫中找到JLBH的代碼,該庫可以在GitHub上的此處找到。
要從Maven-Central下載,請將其包含在pom.xml中(檢查最新版本):
<dependency><groupId>net.openhft</groupId><artifactId>chronicle-core</artifactId><version>1.4.7</version></dependency>要編寫基準,您必須實現JLBHTask接口:
它只有兩種方法需要實現:
- init(JLBH jlbh)傳遞了對JLBH的引用,您需要在基準測試完成后回調(jlbh.sampleNanos())。
- 運行(long startTime)在每次迭代上運行的代碼。 在確定基準測試已花費了多長時間后,您需要保留開始時間,并回調jlbh.sampleNanos()。 JLBH計算sampleNanos()的調用次數,它必須與run()的調用次數完全匹配。 對于您可以創建的其他探針,情況并非如此。
- 第三種可選方法complete()可能對某些基準的清理有用。
所有這些最好在一個簡單的示例中看到:
在這種情況下,我們測量將項目放到ArrayBlockingQueue上并再次取下需要多長時間。
我們添加探針以查看對put()和poll()的調用花費了多長時間。
我鼓勵您運行此操作,以改變吞吐量和ArrayBlockingQueue的大小,并查看其區別。
如果將accountForCoordinatedOmission設置為true或false,您也可以看到它的區別。
package org.latency.prodcon;import net.openhft.chronicle.core.jlbh.JLBH; import net.openhft.chronicle.core.jlbh.JLBHOptions; import net.openhft.chronicle.core.jlbh.JLBHTask; import net.openhft.chronicle.core.util.NanoSampler;import java.util.concurrent.*;/*** Simple test to demonstrate how to use JLBH*/ public class ProducerConsumerJLBHTask implements JLBHTask {private final BlockingQueue<Long> queue = new ArrayBlockingQueue(2);private NanoSampler putSampler;private NanoSampler pollSampler;private volatile boolean completed;public static void main(String[] args){//Create the JLBH options you require for the benchmarkJLBHOptions lth = new JLBHOptions().warmUpIterations(40_000).iterations(100_000).throughput(40_000).runs(3).recordOSJitter(true).accountForCoordinatedOmmission(true).jlbhTask(new ProducerConsumerJLBHTask());new JLBH(lth).start();}@Overridepublic void run(long startTimeNS) {try {long putSamplerStart = System.nanoTime();queue.put(startTimeNS);putSampler.sampleNanos(System.nanoTime() - putSamplerStart);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void init(JLBH lth) {putSampler = lth.addProbe("put operation");pollSampler = lth.addProbe("poll operation");ExecutorService executorService = Executors.newSingleThreadExecutor();executorService.submit(()->{while(!completed) {long pollSamplerStart = System.nanoTime();Long iterationStart = queue.poll(1, TimeUnit.SECONDS);pollSampler.sampleNanos(System.nanoTime() - pollSamplerStart);//call back JLBH to signify that the iteration has ended lth.sample(System.nanoTime() - iterationStart);}return null;});executorService.shutdown();}@Overridepublic void complete(){completed = true;} }看一下JLBHOptions中包含的所有可用來設置JLBH基準的選項 。
在下一篇文章中,我們將查看JLBH基準的更多示例。
如果您對JLBH有任何反饋,請讓我知道–如果您想貢獻自己的力量來編錄Chronicle-Core并發出拉取請求!
翻譯自: https://www.javacodegeeks.com/2016/04/jlbh-introducing-java-latency-benchmarking-harness.html
總結
以上是生活随笔為你收集整理的JLBH – Java延迟基准线束介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gta5电脑内存不足(电脑下gta5存储
- 下一篇: extjs6 mvvm_ZK 6中的MV