最近気付いた GNU screen の tips を少し.
sessionname
screen では
% screen -S <session_name>
としてセッション名を付けてから起動すると,
以降 -r で復帰する時などに <session_name> で参照できるが,
普通付け忘れることが多い (^^;)。というか, 起動してから, その screen での主な
作業が決まることも多い。
で, そういう時でも, 実は <prefix> : sessionname foo とタイプすれば,
名前を foo に変更することができる。
..しかし, その際に $STY を変更してはくれないし, やや手続きが面倒。
次のように ~/.zshrc に書いておくと, シェルから % session hoge とタイプする
だけで今のセッションネームを hoge に変更できる。
session () {
screen -X sessionname "$@"
eval "STY=$STY:r.$@"
}
ただし, $STY の変更はこれを実行したシェルだけなので, 他に同時に走っている
シェルでは /tmp/uscreens/S-username/* を見たりして$STYをアップデート
する必要があるかも。
completion
複数の screen が上がっていてレジュームする時, 特に名前を付けていなければ,
% screen -r 21576
のようにプロセス番号を指定しなければならない。(または, 名前を付けていれば
どの名前があるか思い出さないといけない。)
screen -ls を見てプロセス番号をコピーするのは何だかなぁ, とずっと思っていた
のだが, .zshrc に次のように書いておくと,
% screen -r <TAB>
で補完できる。
_screen () {
reply=(`screen -ls | awk '/^[ \t]*[0-9][0-9]+/{ split($1,a,"."); print a[1] }'`)
}
compctl -K _screen screen
compinit が重いのと余計な補完をしてくれるため, わざと使っていないので,
compctl になっているのに注意。
compinit だと, 上の補完は誰かが書いてすでに入って
いる可能性があると思う。これでタブで補完しまくり。便利便利。
prefix
screen のデフォルトのプレフィクスは C-a のため, Emacs が使いにくい
ので, screen を使っている人は普通何かのキーに変更していると思う。
僕は telnet のエスケープからの繋がりで
escape ^]]
としていたが (C-] で screen の機能を実行する), いずれにしても
ホームポジションから指を離さないといけないので, 頻繁に使うウインドウの移動
(C-] C-]) などがやりにくい。
以前 screen スレを見ていたら, "C-;" は普通は意味を持っていないよ, という情報
があった。; はホームポジションなので, 全く手を離さずにタイプできる。
ただし, 普通に C-; を設定しても, そんなコードは存在しないのでバインドできない。
が, 普通X上で使うことが今は仮定できるので, その場合は, C-; が C-] のコードを
出すように ~/.Xresources で設定してあげれば実現できる。
具体的には, .screenrc が
escape ^]]
だった場合, .Xresources に次のように書いておく。
KTerm*VT100*Translations: #override \
Ctrl <Key> ;: string(0x1d) \n\
Meta Ctrl <Key> p: string(0x1d) string("[") string(0x15) \n\
Meta Ctrl <Key> n: string(0x1d) string("[") string(0x04)
これで, X上では C-; を screen のプレフィクスとして使える。2行目〜3行目
は, screen の copy モードに入らなくても, M-C-{p,n} でバックスクロール
するための設定。C-] でない人は, "0x1d" の部分を自分が使っているプレフィクス
のコードに変更すればいけると思う。
Cでは一応多次元配列が使えるが, double matrix[10][20] のように
コンパイル時に決まっていない場合は, 普通は matrix[i][j] のようにはアクセスでき
ない。
列ごとに1行を malloc して割り付ければアクセスできるが, 10000x1000の行列なら
10000回 malloc することになるわけで, メモリ上で断片化が起きるし,
malloc のオーバヘッドがありそうなので良くないかと思っていた。
(& 原理的に連続なものを断片的に malloc するのは良くないという気もした。)
そうでないと,
matrix = (double *)malloc(rows * cols * sizeof(double)); のように確保する
ことになるが, これは matrix[i][j] ではアクセスできない。
仕方がないので, これまで
#define LZS(i,j) (*(lzs + K * i + j))
のようにマクロを定義して使っていたが, 家に帰って, 前にPCに保存しておいた
C FAQ
(fj.lang.c に定期的に流れていたもの) を読んでいたら,
以下のようなコードを書くと, matrix[i][j] でアクセスできることを知った。
/*
dmatrix.h
a header file of double matrix.
$Id: dmatrix.h,v 1.1 2004/10/26 05:04:21 dmochiha Exp $
*/
#ifndef __DMATRIX_H__
#define __DMATRIX_H__
extern double **dmatrix(int rows, int cols);
#endif
/*
dmatrix.c
an implementation of double matrix.
$Id: dmatrix.c,v 1.1 2004/10/26 05:04:20 dmochiha Exp $
*/
#include <stdlib.h>
#include "dmatrix.h"
double **
dmatrix (int rows, int cols)
{
double **matrix;
int i;
matrix = (double **)malloc(rows * sizeof(double *));
if (matrix == NULL)
return NULL;
*matrix = (double *)malloc(rows * cols * sizeof(double)); // 中身を連続して malloc
if (*matrix == NULL)
return NULL;
for (i = 1; i < rows; i++)
matrix[i] = *matrix + i * cols;
return matrix;
}
以下のように使う。
#include "dmatrix.h"
double **matrix;
if ((matrix = dmatrix(nrows, ncols)) == NULL) {
fprintf(stderr, "cannot allocate matrix\n");
exit(1);
}
st = myclock();
for (i = 0; i < nrows; i++)
for (j = 0; j < ncols; j++)
matrix[i][j] = i + j;
ed = myclock();
ふむふむ, と思っていたが, コードを書いて調べてみると, 下のように
列ごとに malloc する方が速いようだ。えーーーー。;;
コードは上の dmatrix を使った方が綺麗なんだけど..。;
pxn:~/tmp/test% ./mdary 100 100 % 上の dmatrix を使った場合
elapsed = 0.000128
pxn:~/tmp/test% ./mdary2 100 100 % 列ごとに malloc する場合
elapsed = 0.000038
pxn:~/tmp/test% ./mdary 10000 1000
elapsed = 0.158179
pxn:~/tmp/test% ./mdary2 10000 1000
elapsed = 0.128347