Bash

如何防止這種“重放記憶體”行為?

  • December 1, 2016

我有這個 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 5shell 腳本中的行,我們會看到以下結果:

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 5ing,因為受記憶體影響的時間並不代表每次都是冷啟動。

正如我的評論:

可能會在每次呼叫之前嘗試“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

引用自:https://unix.stackexchange.com/questions/327338