Bash
如何防止這種“重放記憶體”行為?
我有這個 C89 小程序——它的作用、工作原理以及未定義的行為並不重要,只是它只在一個執行緒上執行一些長時間的記憶體和數學運算:
x, c, * b, m, t, i, a; g (n) { for (b = malloc(0); c < n; b[c - 1] = x++, t = 1) { char s[9]; for (i = m = 0; i < sprintf(s, "%d", x); m += a, t *= a) a = s[i++] - 48; b = m * t ? x % m + x % t ? b : realloc(b, 4 * ++c) : b; } return b[c - 1]; } main (j) { printf("%d\n", g(--j)); }
像這樣編譯它:
gcc -std=c89 tt.c -o tt -O3
.然後,如果我使用 shell 腳本循環執行它,以了解它的執行時間:
#!/bin/bash echo "using input $1" for _ in `seq 1 10`; do ( time ./tt $(seq 1 $1) ) 3>&1 1>/dev/null 2>&3 \ | grep real \ | cut -f2 # sleep 5 done
我看到這樣的輸出:
$ ./tt.sh 50 using input 50 0m0.016s 0m0.008s 0m0.008s 0m0.007s 0m0.007s 0m0.007s 0m0.008s 0m0.008s 0m0.007s 0m0.007s
或者像這樣:
$ ./tt.sh 34 using input 34 0m0.007s 0m0.004s 0m0.004s 0m0.004s 0m0.005s 0m0.004s 0m0.003s 0m0.003s 0m0.003s 0m0.004s
在第一次呼叫之後,程序執行時會有一個初始加速
real
,然後所有後續呼叫都以這個假加速執行。如果我取消註釋
# sleep 5
shell 腳本中的行,我們會看到以下結果:using input 50 0m0.008s 0m0.020s 0m0.018s 0m0.012s 0m0.009s 0m0.006s 0m0.013s 0m0.012s 0m0.009s 0m0.012s using input 34 0m0.006s 0m0.007s 0m0.004s 0m0.007s 0m0.008s 0m0.003s 0m0.004s 0m0.004s 0m0.005s 0m0.007s
時間看起來更符合預期和更準確,其中的差異必須歸因於那一刻處理器的隨機狀態(即它們是小的自然變化)。
如果我想獲得我的程序的平均執行時間,我應該對這些數字進行平均,但是
sleep 5
在每次呼叫之間,雖然這是我能找到停止這種行為的唯一方法,但 10 次測試而不是幾個測試加起來是 50 秒20 次測試的秒數。我以前在單執行緒程序中看到過這種“重放記憶體”行為,這些程序一遍又一遍地執行長操作(緊密循環),我知道在 99.9% 的情況下它是可取的。
假設這不是某些 Intel Magic™ 在硬體級別的結果,這是 Linux 核心或 Bash 故意在做的事情,我怎樣才能讓它停止?
我希望我的程序具有可重現的執行時,包括從“冷啟動”載入庫和分頁,而不需要
sleep 5
ing,因為受記憶體影響的時間並不代表每次都是冷啟動。
正如我的評論:
可能會在每次呼叫之前嘗試“echo 3 > /proc/sys/vm/drop_caches”
tt
提問者的回答:
是的,迴聲 1 | sudo tee /proc/sys/vm/drop_caches 完全符合我的要求(回顯 3 會產生奇怪的結果)。你應該把它作為答案
To free pagecache: echo 1 > /proc/sys/vm/drop_caches To free reclaimable slab objects (includes dentries and inodes): echo 2 > /proc/sys/vm/drop_caches To free slab objects and pagecache: echo 3 > /proc/sys/vm/drop_caches