FTPクライアントとして、僕はFileZillaを使っているのですが、
Windows専用だったバージョン2系から、クロスプラットフォーム版として、バージョン3系へと、
開発リソースはシフトしましたが、バージョン3系は、安定性や機能、操作性といった面で、
バージョン2系よりも劣っていました。
なので、私も新たに導入するときはバージョン2系を選択するようにしていたのですが
(最新版のWindowsインストーラはXP上では正常に動作しないことも一因)
バージョン3を使う大きな利点を発見したのです!
なんと、FileZilla3ではSFTPプロトコル利用時に、日本語の利用が可能になったのです!
いやぁ、わざわざ端末で日本語ファイル名を hoge.tar にリネームしなくても転送が可能になるなんて、便利だなぁ
お昼ごはんを食べたら、続きをやることを忘れてしまったので、昨日の続き。
昨日は
// _decHexDigits s a translation table from a decimal number to its
// digits hexadecimal representation (e.g. _decHexDigits [234] = 0x234).
static readonly int[] _decHexDigits = new int [10000];
// _decHexLen caches the number of digits in a hexadecimal number.
// For instance _decHexLen [0x234] = 3.
static readonly int[] _decHexLen = new int [0x10000];
の_decHexLenを使わないように変更したので、今回は _decHexDigits のサイズを10000から100に縮小させますー
パッチはこんな感じ。昨日の分も含まれちゃってます
--- NumberFormatter.cs 2007-12-30 15:02:13.027134488 +0900
+++ NumberFormatter.reduce.cs 2007-12-31 09:42:27.605475016 +0900
@@ -74,32 +74,16 @@
// _decHexDigits s a translation table from a decimal number to its
// digits hexadecimal representation (e.g. _decHexDigits [234] = 0x234).
- static readonly int[] _decHexDigits = new int [10000];
-
- // _decHexLen caches the number of digits in a hexadecimal number.
- // For instance _decHexLen [0x234] = 3.
- static readonly int[] _decHexLen = new int [0x10000];
+ static readonly int[] _decHexDigits = new int [100];
static NumberFormatter ()
{
- // Compute _decHexDigits and _decHexLen.
+ // Compute _decHexDigits.
uint res = 0;
for (int i = 0; i < _decHexDigits.Length; i++) {
_decHexDigits [i] = (int)res;
res = AddOneToDecHex (res);
}
- int len = 0;
- for (int i = 0; i < _decHexLen.Length; i++) {
- if (i == 0x1)
- len = 1;
- if (i == 0x10)
- len = 2;
- else if (i == 0x100)
- len = 3;
- else if (i == 0x1000)
- len = 4;
- _decHexLen [i] = len;
- }
}
#endregion Static Fields
@@ -210,23 +194,48 @@
private static uint ToDecHex (int val)
{
int res = 0;
+ if (val >= 1000000) {
+ int v = val / 1000000;
+ val -= v * 1000000;
+ res = _decHexDigits [v] << 24;
+ }
if (val >= 10000) {
int v = val / 10000;
val -= v * 10000;
- res = _decHexDigits [v] << 16;
+ res |= _decHexDigits [v] << 16;
+ }
+ if (val >= 100) {
+ int v = val / 100;
+ val -= v * 100;
+ res |= _decHexDigits [v] << 8;
}
return (uint)(res | _decHexDigits [val]);
}
// Helper to count number of hexadecimal digits in a number.
- private static int DecHexLen (uint val)
+ private static int DecHexLen (uint v)
{
- int v = (int)val;
- if (v < 0)
- return 8;
- if (v < 0x10000)
- return _decHexLen [v];
- return 4 + _decHexLen [v >> 16];
+ if (v < 0x10000) {
+ if (v < 0x100) {
+ if (v < 0x10)
+ return v == 0 ? 0 : 1;
+ return 2;
+ } else {
+ if (v < 0x1000)
+ return 3;
+ return 4;
+ }
+ } else {
+ if (v < 0x1000000) {
+ if (v < 0x100000)
+ return 5;
+ return 6;
+ } else {
+ if (v < 0x10000000)
+ return 7;
+ return 8;
+ }
+ }
}
// Count number of hexadecimal digits stored in _val1 .. _val4.
@@ -1532,8 +1541,14 @@
Append ((char)('0' | exponent));
}
else {
- int hexDigit = _decHexDigits [exponent];
- if (exponent >= 100 || minDigits == 3)
+ int hexDigit = 0;
+ if (exponent >= 100) {
+ int v = exponent / 100;
+ exponent -= v * 100;
+ hexDigit = _decHexDigits [v] << 8;
+ }
+ hexDigit |= _decHexDigits [exponent];
+ if ((hexDigit >> 8) != 0 || minDigits == 3)
Append ((char)('0' | (hexDigit >> 8)));
Append ((char)('0' | ((hexDigit >> 4) & 0xf)));
Append ((char)('0' | (hexDigit & 0xf)));
ベンチマーク結果 (昨日のベンチコード)
| パッチ前 | パッチ後 | 昨日のパッチ | 今日のパッチ |
| CPU | メモリ | CPU | メモリ | CPU | メモリ | CPU | メモリ |
| 8.6sec | 20KB | 4.09sec | 327KB | 4.31sec | 57KB | 4.57sec | 20KB |
うむ。いい感じな気がする。英語をがんばればこれをMLに流せるかな…
パッチファイル
速度を向上させるパッチがきてたー
というわけで、さっそくベンチ
| パッチ前 | パッチ後 |
| CPU | メモリ | CPU | メモリ |
| 8.6sec | 20KB | 4.09sec | 327KB |
テストコードはこんな感じ
using System;
using System.Globalization;
class Test {
static void Main ()
{
DateTime dt = DateTime.Now;
NumberFormatInfo nfi = NumberFormatInfo.GetInstance (null);
long before = GC.GetTotalMemory (true);
for (int i = 0; i < 10000000; i ++)
i.ToString ("g", nfi);
TimeSpan time = DateTime.Now.Subtract (dt);
long after = GC.GetTotalMemory (true);
Console.WriteLine ("Time:{0}, Memory:{1}KB", time, (after - before) / 1000);
}
}
なんでプロファイラを使わないで、GC.GetTotalMemoryを使っているかというと、
プロファイラの実行に時間がかかるから(ぇ
それに、単純に静的に確保されるメモリ領域を知りたいだけだから。
次は、上記のコードのdouble型版。静的領域のメモリ確保量は変わらないと思ったけど少し変化が。
| パッチ前 | パッチ後 |
| CPU | メモリ | CPU | メモリ |
| 31.5sec | 32KB | 9.3sec | 389KB |
わお。劇的に早くなってる。しかもユニットテストは全部パスしているっぽい
だけど気になるのは
// _decHexDigits s a translation table from a decimal number to its
// digits hexadecimal representation (e.g. _decHexDigits [234] = 0x234).
static readonly int[] _decHexDigits = new int [10000];
// _decHexLen caches the number of digits in a hexadecimal number.
// For instance _decHexLen [0x234] = 3.
static readonly int[] _decHexLen = new int [0x10000];
この部分。さすがに静的メモリ確保しすぎな気がする。なので、以下のパッチをさらに適用して再測定。
--- NumberFormatter.cs 2007-12-30 13:39:42.397014155 +0900
+++ NumberFormatter.reduce.cs 2007-12-30 14:23:13.781828495 +0900
@@ -76,30 +76,14 @@
// digits hexadecimal representation (e.g. _decHexDigits [234] = 0x234).
static readonly int[] _decHexDigits = new int [10000];
- // _decHexLen caches the number of digits in a hexadecimal number.
- // For instance _decHexLen [0x234] = 3.
- static readonly int[] _decHexLen = new int [0x10000];
-
static NumberFormatter ()
{
- // Compute _decHexDigits and _decHexLen.
+ // Compute _decHexDigits.
uint res = 0;
for (int i = 0; i < _decHexDigits.Length; i++) {
_decHexDigits [i] = (int)res;
res = AddOneToDecHex (res);
}
- int len = 0;
- for (int i = 0; i < _decHexLen.Length; i++) {
- if (i == 0x1)
- len = 1;
- if (i == 0x10)
- len = 2;
- else if (i == 0x100)
- len = 3;
- else if (i == 0x1000)
- len = 4;
- _decHexLen [i] = len;
- }
}
#endregion Static Fields
@@ -219,14 +203,29 @@
}
// Helper to count number of hexadecimal digits in a number.
- private static int DecHexLen (uint val)
+ private static int DecHexLen (uint v)
{
- int v = (int)val;
- if (v < 0)
- return 8;
- if (v < 0x10000)
- return _decHexLen [v];
- return 4 + _decHexLen [v >> 16];
+ if (v < 0x10000) {
+ if (v < 0x100) {
+ if (v < 0x10)
+ return v == 0 ? 0 : 1;
+ return 2;
+ } else {
+ if (v < 0x1000)
+ return 3;
+ return 4;
+ }
+ } else {
+ if (v < 0x1000000) {
+ if (v < 0x100000)
+ return 5;
+ return 6;
+ } else {
+ if (v < 0x10000000)
+ return 7;
+ return 8;
+ }
+ }
}
// Count number of hexadecimal digits stored in _val1 .. _val4.
| パッチ後 | パッチ後+メモリ削減パッチ |
| CPU | メモリ | CPU | メモリ |
| 4.09sec | 327KB | 4.31sec | 57KB |
うむ。だいぶ減った。
後は、_decHexDigits = new int [10000] の部分も new int[100] ぐらいにすればいい気がするけど
速度を考慮すると、これぐらいでもちょうどいいのかな? ここら辺のトレードオフって難しいなぁ
メモに対してコメントを付ける機能を追加っと。
reCAPTCHAを使ってスパム対策もおっけー
今日はサイトマップを作った。ページ生成の流れは
- SQLでページ一覧を抽出
- URLとタイトルの一覧をXMLで出力。
- XSLでフラットなページ一覧から、URLを利用して階層構造に整形
とまぁ、こんな感じ。XSLにも慣れてきて数分でできた。
XSLでは、
URLに{PREFIX}を含み、{PREFIX}よりも前の文字列が空、{PREFIX}よりも後ろに / を含まない
(つまり、{PREFIX}hoge という形式のURLのみを選択)
という条件で、for-eachを回し、抽出されたページのURL + / を 新しい{PREFIX}として
再帰的にテンプレートを呼び出し・・・という仕組みで階層構造に変形してる。
(もちろん最初のテンプレート呼び出しは {PREFIX}=/ )
でもいくつか問題もあって、ページはIDで一意に識別していてURLとは独立しているんだけど
サイトマップにはURLも表示しなくちゃいけない。となると、多対1の関係にあるURLとIDから、
IDに対応するURLをひとつだけ抽出しなくちゃいけない。現在はSQLの GROUP BY を使ってごまかしているけど
StartPageがこっちの短いURLじゃなくてこっちの長いURLが選択されちゃってる。
なるべく一回のSQL実行で短いURLを選択するようにできないかなぁ・・・
残る作業は、メモに対してコメントをつける機能とか、このメモをRSSとかで配信できるようにぐらいかな…
あとはサイトマップを開くと悲しい量のページ数なので、何かソフトを作ってページを増やしたいなぁ
自転車で30分程のPCパーツショップへHDDを買いに行って、
現在、Windowsをインストール中。
インストール自体はすぐに終わってもWindows Updateが終わらない…
話は変わりますが、久しぶりにHDDを買って驚いたのですが
プラッタ枚数が1枚程度の場合、HDDの厚さが3分の2ぐらいになってるんですねー
160GBのHDDなので下手したら、プラッタ半面かもしれませんが。
こことかここで書いたことの続きなんだけど
試しにクイックじゃないフォーマットをかけてみたら、不良セクタが32KBに増えた。
もう一度、全セクタチェックをかけたら、不良セクタが38KBに。
新しいHDDを買ってくるか、別なHDDにOSを再インストールしないとなぁ…
今日の午前に書いたメモから、さらに不良セクタが増えていって、現在28KB
もう、このハードディスクは駄目かもしれんね…
旧ホームページでは、
Apache + mod_python + 4suite
という構成で、XMLファイルを動的にXSL変換していたけど、
ThinkPad T43上では1秒間に30リクエストぐらいしか処理できなかった。
だけど、新ホームページで採用した
lxmlというlibxml2とlibxsltのラッパーライブラリを使うと、
XSL変換の速度が七倍も向上した。なので、現在は
Apache + mod_python + lxml + sqlite
という構成で運営している。
何となくバックエンドをデータベースにしたかったので、
sqliteを使っている。無駄にパーマリンクとか、バージョンリンクとかがあるのは
そのためだったり。このメモの存在もね。
実家の家族共用PCのHDDに不良セクタが24KB分計上されてた。
きっと、起動中にブレーカーが落ちたりとか、
いろいろ乱暴な使われ方をされたからかな?
一部では、僕の呪いという噂もあるけどね(ぇ
ホームページのシステムを書き換えたのを機に、ブログっぽい日記でも付け始めようかと思ったので。