nice(笑)ってきてたけど、正直、優先度について全く知らなかったっていう。
どれだけ効果があるのかな。
作ったプログラムとスクリプトの紹介
loop ... 40億回インクリメントを行うループ
loop2 ... 4万回インクリメントを行うループ(ループ毎にusleep(1000)するので、40秒かかる計算)
kick.sh ... 指定したコマンドを3回同時にバックグラウンド実行する。それぞれ、通常、nice, chrtを使う。
コードは最後。
環境
SのVPS(512MB)
[root@www43071u tmp]# uname -a
Linux www43071u.sakura.ne.jp 2.6.32-220.4.1.el6.x86_64 #1 SMP Tue Jan 24 02:13:44 GMT 2012 x86_64 x86_64 x86_64 GNU/Linux
[root@www43071u tmp]# cat /etc/redhat-release
CentOS release 6.2 (Final)
[root@www43071u tmp]# gcc -v
Using built-in specs.
Target: x86_64-redhat-linux
コンフィグオプション: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
スレッドモデル: posix
gcc version 4.4.6 20110731 (Red Hat 4.4.6-3) (GCC)
作業PC@VM
[root@localhost tmp]# uname -a
Linux localhost.localdomain 2.6.32-220.el6.x86_64 #1 SMP Tue Dec 6 19:48:22 GMT 2011 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost tmp]# cat /etc/redhat-release
CentOS release 6.2 (Final)
[root@localhost tmp]# gcc -v
Using built-in specs.
Target: x86_64-redhat-linux
コンフィグオプション: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
スレッドモデル: posix
gcc version 4.4.6 20110731 (Red Hat 4.4.6-3) (GCC)
自宅鯖(nimono鯖)
[root@rying tmp]# uname -a
Linux rying.net 2.6.38.3 #4 SMP Sat Apr 30 20:21:58 JST 2011 i686 i686 i386 GNU/Linux
[root@rying tmp]# cat /etc/redhat-release
CentOS release 5.6 (Final)
[root@rying tmp]# gcc -v
Using built-in specs.
Target: i386-redhat-linux6E
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --disable-gnu-unique-object --enable-languages=c,c++,fortran --disable-libgcj --with-mpfr=/builddir/build/BUILD/gcc-4.4.4-20100726/obj-i386-redhat-linux6E/mpfr-install/ --with-ppl=/builddir/build/BUILD/gcc-4.4.4-20100726/obj-i386-redhat-linux6E/ppl-install --with-cloog=/builddir/build/BUILD/gcc-4.4.4-20100726/obj-i386-redhat-linux6E/cloog-install --with-tune=generic --with-arch=i586 --build=i386-redhat-linux6E
Thread model: posix
gcc version 4.4.4 20100726 (Red Hat 4.4.4-13) (GCC)
他のディストリビューションが怖いCentOS厨。
自宅鯖はおそらく、ふつーのカーネル。
計測
コンパイル時にオプションはつけないで実施した。
最適化しないよう明示する-O0とかしたほうがよかったかも。
SのVPS(512MB)
# ./kick.sh ./loop
Start normal[pid:10676]
Start chrt[pid:10677]
Start nice[pid:10678]
Finish chrt[pid:10677] (12890000clock, time:12.920274)
Finish nice[pid:10678] (13500000clock, time:13.719407)
Finish normal[pid:10676] (14040000clock, time:22.026900)
プロンプトが全く帰ってこなかった。chrt終了後は普通に操作できた。
# ./kick.sh ./loop2
Start normal[pid:10722]
Start chrt[pid:10723]
Start nice[pid:10724]
Finish chrt[pid:10723] (960000clock, time:47.292046)
Finish nice[pid:10724] (960000clock, time:48.779575)
Finish normal[pid:10722] (980000clock, time:49.117561)
sleepの精度が悪いと思えばおおむね期待通り。
作業PC@VM
# ./kick.sh ./loop & top
Start normal[pid:12341]
Start chrt[pid:12342]
Start nice[pid:12343]
Finish chrt[pid:12342] (10150000clock, time:10.656801)
Finish nice[pid:12343] (10140000clock, time:19.264167)
Finish normal[pid:12341] (9970000clock, time:29.298647)
プロンプトがちょこっと帰ってきたのでtopを一緒に表示。chrt終了後は普通に操作できた。
topコマンド見
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 12342 root RT 0 3976 448 372 R 99.9 0.0 0:02.13 loop 12343 root 0 -20 3976 452 372 R 6.7 0.0 0:00.08 loop 1 root 20 0 19272 1512 1248 S 0.0 0.1 0:01.38 init (更新後...) PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 12343 root 0 -20 3976 452 372 R 70.1 0.0 0:01.49 loop 12341 root 20 0 3976 452 372 R 0.7 0.0 0:00.01 loop 1 root 20 0 19272 1512 1248 S 0.0 0.1 0:01.38 init
chrtはPRがRTになってる。niceはPRが0でNIが-20。普通はPRが20でNIが0。
# ./kick.sh ./loop2
Start chrt[pid:12354]
Start nice[pid:12355]
Start normal[pid:12353]
Finish chrt[pid:12354] (0clock, time:78.973567)
Finish nice[pid:12355] (0clock, time:78.983294)
Finish normal[pid:12353] (0clock, time:78.990050)
論外
自宅鯖(nimono鯖)
# ./kick.sh ./loop
Start normal[pid:24110]
Start chrt[pid:24111]
Start nice[pid:24112]
Finish chrt[pid:24111] (10540000clock, time:10.550355)
Finish nice[pid:24112] (10580000clock, time:10.830323)
Finish normal[pid:24110] (10600000clock, time:21.227035)
プロンプトが全く帰ってこなかった。chrt終了後は普通に操作できた。
# ./kick.sh ./loop2
Start normal[pid:24196]
Start chrt[pid:24197]
Start nice[pid:24198]
Finish chrt[pid:24197] (100000clock, time:40.157387)
Finish normal[pid:24196] (100000clock, time:41.892862)
Finish nice[pid:24198] (100000clock, time:41.924659)
期待通りだが、clock数がどれも一緒なのが怪しい。
まとめ
- 処理速度を上げる効果はない。(clock数はどれも優先度に限らず、ばらばら。)
- CPUが取り合いになっている状態のときは、chrt>nice>普通の順で優先度が守られているのが分かった。
- CPUが多めに割り当てられるので、実行時間が短くなる。
- スリープ(待ち状態)が頻繁に発生すると、優先度の効果が小さくなる。
loop1.c
#include <stdio.h> #include <sys/types.h> #include <sys/time.h> #include <unistd.h> #include <time.h> #include <stdlib.h> double timevaldiff(const struct timeval *et, const struct timeval *st){ return (et->tv_sec - st->tv_sec) * 1000000.0 + (et->tv_usec - st->tv_usec) ; } int main(int argc, char **argv){ unsigned int loop = 4000000000; unsigned int i; pid_t pid = getpid(); clock_t sc, ec; struct timeval st, et; if(argc != 2){ printf("usage:%s [NAME]", argv[0]); exit(1); } printf("Start %s[pid:%d]\n", argv[1], pid); sc = clock(); gettimeofday(&st, NULL); for(i=0;i<loop;++i); gettimeofday(&et, NULL); ec = clock(); printf("Finish %s[pid:%d] (%dclock, time:%f)\n", argv[1], pid, ec-sc, timevaldiff(&et, &st)/1000000); return 0; }
loop2.c
#include <stdio.h> #include <sys/types.h> #include <sys/time.h> #include <unistd.h> #include <time.h> #include <stdlib.h> double timevaldiff(const struct timeval *et, const struct timeval *st){ return (et->tv_sec - st->tv_sec) * 1000000.0 + (et->tv_usec - st->tv_usec) ; } int main(int argc, char **argv){ unsigned int loop = 40000; unsigned int i; pid_t pid = getpid(); clock_t sc, ec; struct timeval st, et; if(argc != 2){ printf("usage:%s [NAME]", argv[0]); exit(1); } printf("Start %s[pid:%d]\n", argv[1], pid); sc = clock(); gettimeofday(&st, NULL); for(i=0;i<loop;++i) usleep(1000); gettimeofday(&et, NULL); ec = clock(); printf("Finish %s[pid:%d] (%dclock, time:%f)\n", argv[1], pid, ec-sc, timevaldiff(&et, &st)/1000000); return 0; }
kick.sh
#!/bin/sh if [ $# != 1 ] ;then echo "usage: $0 [COMMAND]"; exit 1 fi $1 normal & chrt -r 99 $1 chrt & /bin/nice -n -20 $1 nice &