実験環境
- Intel Core i7-7500U CPU @ 2.70 GHz クアッドコア
- メモリ 16GB
- Ubuntu 16.10 yakkety (x86_64, 4.8.0-46-generic)
- GNU bash 4.3.46(1)-release (x86_64-pc-linux-gnu)
- grep (GNU grep) 2.25
- cat (GNU coreutils) 8.25
- go version go1.8 linux/amd64
# 改行があるテキストファイルの場合のログ | |
Size grep a FILE cat FILE | grep a | |
1 1628986.050000 2277017.950000 | |
5 1371493.850000 1866161.350000 | |
10 1330203.100000 1663005.050000 | |
50 1336509.300000 1693194.800000 | |
100 1371718.000000 1811099.450000 | |
500 1456991.150000 1917038.800000 | |
1024 1543473.000000 2094624.000000 | |
5120 2423058.550000 3364557.450000 | |
10240 3218446.000000 4969714.750000 | |
51200 11629891.200000 18146762.950000 | |
102400 22254559.750000 34036223.300000 | |
512000 100217975.550000 160507865.500000 | |
1048576 180088340.850000 320137904.100000 | |
5242880 857794564.150000 1545226725.900000 | |
10485760 2886427989.250000 3202013808.850000 |
# バイナリファイルの場合のログ | |
Size grep a FILE cat FILE | grep a | |
1 1581347.050000 1775962.650000 | |
5 1318343.850000 1761388.000000 | |
10 1200220.150000 1554791.000000 | |
50 1245887.950000 1578335.350000 | |
100 1287939.950000 1702699.150000 | |
500 1524866.950000 1842490.650000 | |
1024 1859444.100000 2228896.900000 | |
5120 3996075.150000 4256021.300000 | |
10240 6442738.800000 6835296.600000 | |
51200 25735508.400000 27734911.800000 | |
102400 50883223.100000 52917631.950000 | |
512000 246976414.400000 265936897.700000 | |
1048576 504907376.700000 565962037.050000 | |
5242880 2521654671.250000 2848791126.000000 | |
10485760 5250627603.900000 5524435772.300000 |
# 改行があるテキストファイルについて、<FILENAME grep a についても同様にベンチマークをとってみたログ | |
Size <FILENAME grep a | |
1 2125799.150000 | |
5 1830172.500000 | |
10 1370422.950000 | |
50 1421713.500000 | |
100 1487108.450000 | |
500 1606865.500000 | |
1024 1631634.950000 | |
5120 2442890.650000 | |
10240 3453758.200000 | |
51200 12332587.350000 | |
102400 20900270.400000 | |
512000 90421090.200000 | |
1048576 194268279.050000 | |
5242880 884363476.950000 | |
10485760 3099899414.700000 |
# 改行が無いテキストファイルの場合のログ | |
Size grep a FILE cat FILE | grep a | |
1 1562107.050000 1911358.450000 | |
5 1435588.650000 2015130.550000 | |
10 1283699.150000 1560620.800000 | |
50 1287053.950000 1629947.300000 | |
100 1330382.350000 1635569.650000 | |
500 1880728.450000 2145010.250000 | |
1024 2600131.250000 3162551.900000 | |
5120 7538146.500000 11759352.200000 | |
10240 12450896.600000 31949892.750000 | |
51200 46581310.000000 506808350.150000 | |
102400 89835399.050000 1984445186.600000 | |
512000 489720105.050000 46670393357.750000 | |
1048576 1133701684.900000 195539025232.200012 |
package main | |
import ( | |
"fmt" | |
"io/ioutil" | |
"log" | |
"os" | |
"os/exec" | |
"syscall" | |
"time" | |
) | |
const KB int64 = 1 | |
const MB int64 = 1024 | |
const GB int64 = 1024 * 1024 | |
func main() { | |
fmt.Printf("Size\tgrep a FILE\tcat FILE | grep a\n") | |
sizes := []int64{1 * KB, 5 * KB, 10 * KB, 50 * KB, 100 * KB, 500 * KB, | |
1 * MB, 5 * MB, 10 * MB, 50 * MB, 100 * MB, 500 * MB, | |
1 * GB, 5 * GB, 10 * GB} | |
n := 10 | |
for _, size := range sizes { | |
benchmark(size, n) | |
} | |
} | |
func benchmark(size int64, n int) { | |
// 指定サイズのファイルを作る | |
bigFile, err := ioutil.TempFile("", "") | |
if err != nil { | |
log.Fatal(err) | |
} | |
bigFileName := bigFile.Name() | |
defer func() { | |
err := os.Remove(bigFileName) | |
if err != nil { | |
log.Fatal(err) | |
} | |
}() | |
/* | |
if err := bigFile.Truncate(size * 1024); err != nil { | |
log.Fatal(err) | |
} | |
*/ | |
// ここでベンチマークの種類を変えます | |
fillZero(bigFile, size) | |
// 2*n 回時間計測して平均をとる | |
var timeSum1 time.Duration = 0 | |
var timeSum2 time.Duration = 0 | |
timeSum1 += execLoop(n, grep1, bigFileName) | |
timeSum2 += execLoop(n, grep2, bigFileName) | |
timeSum2 += execLoop(n, grep2, bigFileName) | |
timeSum1 += execLoop(n, grep1, bigFileName) | |
// 出力 | |
fmt.Printf("%d\t%f\t%f\n", size, | |
float64(timeSum1)*0.5/float64(n), | |
float64(timeSum2)*0.5/float64(n)) | |
} | |
func fillZero(file *os.File, size int64) { | |
b := make([]byte, 1024) | |
for i, _ := range b { | |
b[i] = '0' | |
} | |
for i := int64(0); i < size; i++ { | |
_, err := file.Write(b) | |
if err != nil { | |
// TODO | |
log.Fatal(err) | |
} | |
} | |
} | |
func fillZeroWithNewline(file *os.File, size int64) { | |
b := make([]byte, 1024) | |
for i := 0; i < 1023; i++ { | |
b[i] = '0' | |
} | |
b[1023] = '\n' | |
for i := int64(0); i < size; i++ { | |
_, err := file.Write(b) | |
if err != nil { | |
// TODO | |
log.Fatal(err) | |
} | |
} | |
} | |
func fillNull(file *os.File, size int64) { | |
b := make([]byte, 1024) | |
for i, _ := range b { | |
b[i] = 0x0 | |
} | |
for i := int64(0); i < size; i++ { | |
_, err := file.Write(b) | |
if err != nil { | |
// TODO | |
log.Fatal(err) | |
} | |
} | |
} | |
// grep を n 回ループする時間を測る | |
func execLoop(n int, grep func(string) string, bigFileName string) time.Duration { | |
var timeSum time.Duration = 0 | |
for i := 0; i < n; i++ { | |
command := exec.Command("bash", "-c", grep(bigFileName)) | |
start := time.Now() | |
err := command.Run() | |
timeSum += time.Since(start) | |
if err != nil { | |
if exitErr, ok := err.(*exec.ExitError); ok { | |
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { | |
if status.ExitStatus() != 1 { | |
log.Fatal(err) | |
} | |
} else { | |
log.Fatalf("exitErr.Sys().(syscall.WaitStatus) failed") | |
} | |
} else { | |
log.Fatal(err) | |
} | |
} | |
} | |
return timeSum | |
} | |
// grep a FILENAME | |
func grep1(fileName string) string { | |
return "grep a \"" + fileName + "\"" | |
} | |
// cat FILENAME | grep a | |
func grep2(fileName string) string { | |
return "cat \"" + fileName + "\" | grep a" | |
} |
set terminal png font "MigMix 2M,14" | |
set title "Useless Use of Catによる実行速度変化 (改行あり)" | |
set xlabel "テキストファイルのサイズ [KB]" | |
set ylabel "時間 [秒]" | |
set key left top | |
set output "UUoC.png" | |
set logscale x 10 | |
set logscale y 10 | |
set format x "%.0t{/Symbol \264}10^{%T}" | |
set format y "%.0t{/Symbol \264}10^{%T}" | |
set xtics rotate by -70 | |
plot "log" using 1:($2 / 1000000000) title "grep a FILENAME", \ | |
"log" using 1:($3 / 1000000000) title "cat FILENAME | grep a" |