群馬へ。
家内の実家に日帰りで里帰り。ガソリンが115円とかあったけど、タイミングが合わず。でも119円で入れてきた。こちらより10円近く安いな。あと灯油も20リッタで1300円とかだった。
野菜をいっぱいもらってきた。もう全然違うんだよね。ブロッコリとか味もさることながら、2-3日もたつと黄色くなってすぐにダメになる。スーパで買ってきたのなんて1週間以上青々としてるし。成長抑制剤、オソロシイ。
Ubuntu 辞典
ひとしきり探し回ってから、EBViewがデフォルトでインストール済みであることに気付く。何やってるんだか。これでEPWingが扱えるので、英辞郎だけEBStudioで変換。なんかすごく速くていいな。Windowsの方もEBStudioに乗り替えようかな。
デスクトップにもUbuntu
デスクトップにもUbuntuを入れてみた。nVidiaドライバは、普通にアプリの追加と削除から入れるだけ。あとは、nvidia-xconfig -d 24 --twinviewとするとデュアルディスプレイが使える設定になるので、/etc/X11/xorg.confをエディタで開いてセカンドディスプレイの位置をRightOfからLeftOfに変更。残念ながら片方だけ回転というのはできないようだ。しかし設定はずいぶんと簡単になったものだ。
サイズ0の配列
サイズ0のコレクションは、Collectionsに宣言されている(EMPTY_LIST, EMPTY_SET, EMPTY_MAP)。サイズ0の配列がArraysあたりに宣言されていないのはなぜだろう。サイズ0の配列ってイミュータブルとみなして良いよね? もっとも配列は型情報を持っているから面倒というのはあるが。Stringのコンスタントプールみたいに、型ごとにプールするだけの話だよなぁ。
デフラグ
仕事用のThinkPadがかなり遅くなってきた。まだ2か月くらいしか使ってないんだけど、ディスクアクセスが地を這うように遅い。デフラグしても、導入当初の速度には戻らないんだけど、かけないよりはマシか。
デスクトップの方は、ほとんど使っていないから、大丈夫かと思いきや、
こんなに空き領域が残っていても、激しく断片化するんだなぁ。デスクトップの方は、そんなに使っちゃいないんだけど、なんで、こんなに断片化するかな。
あ、そういえばNIOのテストで何度もファイルのコピーを繰り返したっけ。しかもマルチスレッド化とかしたし。あれが原因か ^^;
クリスマス
鳥の丸焼きをいただいた。普通、こういうのって大味で、味気ないものだけど、今回いただいたものは、すごくおいしかった。胸肉なんか、さっぱりしているのに、とってもジューシー。

夢久は訳も分からず、記念撮影。

るいもは、ちょっとおすそわけ。ひたすら突進してきて、大変なことに...

Ubuntu Emacs
どうもフォントが気に入らない。デフォルトだと明朝だし。ipamonagothicにしてみたら、妙に字間が開くし。で、結局-nwでターミナルモードで使うのがいい感じだということに気づく。でもなぜか.emacsにset-foreground-colorしても無視される。あとset-terminal-encoding-systemも無視される。なんでだ。良く分からん。set-foreground-colorでwhiteにしても、なんか微妙に暗い。
暗いのは、ターミナルのプロファイルの設定の「色」のところでパレットの組み込みスキームを"XTerm"に変更したら直った。
finalフィールドって変更できるんだ。
リフレクション使えば、finalフィールドって変更できるんだね。
import java.lang.reflect.Field;
public class Test {
final int i = 1;
public static void main(String[] args) throws Exception {
Test test = new Test();
Field field = Test.class.getDeclaredField("i");
field.setAccessible(true);
field.set(test, 123);
System.console().printf("i = %d%n", field.getInt(test));
System.console().printf("i = %d%n", test.i);
}
}
$ java Test i = 123 i = 1
しかしfinalフィールドは、値がインライン展開されるから、リフレクションで取得した値と、普通にアクセスした値が異るという、イヤな結果に。むしろfinalフィールドの変更はリフレクション経由の場合もエラーにした方が良かったんじゃないか?
結局Meadow2に戻す。
やっぱりce-scrollには馴染めなかった。ところどころカーソルの動きがおかしくなるのと、致命的なのはEmacs全体に適用されてしまう点。文書以外のバッファでは通常のカーソル移動でないと困るんだよね。特に自分の場合、マクロを多用するので。やっぱりphysical-line-modeは良くできている。
キー配列ではまる。
何かのタイミングでキーボードが英語配列になってしまった。デバイスマネージャのキーボードドライバを日本語 PS/2 キーボード(106/109 キー Ctrl+英数)に変更して、ほとんどのアプリケーションは問題無くなったのだが、なぜかMS Officeだけは英語配列のまま。そんなに使用頻度は高くないので、だましだまし使っていたのだが、そろそろ我慢できなくなってきて調べてみた。
結局ここの情報で直った。レジストリエディタで、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard\Layouts\00000411下のLayout Fileをkbdjpn.dllに修正。
SimpleDateFormatのk
人の書いたソースを見ていたら、SimpleDateFormatの書式に"kk:mm"というのがあって、kってなんだろうと調べてみたら時間を1-24で表現する書式のようだ。
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, Calendar.DECEMBER);
cal.set(Calendar.DAY_OF_MONTH, 31);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
Date date = cal.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd kk:mm");
System.out.println(sdf.format(date));
sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
System.out.println(sdf.format(date));
2006/12/31 24:00 2006/12/31 00:00
なんか日付との整合性が合わないな。これって本当は2006/12/30 24:00じゃないの? kを使う時は日付を使用してはいけないのかな。
50万hit
カウンタが50万を越えた。もっともほとんどはRSSリーダからのポーリングによるものと思われるので、実際のPVはずっと少ないんだろうけど。
というわけで、これからもよろしくお願いいたします。
ファイルコピー
SHISHI@東京さんからヒントをいただいたので、ちょっとNIO版を書き換えてみた。
public class CopyByNio2 {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
String copyFrom = args[0];
String copyTo = args[1];
int bufferSize = 32 * 1024;
if (args.length > 2) {
bufferSize = Integer.parseInt(args[2]) * 1024;
}
if (bufferSize <= 0)
throw new IllegalArgumentException("Invalid buffer size(=" + bufferSize + ").");
FileChannel in = null;
FileChannel out = null;
try {
in = new FileInputStream(copyFrom).getChannel();
out = new FileOutputStream(copyTo).getChannel();
long size = in.size();
long offset = 0;
while (size > 0) {
long writtenSize = in.transferTo(offset, size, out);
offset += writtenSize;
size -= writtenSize;
}
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
if (in != null) {
try {in.close();}
catch (IOException ex) {ex.printStackTrace();}
}
if (out != null) {
try {out.close();}
catch (IOException ex) {ex.printStackTrace();}
}
System.console().printf("Elapsed %,d%n",System.currentTimeMillis() - startTime);
}
}
}
あってるかな? 一応コピーされたファイルの内容を確認したので、大丈夫そうだけど... 結果は0.5秒くらい速くなったけど、この程度だと大差無しかなぁ。というか前回のテストでは25秒くらいだったのが、今回はどれも10秒くらいで終わるのは、どういうわけだろう。前回は、なぜかキャッシュが効いていなかったようだ。バックグランドで動いていたアプリケーションのせいだろうか。
続ファイルコピー
そういえばwrite back cacheの影響があるなと思い、コピー先をUSB 1.1のメモリに変えてみた。約6.3MBのファイルコピー。
Stream
| 1024 | 512 | 256 | 128 | 64 | 32 | 16 |
|---|---|---|---|---|---|---|
| 7.79 | 8.02 | 8.52 | 9.53 | 11.55 | 16.03 | 25.15 |
NIO
| 1024 | 512 | 256 | 128 | 64 | 32 | 16 |
|---|---|---|---|---|---|---|
| 7.78 | 7.99 | 8.52 | 9.53 | 11.55 | 16.13 | 25.32 |
やっぱり大差無いな。もっとも今回の例だとUSBへの書き込みが圧倒的なbottle neckだから差が出なくて当然か。しかし随分とバッファサイズが影響するもんだ。USBへの書き込みの開始終了に、何かオーバーヘッドがあるんだろうか。
読み込みと書き込みが遅いデバイスならば、読み込みと書き込みを別スレッドに分けてオーバーラップさせてやったら、速くなるんじゃないだろうか。というわけでマルチスレッド版コピーを試してみた。
import java.io.*;
import java.util.concurrent.*;
public class MultiThreadedCopyByStream {
static class Packet {
final int size;
final byte[] buf;
Packet(int size, byte[] buf) {
this.size = size;
this.buf = buf;
}
}
static BlockingQueue queue = new LinkedBlockingQueue(8);
static class Donor extends Thread {
final String copyFrom;
final int bufSize;
Donor(String copyFrom, int bufSize) {
this.copyFrom = copyFrom;
this.bufSize = bufSize;
}
@Override public void run() {
InputStream in = null;
try {
in = new FileInputStream(copyFrom);
while (true) {
byte[] buf = new byte[bufSize];
System.console().printf("%,d, Reading data%n", System.currentTimeMillis() - startTime);
int readLength = in.read(buf);
System.console().printf("%,d, Reading data done%n", System.currentTimeMillis() - startTime);
if (readLength == -1) {
try {
queue.put(new Packet(-1, null));
}
catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
break;
}
try {
queue.put(new Packet(readLength, buf));
}
catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
if (in != null) {
try {in.close();}
catch (IOException ex) {ex.printStackTrace();}
}
}
}
}
static class Acceptor extends Thread {
final String copyTo;
Acceptor(String copyTo) {
this.copyTo = copyTo;
}
@Override public void run() {
startTime = System.currentTimeMillis();
OutputStream out = null;
try {
out = new FileOutputStream(copyTo);
while (true) {
Packet packet = null;
try {
packet = queue.take();
}
catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
if (packet.size == -1) break;
System.console().printf("%,d, Writing data%n", System.currentTimeMillis() - startTime);
out.write(packet.buf, 0, packet.size);
System.console().printf("%,d, Writing data done%n", System.currentTimeMillis() - startTime);
}
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
if (out != null) {
try {out.close();}
catch (IOException ex) {ex.printStackTrace();}
}
System.console().printf("Elapsed %,d%n",System.currentTimeMillis() - startTime);
}
}
}
public static void main(String[] args) {
String copyFrom = args[0];
String copyTo = args[1];
int bufferSize = 32 * 1024;
if (args.length > 2) {
bufferSize = Integer.parseInt(args[2]) * 1024;
}
if (bufferSize <= 0)
throw new IllegalArgumentException("Invalid buffer size(=" + bufferSize + ").");
new Donor(copyFrom, bufferSize).start();
new Acceptor(copyTo).start();
}
static volatile long startTime;
}
concurrentパッケージを使うと簡単だ。読み込みがローカルドライブだと差がでないだろうから、無線LAN越しのリモートファイルにしてみた。バッファサイズは1MB。
| マルチスレッド | シングルスレッド(Stream) | シングルスレッド(NIO) |
|---|---|---|
| 8.24 | 9.14 | 9.16 |
32, Reading data 516, Reading data done 516, Writing data 516, Reading data 1,407, Reading data done 1,407, Reading data 1,407, Reading data done 1,422, Reading data 1,735, Writing data done 1,735, Writing data 1,875, Reading data done 1,875, Reading data 2,344, Reading data done 2,360, Reading data 2,938, Reading data done 2,938, Reading data 2,938, Reading data done 2,938, Writing data done 2,938, Reading data 2,938, Writing data 2,954, Reading data done 4,172, Writing data done 4,172, Writing data 5,407, Writing data done 5,407, Writing data 6,625, Writing data done 6,625, Writing data 7,860, Writing data done 7,860, Writing data 8,219, Writing data done
読み込みが、ほぼ一瞬で終わっている。どうもOSに違いレイヤで、データの先読みをしているっぽい。面白いのがcmdのcopyによる結果が8.17secで高速なところ。copyも内部はマルチスレッド化しているんだろうか?
JDK 6.0
昔、ASCIIの実践Javaで、artonさんがStreamとNIOでファイルコピーの比較を掲載していたのだけど、あの頃は1.4だったので6.0ならば、どうかなと思って、やってみた。環境は、Core 2 Duo(3.4Gにover clock)で、Windows XP、DiskはSATA(3Gbps) Seagateの7200rpmのもの。ローカルファイル(サイズ670MB)のコピー時間を計ってみた。3回測定し、平均値から大きく逸脱しているものは除いて平均をとってみた。単位は秒。
Stream:
| 1k | 2k | 4k | 8k | 16k | 32k | 64k |
|---|---|---|---|---|---|---|
| 26.1 | 26.0 | 26.2 | 26.0 | 26.3 | 28.7 | 28.4 |
Nio:
| 1k | 2k | 4k | 8k | 16k | 32k | 64k |
|---|---|---|---|---|---|---|
| 26.4 | 26.1 | 26.3 | 24.8 | 26.3 | 26.3 | 28.0 |
う〜ん、今回もNIOとStreamでは大差無しかな。というかバッファサイズって1kもあれば十分なんだね。でもディスクアクセスの音を聞いていると、どうもバッファサイズは効いていないような気もする。もっとOSに近いレイヤでバッファリングがかかっていて、アプリケーションでバッファリングしても、これだけCPUが速い時代になると無意味なのかもしれない。何しろCPU使用率は、どのケースも有意差無しだったし。しかしバッファサイズが大きいとなんで遅くなるんだろう。Streamが32kで、ちょっと遅くなるのに対しNioは64kからちょっと遅くなるという傾向も興味深い。
ちなみにcmdでふつーにcopyしたら、27.8秒だった。cmdのcopyもバッファサイズが大きいのかな。
使用したプログラム:
--- CopyByStream.java ---
import java.io.*;
public class CopyByStream {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
String copyFrom = args[0];
String copyTo = args[1];
int bufferSize = 32 * 1024;
if (args.length > 2) {
bufferSize = Integer.parseInt(args[2]) * 1024;
}
if (bufferSize <= 0)
throw new IllegalArgumentException("Invalid buffer size(=" + bufferSize + ").");
byte[] buf = new byte[bufferSize];
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(copyFrom);
out = new FileOutputStream(copyTo);
while (true) {
int readLength = in.read(buf);
if (readLength == -1) break;
out.write(buf, 0, readLength);
}
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
if (in != null) {
try {in.close();}
catch (IOException ex) {ex.printStackTrace();}
}
if (out != null) {
try {out.close();}
catch (IOException ex) {ex.printStackTrace();}
}
System.console().printf("Elapsed %,d%n",System.currentTimeMillis() - startTime);
}
}
}
--- CopyByNio.java ---
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
public class CopyByNio {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
String copyFrom = args[0];
String copyTo = args[1];
int bufferSize = 32 * 1024;
if (args.length > 2) {
bufferSize = Integer.parseInt(args[2]) * 1024;
}
if (bufferSize <= 0)
throw new IllegalArgumentException("Invalid buffer size(=" + bufferSize + ").");
FileChannel in = null;
FileChannel out = null;
try {
in = new FileInputStream(copyFrom).getChannel();
out = new FileOutputStream(copyTo).getChannel();
ByteBuffer buf = ByteBuffer.allocateDirect(bufferSize);
while (true) {
int readLength = in.read(buf);
if (readLength == -1) break;
buf.flip();
out.write(buf);
buf.rewind();
}
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
if (in != null) {
try {in.close();}
catch (IOException ex) {ex.printStackTrace();}
}
if (out != null) {
try {out.close();}
catch (IOException ex) {ex.printStackTrace();}
}
System.console().printf("Elapsed %,d%n",System.currentTimeMillis() - startTime);
}
}
}
チャーリーくん家
チャーリーくんの家に遊びに行ってきた。チャーリーくんは夢久の兄弟。兄弟だけあって、仕草や容姿がとても似ている。


このまぶしそうな顔なんか、そっくり。




これは、お友達のNeneちゃん。なんかずっと怒っていたんだけど、なんで、そんなに怒っているのかは、良く分からず ^^;







どうも、私は、普段のチャーリー君の席に座ってしまっていたようで、そのせいか、ちょっとご機嫌斜めだったかも。ごめんね。
File.list(FilenameFilter)
File.traverse(FilenameListener)みたいのが欲しいなぁ。連番ファイルの最大が欲しいみたいな時は、別にリストなんていらないので。ファイル数が多いとメモリ消費がばかにならない。
あ、そっか、FilenameFilterで常にfalseを返すようにすればいいのか。
Ubuntu AirH"でprinにつなぐ。
ちょっと悩んだけど、できてみればあっけない。
--- /etc/ppp/peers/provider --- hide-password noauth connect "/usr/sbin/chat -v -f /etc/chatscripts/provider" debug /dev/ttyS2 115200 defaultroute noipdefault user "prin" remotename provider ipparam provider
--- /etc/ppp/pap-secrets --- 最後に以下の行を追加。 prin provider prin
--- /etc/chatscripts/provider --- 以下の行だけ残して、他は行頭に#を入れてコメントアウト '' AT&FZ&C1E0V1&D2X4\V1\X1S0=0S7=60&K3 OK-AT-OK ATDTxxxxxxxxxx##64 CONNECT ''
ダイヤルアップ開始はsudo pon provider。ログはplogで確認できる。接続断はpoff。なんかpap-secretsがグループアクセスできちゃうよってWarningが出るので、chmodでグループアクセスを禁止した。でも、prinだと、これって共通だから別に隠さなくてもいい気はする。
FindBugs、Google codeに移動。
いつのまにかGoogle codeに移行していた。しかしGoogleはデザインがシンプルで良いね。SourceForgeの方のCVSも残っている模様。
ubuntu Emacsでファイルの最後に飛ぶ
"Shift + Alt + >"だと、なんか文字化けする。なぜなんだろう。と思ったら、ブラウザ上でやるとカタカナモードになるようだ。IMまわりのキーバインドに割り当てられているのかな。
あった。システム->設定->キーボードの中のレイアウトのオプションで、"Group Shift/Lock behavior"で、Alt+Shift changes groupのチェックを外したら直った。
Ubuntu svn
ssh+svnでアクセスできるようにする。
mkdir ~/.ssh/ cd ~/.ssh/ ssh-keygen -t dsa cat ~/.ssh/id_dsa.pub | ssh userid@host "cat - >> ~/.ssh/authorized_keys"
パスフレーズを何度も聞かれるので、
ssh-agent ssh-add
ubuntu Emacs設定
とりあえずSKK。
Apel:ftp://ftp.jpl.org/pub/elisp/apel/。展開してsudo make install。
SKK:http://openlab.ring.gr.jp/skk/maintrunk/legacy/。展開して、sudo make、sudo make install。
辞書:http://openlab.ring.gr.jp/skk/dic/。SKK-JISYO.Lを~に展開。
--- .emacs ---
;; Add pahts to SKK and APEL
(defvar system-load-path load-path)
(setq my-load-path '("/usr/share/skk"
"/usr/local/share/emacs/site-lisp/skk"
"/usr/local/share/emacs/site-lisp/apel"
"/usr/local/share/emacs/21.4/site-lisp/emu"))
(setq load-path (append my-load-path system-load-path))
;; Configure for SKK
(require 'skk-autoloads)
(global-set-key "\C-x\C-j" 'skk-mode)
;; Specify dictionary location
(setq skk-large-jisyo "~/SKK-JISYO.L")
(add-hook 'isearch-mode-hook
(function (lambda ()
(and (boundp 'skk-mode) skk-mode
(skk-isearch-mode-setup)))))
(add-hook 'isearch-mode-end-hook
(function
(lambda ()
(and (boundp 'skk-mode) skk-mode (skk-isearch-mode-cleanup))
(and (boundp 'skk-mode-invoked) skk-mode-invoked
(skk-set-cursor-properly)))))










