測試環境準備
- 運行前,通過echo 1 > /proc/sys/vm/drop_caches清理IO cache
- 運行前,通過iostat -x -p {dev} 1確認沒有其它IO影響結果
- sysbench參數
<code>sysbench --test=fileio --num-threads=$SYSBENCH_NUM_THREADS --file-num=$SYSBENCH_FILE_NUM --file-block-size=$SYSBENCH_BLOCK_SIZE --file-total-size=$SYSBENCH_FILE_TOTAL_SIZE --file-test-mode=$1 --file-io-mode=sync --file-extra-flags=$DIRECT --file-fsync-all=$FSYNC --file-fsync-mode=fsync --file-fsync-freq=0 --file-merged-requests=0 --max-time=$SYSBENCH_TIME --max-requests=0/<code>
其中的變量參數
<code>binlog 異常暴漲分析SYSBENCH_FILE_TOTAL_SIZE=16G SYSBENCH_FILE_NUM=16 SYSBENCH_NUM_THREADS=16 DIRECT= FSYNC=off SYSBENCH_BLOCK_SIZE=4096 SYSBENCH_TIME=60/<code>
附件中的run_sysbench.sh是運行sysbench的腳本,每個實驗的輸出都附在附件中,樣例輸出:
現象1
步驟1
1.非Direct I/O模式,測試順序寫
<code>./run_sysbench.sh seqrewr run | tee 1_sysbench_seqrewr/<code>
2.非Direct I/O模式測試隨機寫
<code>./run_sysbench.sh rndwr run | tee 2_sysbench_rndwr/<code>
3.Direct I/O模式,測試順序寫(seqrewr)
<code>DIRECT=1 ./run_sysbench.sh seqrewr run | tee 3_sysbench_direct_seqrewr/<code>
4.Direct I/O模式,測試隨機寫(rndwr)
<code>DIRECT=1 ./run_sysbench.sh rndwr run | tee 4_sysbench_direct_rndwr/<code>
結果1
對於磁盤的I/O測試,直覺上順序寫比隨機寫要快很多。從測試結果可以看到:
- 在Direct I/O模式下,與直覺結果相符
- 在非Direct I/O模式下,隨機寫比順序寫IOPS快4倍, 吞吐與IOPS成正比。這一點是違反直覺的
對結果的分析將集中在非Direct I/O模式下。
分析1
我們一時間對上述結果沒有任何頭緒,也不大可能是意外發明瞭隨機寫更快的磁盤. 先嚐試觀察對磁盤的IO壓力分佈:
<code>iostat -x -p /dev/sdb 1/<code>
觀察到在sysbench結束後,順序寫的I/O壓力為0,但隨機寫的I/O壓力仍將持續一些時間。隨即懷疑sysbench在順序寫時用fsync進行刷盤,並等待刷盤結束。在等待期間沒有sysbench不發出新的IO請求,自然IOPS會降低。但sysbench參數中已經設置了--file-fsync-all=off,與現象衝突。
用strace確認這一結論:
<code>strace -e trace=fsync -f ./run_sysbench.sh seqrewr run 2>&1 | tee 5_strace_sysbench_seqrewr/<code>
可以看到顯式的fsync調用。
在sysbench源碼中可以找到與FILE_OP_TYPE_FSYNC相關的一段代碼:
<code> if (file_fsync_end && file_req->operation == FILE_OP_TYPE_WRITE && fsynced_file2 < num_files) { file_req->file_id = fsynced_file2; file_req->pos = 0; file_req->size = 0; file_req->operation = FILE_OP_TYPE_FSYNC; fsynced_file2++; }/<code>
意味著這個fsync與sysbench參數file-fsync-end相關。解決方案:1. 設置--file-fsync-end=no2. 在測試中sysbench順序寫 寫完所有文件的時間--max-time, 避免多出的fsync
之後的測試中, 將置--file-fsync-end=no, 並將--max-time設為30, 避免fsync, 且減少測試時間成本。
插曲1
在分析的過程中,實際過程要比上述描述艱辛一些。
觀測工具使用不當帶來測試偏差。
用strace確定是否有fsync調用時,最初用的命令是:
<code>strace -f ./run_sysbench.sh seqrewr run 2>&1 | tee 5_strace_sysbench_seqrewr/<code>
由於缺少了-e trace=fsync參數,strace的成本上升,導致sysbench的性能下降,使得寫完所有文件的時間>--max-time,就沒有發現fsync調用。
這一結果與預期不符,一時陷入僵局。繞了一圈後懷疑和觀測工具相關,雖沒有定位到是因為觀測工具引起的性能下降,但可以嘗試用另一個觀測工具來校準偏差。在此選定的工具是systemtap。
使用另一觀測工具用於校準 — systemtap
Systemtap 提供了極低成本的內核檢測能力,類似於Dtrace,詳細的介紹請找官方文檔。
以檢測fsync調用為例演示systemtap的用法:
- 環境準備請找官方文檔
- 編輯systemtap腳本 6_systemtap_fsync_summary.stp
<code>!/usr/bin/env stap global r probe syscall.fsync { r[pid()] < 1 } probe end { foreach ([pid-] in r) { printf ("pid=%d, fsync=%d times\n", pid, @count(r[pid])) } }/<code>
3.編譯
<code>stap -v -r $(uname -r) -DMAXSKIPPED=100000 -DSTP_NO_OVERLOAD 6_systemtap_fsync_summary.stp -m 6_systemtap_fsync_summary.ko/<code>
systemtap在觀測負荷會顯式影響系統性能時,會”跳過”一些觀測點,這樣不會影響系統性能,可以安全地使用,但會造成結果不準確。-DMAXSKIPPED=100000 -DSTP_NO_OVERLOAD 這兩個參數能systemtap儘量”不計成本”地觀測,但需要警惕其帶來的開銷。後續編譯中默認會使用這兩個參數,但所有結果需要和不使用參數的情況進行對比,來發現並規避其影響。本文不記述對比的過程。
4.使用
<code>staprun -v fsync_summary.ko | tee 6_systemtap_fsync_summary/<code>
輸出如下:
<code>pid=34888, fsync=16 times/<code>
可以看到16個fsync調用,與sysbench配置的線程數一致。即證明之前不當使用strace造成了觀測結果的偏差。
5.說明systemtap可以一鍵運行腳本,但我們用了編譯+運行兩個步驟,原因是systemtap的編譯環境配置比較繁複,因此我們將編譯環境隔離到了一個容器中,而將編譯好的.ko文件放到目標機上運行,目標機只需安裝簡單的依賴就可以運行。避免環境汙染。
覆盤1
回頭重看現象1的分析過程, 有幾點教訓:1.其實sysbench的標準輸出已經給出了問題原因:
<code>... Extra file open flags: 0 16 files, 1Gb each 16Gb total file size Block size 4Kb Calling fsync() at the end of test, Enabled. Using synchronous I/O mode .../<code>
Calling fsync() at the end of test, Enabled.,藏在一堆數字中信息容易被忽略
2.對觀測工具要進行校準
現象2
步驟2
根據現象1的分析,調整sysbench參數:置--file-fsync-end=no,並將--max-time設為30。重新運行非Direct IO模式的順序寫和隨機寫的測試。
1.測試順序寫
<code>SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run | tee 7_sysbench_seqrewr/<code>
2.測試隨機寫
<code>SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run | tee 8_sysbench_rndwr/<code>
結果2
比之前的結果好一些,但觀察仍到兩個異常現象:
1. 現象2的隨機寫效率高於現象1。猜測是因為縮短了--max-time,導致文件系統緩存仍然在預熱過程中,不需等待回刷。之後的分析中將略過這一點,並不影響分析結果。2. 順序寫的效率仍然低於隨機寫。對這個現象完全沒有想法。
分析2.1 – 端到端的延遲分佈
如果對Linux I/O棧比較陌生,可以查看Linux Storage Stack Diagram 做初步瞭解。
由於對”順序寫的效率低於隨機寫”這一現象沒有任何想法,就先測量一下端到端的延遲分佈,即站在vfs層的角度看延遲分佈。
期望是能判斷延遲是否平均,是否由於個別I/O的異常拖慢了整體水平。
還是用到了systemtap腳本,此處略去編譯過程,直接給出腳本和結果。
systemtap腳本2.1
vfs_write_latency.stp
<code>global input_devname="sdb" global io_latency probe vfs.write.return { if (bytes_to_write > 0 && input_devname == devname) { time = gettimeofday_ns() - @entry(gettimeofday_ns()) io_latency < time } } probe end { print (@hist_log(io_latency)) }/<code>
運行2.1
1.測試順序寫
<code>1> staprun -v vfs_write_latency.ko 2>&1 | tee 9_systemtap_vfs_write_latency_seqrewr 2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>
2.測試隨機寫
<code>1> staprun -v vfs_write_latency.ko 2>&1 | tee 10_systemtap_vfs_write_latency_rndwr 2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>
結果2.1
1.順序寫
2.隨機寫
可以看到:1. 存在skipped probes. systemtap認為有一個觀測點影響太大,因此跳過。2. 存在一個非常離譜的異常點:1152921504606846976ns,以至對平均值產生了很大影響。這可能是由於skipped probes引起的。之後的分析將這個異常點去掉。3. 存在兩段峰值:2048~524288ns,2097152~1073741824ns。第二段的命中次數遠低於第一段,但延遲佔有一定比例。由於一時沒有頭緒,先忽略這一現象,留待之後解決。4. 隨機寫比順序寫的低延遲段(4096ns附近)的分佈要多一些。
目前為止沒有進展。下一步試試研究設備層的I/O請求特徵,期望是設備層的I/O請求特徵正常,從而確認問題出在文件系統和IO調度上。
分析2.2 – 設備層的I/O請求特徵
systemtap腳本2.2
運行2.2
1.測試順序寫
<code>1> staprun -v ioblock_request_summary.ko 2>&1 | tee 11_systemtap_ioblock_write_latency_seqrewr 2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>
2.測試隨機寫
<code>1> staprun -v ioblock_request_summary.ko 2>&1 | tee 12_systemtap_ioblock_write_latency_rndwr 2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>
結果2.2
- 測試順序寫 (結果經過縮減)
- 測試隨機寫 (結果經過縮減)rw是讀寫模式,io_size是設備I/O的大小,count是次數,avg_latency是平均延遲。
可以看到:
- 順序寫的設備I/O的大小集中在大於4k的區域,即在之前經過了合併。隨機寫的設備I/O的大小几種在4k,即沒有經過合併. 符合預期
- 從延遲上沒有發現明顯的差異
可以得到的結論是:順序寫和隨機寫的反常的性能差異很大程度來自於文件系統和IO調度。
分析2.3 – 文件系統的緩存命中率
想到問題可能在文件系統,那可能性比較大的是緩存系統的命中率。順序寫的緩存命中率較低,隨機寫的緩存命中率較高,即幾個發往文件系統的隨機寫請求可能寫的是同一個數據塊。猜測隨機寫在文件系統緩存的代價較小,因此性能較好。
下面驗證文件系統的緩存命中率。可以參考Brendan Gregg神的cachestat。不過此處由於只需要對比趨勢而不需要保證絕對值正確,所以可以簡化實現。
systemtap腳本2.3.1
運行2.3.1
1.測試順序寫
<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 13_systemtap_io_cache_hit_ratio_seqrewr 2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>
2.測試隨機寫
<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 14_systemtap_io_cache_hit_ratio_rndwr 2> SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>
結果2.3.1
可以看到, 隨機寫的緩存命中率(1-add_to_page_cache_lru/pagecache_get_page)比順序寫要高。之後的測試,我們增大sysbench文件的總大小到64G,來降低隨機寫的緩存命中率。
運行2.3.2
1.測試順序寫
<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 15_systemtap_io_cache_hit_ratio_64G_seqrewr 2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>
2.測試隨機寫
<code>1> staprun -v io_cache_hit_ratio.ko 2>&1 | tee 16_systemtap_io_cache_hit_ratio_64G_rndwr 2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>
結果2.3.2
可以看到,隨著測試文件增大,隨機寫的緩存命中率下降,性能也隨之下降。寫緩存的命中率是隨機寫和順序寫性能差異的影響因素之一。
分析2.4 – 文件系統的緩存延遲分析
分析2.3的結果是隨機寫和順序寫的性能差不多,但我們仍可以進一步分析緩存的延時:找一個使用緩存的堆棧,逐層做延遲分析,這是個笨拙但有效的方法。
Systemtap本身提供了大量腳本,其中就有一些成熟的函數入口可以直接借用,而不用自己讀Linux源碼分析backtrace,比如對於緩存,找到/usr/share/systemtap/tapset/linux/vfs.stp文件,搜一下cache,就可以找到以下入口點:
<code>probe vfs.add_to_page_cache = kernel.function("add_to_page_cache_locked") !, kernel.function("add_to_page_cache") { ... }/<code>
之後可以通過systemtap打印出add_to_page_cache的調用棧 (在3.19內核中, 實際使用了add_to_page_cache_lru,這個需要查看源碼才能知道此處的變更),此處不詳述,結果如下:
然後觀測這個堆棧中每個函數的延遲,這個過程中需要特別注意如果觀測點過多,那麼對性能結果會有較大影響,以致影響分析的結論。因此每一次觀測後需要對比觀測前後的性能差別,如果差異過大,應調整觀測手段或減小觀測的範圍。
在此我們就假設運氣很好,一次觀測就能命中要害。
systemtap腳本2.4.1
ext4_write_latency.stp
<code>global input_devname="sdb" global latency_ext4_file_write_iter probe kernel.function("ext4_file_write_iter").return { dev = __file_dev($iocb->ki_filp) devname = __find_bdevname(dev, __file_bdev($iocb->ki_filp)) if (devname == input_devname) { latency_ext4_file_write_iter < gettimeofday_ns()-@entry(gettimeofday_ns()) } } global latency___generic_file_write_iter probe kernel.function("__generic_file_write_iter").return { dev = __file_dev($iocb->ki_filp) devname = __find_bdevname(dev, __file_bdev($iocb->ki_filp)) if (devname == input_devname) { latency___generic_file_write_iter < gettimeofday_ns()-@entry(gettimeofday_ns()) } } probe end { printf ("ext4_file_write_iter latency: %d\n", @avg(latency_ext4_file_write_iter)) printf ("__generic_file_write_iter latency: %d\n", @avg(latency___generic_file_write_iter)) }/<code>
運行2.4.1
1.測試順序寫
<code>1> staprun -v ext4_write_latency.ko 2>&1 | tee 17_systemtap_ext4_write_latency_seqrewr 2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>
2.測試隨機寫
<code>1> staprun -v ext4_write_latency.ko 2>&1 | tee 18_systemtap_ext4_write_latency_rndwr 2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>
結果2.4.1
可以看到:1. 順序寫與隨機寫相比,__generic_file_write_iter的開銷明顯減小,符合常識2. 順序寫與隨機寫相比,ext4_file_write_iter在其他方面的開銷佔比明顯增加
分析2.4.1
從結果1得到結論:ext4_file_write_iter在其他方面的開銷佔比明顯增加。至於哪個方面的開銷增加了,得粗看一下源碼(源碼已將不重要的部分略去):
<code>static ssize_t ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { ... /* * Unaligned direct AIO must be serialized; see comment above * In the case of O_APPEND, assume that we must always serialize */ if (o_direct && ...) { ... } mutex_lock(&inode->i_mutex); if (file->f_flags & O_APPEND) ...; /* * If we have encountered a bitmap-format file, the size limit * is smaller than s_maxbytes, which is for extent-mapped files. */ if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { ... } ... if (o_direct) { ... } ret = __generic_file_write_iter(iocb, from); mutex_unlock(&inode->i_mutex); if (ret > 0) { ... } if (o_direct) ...; errout: if (aio_mutex) ...; return ret; }/<code>
源碼已將分支內的部分略去,只留下主幹。可以看到:1. 代碼特別處理了一些情況(比如, Direct I/O,append模式等)2. 主幹上的操作主要是__generic_file_write_iter和鎖inode->i_mutex
因此可以懷疑鎖inode->i_mutex的代價是否過高
systemtap腳本2.4.2
腳本generic_file_write_iter_concurrency.stp用於觀測__generic_file_write_iter的並行度,以此來估算鎖inode->i_mutex的代價。
<code>global input_devname="sdb" global concurrency, max_concurrency probe kernel.function("__generic_file_write_iter") { dev = __file_dev($iocb->ki_filp) devname = __find_bdevname(dev, __file_bdev($iocb->ki_filp)) if (devname == input_devname) { concurrency += 1 max_concurrency < concurrency } } probe kernel.function("__generic_file_write_iter").return { dev = __file_dev($iocb->ki_filp) devname = __find_bdevname(dev, __file_bdev($iocb->ki_filp)) if (devname == input_devname) { concurrency -= 1 } } probe end { printf ("concurrency=%d\n", @max(max_concurrency)) }/<code>
運行2.4.2
1.測試順序寫
<code>1> staprun -v generic_file_write_iter_concurrency.ko 2>&1 | tee 19_systemtap_generic_file_write_iter_concurrency_seqrewr 2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>
2.測試隨機寫
<code>1> staprun -v generic_file_write_iter_concurrency.ko 2>&1 | tee 20_systemtap_generic_file_write_iter_concurrency_rndwr 2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run/<code>
結果2.4.2
可以看到,鎖inode->i_mutex限制了__generic_file_write_iter的併發度。由常識得知,一個文件一般對應一個inode結構 (也可以通過systemtap打印inode地址來確認),也就是說:
- 順序寫的壓力集中在寫一個文件,因此在inode的鎖上產生了競爭
- 隨機寫的壓力比較分散, 因此__generic_file_write_iter的併發度高
- 順序寫的最大併發度為2,而不是1,可能是發生在已寫滿某一文件並要寫下一個文件的瞬間
之後,我們將調整sysbench併發數為1,來拉平順序寫和隨機寫的__generic_file_write_iter併發度,創造公平的測試環境。
步驟2.4.3
根據現象2的分析,本次的測試將調整sysbench併發數為1。此處也可以隨手驗證一下現象2中的generic_file_write_iter的併發度,在兩種情況下都相等,在此不詳述。
1.測試順序寫
<code>SYSBENCH_NUM_THREADS=1 SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run | tee 21_sysbench_1thread_seqrewr/<code>
2.測試隨機寫
<code>SYSBENCH_NUM_THREADS=1 SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh rndwr run | tee 22_sysbench_1thread_rndwr/<code>
結果2.4.3
可以看到,在相對公平的測試條件下,順序寫比隨機寫的性能更好一些。
現象3
在結果2.1中還遺留了一個問題:在研究延遲分佈時出現了兩個峰。在之前的試驗中,如果將一些函數的延遲分佈打印出來,也能觀察到兩個峰。這些函數並不集中在某一個邏輯路徑上,比較分散。因此可能是一個共有的機制導致第二個峰的出現,而不是某個邏輯分支導致。
另外可以嘗試用systemtap腳本進行分析,但幾經嘗試,第二個峰的出現並不規律。
偶爾想到這是否由於發生了OS的進程切換而導致的,有了想法就可以快速驗證一下。
systemtap腳本3
vfs_write_latency_and_context_switch.ko
<code>global input_devname="sdb" global vfs_write_latency global fire probe vfs.write { if (bytes_to_write > 0 && input_devname == devname) { fire[tid()] = 1 } } probe vfs.write.return { if (fire[tid()] == 1) { delete fire[tid()] vfs_write_latency < gettimeofday_ns() - @entry(gettimeofday_ns()) } } global t_switchout, switch_latency probe scheduler.ctxswitch { if (fire[prev_tid] == 1) { t_switchout[prev_tid] = gettimeofday_ns() } if (fire[next_tid] == 1) { switch_latency < gettimeofday_ns() - t_switchout[next_tid] } } probe end { printf ("vfs write latency:\n") print (@hist_log(vfs_write_latency)) printf ("switch latency:\n") print (@hist_log(switch_latency)) }/<code>
運行3
<code>1> staprun -v vfs_write_latency_and_context_switch.ko 2>&1 | tee 23_systemtap_vfs_write_latency_and_context_switch 2> SYSBENCH_FILE_TOTAL_SIZE=64G SYSBENCH_TIME=30 FIX_FSYNC_END=1 ./run_sysbench.sh seqrewr run/<code>
結果3
可以看到:I/O延遲的第二峰值和OS進程切換相關。
覆盤
現在覆盤整個過程:
1.Direct模式的順序寫性能大於隨機寫,但非Direct模式的順序寫性能小於隨機寫
* 分析:查找fsync系統調用* 結果:調整sysbench參數--file-fsync-end=no2. 順序寫性能仍小於隨機寫* 分析2.1:是否有部分異常I/O延遲拖慢了平均值* 結果2.1:沒有進展。延遲存在兩個峰* 分析2.2:設備層的I/O請求特徵* 結果2.2:設備層的I/O請求特徵無異常,確定問題來自文件系統或IO調度* 分析2.3:文件系統的緩存命中率* 結果2.3:緩存命中率影響了性能,通過調大測試文件大小可降低命中率差異,順序寫性能大於隨機寫* 分析2.4:文件系統的緩存延遲分析* 結果2.4:Ext4的鎖inode->i_mutex的影響, 順序寫受到的影響高於隨機寫3. 對延遲分佈的第二個峰與OS進程切換有關
性能分析經驗
- 性能觀測工具的準確性需要校準,要懷疑其正確性
- 注意其他程序對觀測目標的影響
- systemtap 是強大的觀測工具, 其性能開銷低, 有許多現成的腳本供參考
- 有一些結論的得出,比如現象3,不是依靠於邏輯分析,而是猜測-驗證得來,這就要求對相關的技術有所瞭解
- 之所以現象3不通過邏輯分析,是因為沒有找到恰當的觀測手段和分析方法
IO測試經驗
IO測試時,如果要對兩個場景做性能對比,要關注一下幾個維度
- fsync的調用
- 文件系統的緩存命中率
- 文件系統的併發度
- OS上下文切換的頻度
這幾個維度偏差不大, 才能進行性能對比.
比較順序寫和隨機寫的性能,要確定比較目的,常識中”順序寫性能優於隨機寫”的結論,可能適用於設備I/O,但在文件系統上的某些場景下結論並不適用。
注意
所有的測試結果不能用於生產環境,因為測試時間較短,導致一些因素與生產環境不同,比如文件系統緩存是預熱狀態而並不飽和。得出的結論會有所偏頗,此次試驗只是展示一些分析方法。