2008年 3月 18日 火曜日 NetBeans 6.1 Beta, DTD ファイルから DOM ツリースキャナと SAX ドキュメントハンドラを自動生成
NetBeans 5.5.1 まではプロジェクト内の DTD ファイルを右クリックすると表示されるメニューの中に以下の 2 つが含まれていましたが、6.0/6.0.1 で無くなってしまいました。
これが 6.1 で復活することになりました。メニュー項目名の通り、これらは以下の機能を提供します:
DOM ツリースキャナを生成
DTD から、DOM ツリー内をスキャンするクラスが自動生成されます。生成されたクラスに少し手を加えると、XML の特定のノードの値を変更して出力するプログラムを作ることができます。
SAX ドキュメントハンドラウィザード
こちらも DTD ファイルを読み込んで、ContentHandler インターフェースを実装したドキュメントハンドラを生成します。DTD で定められた要素が見つかった時に、その内容を標準エラー出力に書き出すデバッグ用メソッドが自動生成されます。
これら 2 の機能は、XML を読み込んで動作するプログラムを作るときに便利だったので、ユーザーからの復活の要望が多く、6.1 で復活することになりました。機能を消したのもじつは、熟慮の結果というわけではなかったみたいです:
http://www.netbeans.org/issues/show_bug.cgi?id=90174
私自身、復活する前に使いたい時があって、その時は 5.5.1 でソースを生成させて 6.0.1 で編集しました。
ただ、SAX ドキュメントハンドラウィザードは 6.1 Beta で動かなかったので、さっきバグ登録をしました:
http://www.netbeans.org/issues/show_bug.cgi?id=130372
Beta でバグがあるとはいえ、便利だと思っていた機能が復活したのは嬉しかったです。
Posted by keiichio
( 3月 18日 2008年, 07:38:40 午後 JST )
Permalink
投稿されたコメント [0]
Sun Studio 12, cc, -xprofile による実行時プロファイルデータを用いた最適化
以前の SIMD 命令の使用についてのエントリに続いて、姫野ベンチの実行結果から成績の良かった下記のコンパイルオプションの中の、-xprofile=use:bmt について見ていきたいと思います。
-DMIDDLE -fast -m64 -xvector=simd -xprofile=use:bmt
-xprofile
このオプションは collect、use というパラメータを指定して使用します。collect、use 以外に tcov というパラメータもありますが、tcov については別の機会に説明したいと思います。
-xprofile=collect
-xprofile=use
他のコンパイルオプションによる最適化がソースコードの解析に基づくのとは異なり、このオプションは実行時のプロファイルデータに基づいた最適化を行うためのものです。一旦実行させて最適化のためのプロファイルデータを蓄えておいて、そのプロファイルデータを使って再コンパイルすることで、実際の実行時に時間のかかかった処理を特定しその部分の再構築などを行います。ですので -xprofile オプションを使用するコンパイルは必ず以下の流れになります:
より具体的に見ていくために以下の例を使います (foo.c というプログラムをコンパイルして foo という実行ファイルを作成することを想定しています)
1 $ cc -xtarget=native -xprofile=collect:foo foo.c -o foo 2 $ ./foo 123 3 $ ./foo 456 4 $ rm foo 5 $ cc -xtarget=native -xprofile=use:foo foo.c -o foo
1 行目のコンパイルで、foo という実行可能ファイルは最適化のためのプロファイルデータを収集するプログラムとして生成されます。
2 行目と 3 行目の実行により、実行ディレクトリに foo.profile というサブディレクトリが生成され、ここにプロファイルデータが蓄積されます。このディレクトリ名はオプションの指定のしかたによって変わります。例えば -xprofile=collect:/tmp/bar と指定したら /tmp/bar.profile というサブディレクトリに集められます。プログラムに与える引数によって内部での分岐先が異なるような場合には、異なる引数を与えて複数回実行させます。ただ、ここで与える引数はあくまでも実際の動作により近い典型的な入力値であり、頻度が非常に少ないのであれば上限値や下限値を与える必要はありませんし、すべての分岐を実行させる必要もありません。
4 行目で再コンパイルのために一旦実行ファイルを削除します。実際にはこの部分は make clean によって行われることが多いのではないかと思います。
5 行目で最終的な実行ファイル foo を生成させます。この foo は実行時のプロファイルデータの情報による最適化が行われたものとなります。
姫野ベンチを実行した時には、-xprofile=collect:bmt を指定してコンパイルし実行させた後に -xprofile=use:bmt を指定して再コンパイルを行ったところ、再コンパイルされた実行可能ファイルのパフォーマンスの向上は約 1 - 2 % でした。あまり大きな効果は出ていません。何度か計測した中では -xprofile オプションの指定によってパフォーマンスが低下した計測値も出ています。姫野ベンチのプログラムではソースコードの解析に基づく最適化に実行時のプロファイルデータを加味しても、最適化そのものに大きな変更は加えられなかった。別の言い方をすれば、実行時プロファイルデータによる最適化はあまり (もしかしたらほとんど) 行われなかった。ということだと思います。analyzer(1) を使って逆アセンブリの結果を見てみましたが、処理の流れに違いは見られませんでした。データ配置にはもしかしたら変更が加えられたかもしれません。
姫野ベンチの場合には実行時プロファイルデータによる効果はさほど現れませんでしたが、プログラム内部の処理の流れによっては、-xprofile を使用した実行時プロファイルデータの使用によって効果的な最適化が行われ、最終的なパフォーマンスの向上に効果を及ぼす場合があると思っています。以前、最新 CPU アーキテクチャへの対応についてのエントリで参考資料として挙げたインテルや AMD の最適化に関する説明内にも「もっとも積極的な (most aggressive)」最適化オプションの一部として -xprofile オプションが使用されています。
Posted by keiichio
( 3月 17日 2008年, 03:41:07 午後 JST )
Permalink
投稿されたコメント [0]
NetBeans 6.0.1 日本語ドキュメントの一覧ページ
Sun 社内で進んでいた NetBeans 6.0.1 のドキュメントの翻訳作業が終わったので、今現在 Web サイト上にある 6.0.1 向けの全日本語ドキュメントへのリンクを集めて、見出しページを作りました:
http://ja.netbeans.org/docs/60/1/index.html
このページからリンクされているドキュメントには、Sun の翻訳したページだけではなくて、日本語サイトのプロジェクトメンバーが訳してくれたページへのリンクも含まれています。
すべての 6.0.1 向けのドキュメントを訳すことはできなかったので、まだ英語のまま残っているものもあります。暫定的なページですが、現在英語のまま残っているドキュメントはこのページにあります:
http://wiki.netbeans.org/TFNB6WebDocNotTranslatedYet
あらためて日本語サイトプロジェクト内で呼びかけがあるかもしれませんが、興味をもっている分野のドキュメントが英語のままで、調査もかねて翻訳してみようと思われたかたは、ぜひご連絡ください。詳しくは以下の wiki ページで説明されています。
http://wiki.netbeans.org/JaNetBeansTutorialTrans
プロファイラ関連のドキュメントが訳されていないのが残念 ... って他人事のように言える立場ではないのですが、プロジェクトはすでに 6.1 に軸足を移してしまっているので、コミュニティのメンバーとして自分で訳すかな、と思い始めているところです。
Posted by keiichio
( 3月 13日 2008年, 07:07:17 午後 JST )
Permalink
投稿されたコメント [0]
Sun Studio 12, cc で SIMD 命令の使用を指定する (自動ベクトル化)
以前のエントリで、姫野ベンチを色々なコンパイルオプションを使ってコンパイル/実行してみました。そこで実行した中で一番成績が良かったのは以下のオプションでした。このエントリでは以下のオプションの中の -xvector=simd について見ていきたいと思います。
-DMIDDLE -fast -m64 -xvector=simd -xprofile=use:bmt
-xvector=simd
この指定によって SIMD 命令の生成が行われます。gcc 等で「自動ベクトル化」と説明される機能と同等で、ループを解析して可能であれば SIMD 命令を使ってベクトル演算をするようにコンパイルします。2007 年 11 月の Sun Tech Days 東京での Sun Studio のセッションでは以下のように、左のループが右のループに変換される例が説明されていました:
for (i=0; i<1024; i++) for (i=0; i<1024; i+=4) c[i] = a[i] * b[i] =====> c[i:i+3] = a[i:i+3] * b[i:i+3]
この例で説明しているのは、SIMD 命令が 1 回の実行で 4 つのデータを同時に取り扱うことができるという前提で、左のループでループ 4 回分に相当する処理が右のループでは 1 回で済み、その結果ループの回数 (命令の実行回数) が削減され、実行速度の向上が見込まれる。というものです。
「SIMD 命令によって、左のループで 4 回分に相当する処理が右のループでは 1 回で済む」という部分を具体的に見てみるために、手元の姫野ベンチをコンパイルして、Sun Studio 12 のアナライザ analyzer(1) でアセンブラを見てみたところ、C ソースの 215 行目の積を演算する部分で以下のコードが現れていました
... [215] 80552bf: movlps 0x1050804(%esi),%xmm1 [215] 80552c6: movhps 0x105080c(%esi),%xmm1 [215] 80552cd: movlps 0x408(%ebx),%xmm6 [215] 80552d4: movhps 0x410(%ebx),%xmm6 [215] 80552db: mulps %xmm6,%xmm1 ...
movlps、movhps はインテルのデベロッパーズガイドでそれぞれ以下のように説明されていました
上記の 80552bf, 80552c6 で xmm1 に、80552cd, 80552d4 で xmm6 にそれぞれ 4 つの単精度浮動小数点値が用意されて、80552db で mulps によって 4 つの積が一度に求められています。コンパイルされたすべてのアセンブラを読んで理解できたわけではないので、ピンポイントで「これがそうかな?」と理解しているに過ぎませんが、局所的には確かに:
「1 回の積の演算で 4 つのデータが処理されている」
ということになります。これによるパフォーマンスの向上が今回の計測結果で現れたようです。-xvector=simd オプションの有無で比較すると約 2 - 4 % の向上です。わずかな向上ではありますが、元のコードにまったく手を加えることなく試みることができるパフォーマンス向上のための手段と言うことで、検討する価値はあるように思えます。
-xvector=simd を指定しないでコンパイルした場合には、同じ行は mulss (Multiply Scalar Single-Precision Floating-Point Values) によって積が求められていたので、-xvector=simd の有無で明らかに演算方法は異なっていました。
-xvector=simd を使用する際には -xdepend を同時に指定してループの分析を行う必要がありますが、-xdepend を指定せずに -xvector=simd を指定した場合にはコンパイラが自動で -xdepend を指定してコンパイルを実行します。
Sun Tech Days 東京のセッションでは、-xautopar による自動並列化よりは効果は少ないと説明されていました「SPECfp 2006 で 3% の向上、個々の部分で 1 - 7 % 程度の向上」。-xautopar による自動並列化については別の機会に見てみたいと思います。
参考:
Posted by keiichio
( 3月 11日 2008年, 11:23:58 午前 JST )
Permalink
投稿されたコメント [0]
NetBeans 6.1 Beta がリリースされました。英語版のみのリリースですが、6.1 で予定されている新機能を試すことができます。
NetBeans 日本語サイトと、メーリングリスト上でお知らせするために、リリース情報のページを翻訳して web サイトに上げました、新機能についての参考にしてください。
http://www.netbeans.org/community/releases/61/index_ja.html
このページを最初に公開したときには Spring が Sprint だったり、一通り読み返してからサイトに commit したつもりなのですが、全然ダメでした。メーリングリストで、間違いを指摘して頂いてホントにありがたかったです。
Posted by keiichio
( 3月 07日 2008年, 06:06:48 午後 JST )
Permalink
投稿されたコメント [0]
Sun Studio 12 の最新 CPU アーキテクチャへの対応
前のエントリの続きで、Sun Studio 12 の最新 CPU への対応について調べました。結論から言うと、Sun Studio 12 で最新の x86 CPU への対応は行われていました。ただし Sun Studio 12 にパッチを適用する必要があります。
最新の Sun Studio 12 パッチについては、以下の URL を参照してください。
http://developers.sun.com/sunstudio/downloads/patches/ss12_patches.jsp"
このエントリーで最新の x86 CPU と言っているのは以下の 2 つです。
上記のそれぞれへの対応とは、明確な部分としてはそれぞれのアーキテクチャで拡張された命令セットへの対応が挙げられます (SSSE3 および SSE4A)。内部的なそれ以外の部分への対応も行われているのではないかと思います。これらのマシンのいずれかが手元にあるかたは、ぜひ Sun Studio 12 に最新パッチを適用して以下のフラグのいずれかを試してみてください。
-xtarget=native # コンパイルを実行するマシンに合わせて最適化 -xtarget=native64 # 同上。64bit コンパイル。 -xtarget=woodcrest # インテル Core アーキテクチャ -xtarget=barcelona # AMD クアッドコア Opteron
-xtarget=woodcrest または -xtarget=barcelona を使用する場合には、-m64 を付けることで 64bit コンパイルが行われます。付けない場合には 32bit コンパイルが行われます。
例: $ cc -c -xtarget=barcelona -m64 foo.c -o foo.o
参考資料
すべてがまとまった資料が Sun のサイトから参照できれば良かったのですが見つかりませんでした。各 CPU メーカーからの資料がわかりやすかったです。
Posted by keiichio
( 3月 05日 2008年, 04:49:14 午後 JST )
Permalink
投稿されたコメント [0]
Sun Studio Express 02/08 がリリースされました
Sun Studio Express 02/08 (2008 年 2 月版) がリリースされました。
ダウンロードは以下のページから行えます。メールアドレスの入力を求められます。
http://developers.sun.com/sunstudio/downloads/express/
Sun Studio Express とは、新機能を評価するための先行リリースで、今現在リリースされている Sun Studio 12 に開発中の新機能が加えられたものです。
| Sun Studio 12 | Sun Studio Express 02/08 | |
|---|---|---|
| 位置づけ | 正式リリース | 評価用先行リリース |
| 対応プラットフォーム | Solaris, Linux | Solaris, Linux |
| 価格 | 無償 | 無償 |
| 日本語化 | 日本語化済み | していません |
今回の Studio Express 02/08 で加えられた新機能は以下の URL で見ることができます。
http://developers.sun.com/sunstudio/downloads/ssx/readme.html
製品の最新プロセッサーアーキテクチャへの対応は、どちらの製品であっても行われていると思っていたのですが、Sun Studio の英語版のトップページにある Express 02/08 の紹介で「..., updated compilers and optimized code generation (e.g. SSSE3)」と書かれているのを気にしています。インテルの Core アーキテクチャで追加された SSSE3 については、Express 02/08 のみ対応? パッチをあてれば Sun Studio 12 であっても大丈夫と思っていたのですが ... 調べます...
ちなみに、AMD クアッドコア Opteron (コードネーム: Barcelona) については、両方とも対応しています。-xtarget=barcelona というコンパイラオプションが使えます。
$ cc -c -xtarget=barcelona foo.c -o foo.o
Posted by keiichio
( 3月 03日 2008年, 06:02:36 午後 JST )
Permalink
投稿されたコメント [0]
DoJa-5.1 プロファイル向け i アプリ作成ツールと NetBeans 6.0.1 の連携
片貝さんたちとともに NetBeans の紹介をする 2 月の Java Hottopic セミナー で NetBeans のモバイル開発機能に関する話をするので、そのための下調べとして DoJa - 5.1 プロファイル向け i アプリ作成ツールと NetBeans 6.0.1 の連携を試してみました。
DoJa-5.1プロファイル向けiアプリ作成ツールは以下の URL からダウンロードすることができます:
http://www.nttdocomo.co.jp/service/imode/make/content/iappli/about/tool_foma5_1.html
大まかな手順は
これで、DoJa 向けプロジェクトを NetBeans から作成し、エミュレーター上で実行することができます。途中ビルド用のプロパティファイルの変更が必要ですが、それ以外は特に特別な設定は必要ありませんでした。以下に具体的な手順を説明します。
インストール
インストール先はデフォルトのディレクトリ C:\iDKDoJa5.1\ を使用しました。インストールオプションとしては「カスタム」を選択し、
を選択しました。インストール中に、モジュールのインストール先と、NetBeans のアップデートセンターでインストールする旨を説明するダイアログが表示されました。その時にモジュールのインストール先を控えておきます。私の場合は: c:\iDKDoja5.1\plugin
作成ツールの実行
インストールされたので一度作成ツールを起動して操作してみましたが、すぐに NetBeans の設定をしてしまっても良いと思います。
NetBeans 6.0.1 にプラグインをインストール
NetBeans 6.0.1 でメインメニューから「ツール」>「プラグイン」を選択し、「ダウンロード済み」タブを選んで「プラグインの追加」をクリックします。先ほど控えたプラグインのインストール先を選択します。私の場合は: c:\iDKDoJa5.1\plugin/org.netbeans.modules.iappli.nbm
選択すると「コミュニティ貢献プラグイン」として表示されます。
インストールをクリックしてインストールします。ここで「妥当性検査の警告」ダイアログが表示されます。プラグインの作成時に署名が埋め込まれていない場合にこの警告が表示されます。ダウンロード元およびプラグインの動作などが明確な今回の場合には全く問題ありませんので、そのまま「継続」をクリックしプラグインのインストールを完了させます。インストール済み」タブを選択すると DoJa-5.1 が表示されるはずです。
プロジェクトの作成
インストール後は「新規プロジェクト」ウィザードに「DoJa」カテゴリと「DoJa-5.1 プロジェクト」が追加されるので、それを選択することで DoJa 向けのプロジェクトを作成することができます。
クラスの作成
実際に実行させてみるにはクラスを一つ作成する必要があります。手っ取り早いのは作成ツールが生成してくれるスケルトンコードを、NetBeans で作成したクラスにペーストする方法です。とりあえず動かしたかったので添付のようなクラスを mypacakge というパッケージに作りました。サンプルクラスファイル
Jam ファイルの編集
Jam ファイルにクラス名とアプリケーション名を記述します。「ファイル」タブを選択し bin/DoJaProject1.jam を開きます。ここでの DoJaProject1 というのは私の作成したプロジェクト名ですので、実際の Jam ファイル名はこれとは異なります。この Jam ファイルを開きアプリケーション名は自由に定義します。AppClass には最初に起動するクラスを記述します
AppName = DoJaProject1 AppClass = mypackage.MyClass
プロパティファイルの変更
あとは実行なのですが、プロパティファイルの変更を行わないと実行することができません。「ファイル」タブを選択し nbproject/doja.properties を開き doja.ant.classpath を以下のように変更します
元々は以下の定義が一行で記述されています (説明用に "\" を付けて改行を挿入しました)
doja.ant.classpath=${user.home}/.netbeans/4.1/modules/org.netbeans.modules.iappli.jar:\
${user.home}/.netbeans/5.0/modules/org.netbeans.modules.iappli.jar:\
${user.home}/.jstudio/Ent8/modules/org.netbeans.modules.iappli.jar:\
${user.home}/.jstudio/Ent81/modules/org.netbeans.modules.iappli.jar
これを以下のようにプラグインのインストールディレクトリを指定するようにします。
doja.ant.classpath=${user.home}/.netbeans/6.0/modules/org.netbeans.modules.iappli.jar
実行
IDE から実行させると、作成ツールに含まれるエミュレーターが起動しアプリケーションが実行されます。
Posted by keiichio
( 2月 18日 2008年, 04:36:19 午後 JST )
Permalink
投稿されたコメント [0]
NetBeans 6.0.1 がリリースされました。
http://ja.netbeans.org/downloads/index.html
最後の最後にダウンロードサーバーにトラブルが発生するという、経験したことのない自体にみまわれましたが、無事リリースできました。いやはやドキドキしました。
引き続きドキュメントの日本語版を順次公開していくという作業が続きます。今現在揃っているものについては http://ja.netbeans.org に一覧を作ったのですが、まだ概要ページしか準備できていません。今のころ、2 月末、3 月初旬、3 月半ば、の 3 回のタイミングで日本語ドキュメントを公開していく予定です。
今回のリリースでは http://ja.netbeans.org のメーリングリスト から、たくさんのコメントをよせていただくことができました。日本語 UI に反映できたもの、6.0.1 で修正が行われたもの、6.1 で修正となったものなど色々あります:
次のリリースでもリリース前に様々なコメントがもらえて、今回以上に製品に実際に反映することができればと思っています。
Posted by keiichio ( 2月 08日 2008年, 02:47:39 午後 JST ) Permalink 投稿されたコメント [1]
Sun Studio 12 C コンパイルオプションと姫野ベンチ
以前のエントリで Sun Studio 12 の -fast オプションに関連して、-xregs=frameptr オプションによる、フレームポインタレジスタを汎用レジスタとして使用する場合についてちょっと言及しました。このオプションによるプログラムの実行速度の違いを調べるために、「姫野ベンチ」を使ってみることにしました。姫野ベンチについてはリンク先の説明を参照してください。と言うか、リンク先の説明以上のことはできないです ...
まずは単にコンパイルして実行してみました
マシン
| CPU | 2 次キャッシュ | メモリ |
|---|---|---|
| AMD Opteron 250 (2.4GHz) x2 | 1 MB | 3326 MB |
結果 (5 回計測した中央値)
| コンパイルオプション | 結果 (MFLOPS) |
|---|---|
| -DMIDDLE -fast -m64 | 942.156648 |
| -DMIDDLE -fast -m64 -xregs=no%frameptr | 960.605658 |
... フレームポインタレジスタを本来の目的で使用した方が良いスコアが出ました ... ただ、5 回計測した中の最大値、最小値についてはほとんど差が出ていません。また、5 回すべてでフレームポインタレジスタを汎用レジスタとして使用した場合には遅くなるかというと、そうではありません。これは有意な差とは言えないような気がしています。今回の環境でのこのプログラムについては、フレームポインタレジスタの取り扱いは実行速度に影響を及ぼさない。と言えそうです。
他にも気になるコンパイルオプションがあったので、今回の計測時に一緒に試しました。すべての結果は以下の通りです。
結果 (5 回計測した中央値)
| コンパイルオプション | 結果 (MFLOPS) |
|---|---|
| -DMIDDLE -xtarget=native64 -xO5 | 909.317671 |
| -DMIDDLE -xtarget=native64 -xO5 -xvector=simd | 930.913117 |
| -DMIDDLE -xtarget=native64 -xO5 -xvector=simd -xprofile=use:bmt | 915.097250 |
| -DMIDDLE -fast -m64 | 942.156648 |
| -DMIDDLE -fast -m64 -xregs=no%frameptr | 960.605658 |
| -DMIDDLE -fast -m64 -xvector=simd | 983.480853 |
| -DMIDDLE -fast -m64 -xvector=simd -xprofile=use:bmt | 998.006062 |
-xvector=simd とは、SIMD 命令 (SSE) を使用を指示するためのオプションです。
-xprofile=use は、一旦プロファイル用のデータを収集し、そのデータを使用してコンパイルを行うためのものです。今回の計測時には -xprofile=collect オプションでコンパイルした実行形式を 5 回の実行し、5 回の実行結果をプロファイルデータとして使用しています。
色々と知りたいので、引き続きソースコードを読むなどしていきたいと思っています。
Posted by keiichio
( 11月 05日 2007年, 12:29:09 午後 JST )
Permalink
投稿されたコメント [0]
NetBeans 6.0 の Beta 2 が昨晩リリースされました。
日本語サイト のトップページを更新したところです。リリース情報のページ も更新されています。
ダウンロードはこちらから
http://download.netbeans.org/netbeans/6.0/beta2/
リリーススケジュール上では、次のターゲットは 11 月 3 日のコードフリーズで、その次は 11 月 12 日の RC1 リリースです。
Posted by keiichio
( 10月 23日 2007年, 01:38:11 午後 JST )
Permalink
投稿されたコメント [0]
Java HTML Parser 2.0 に関するつづき。使った部分の Java コードを抜粋。
前回お話しした HTML Parser 2.0 についてもう少し
<head> タグ内でいくつかのタグの操作をするのですが、一番行いたかった処理は charset 属性の追加です。
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
というタグを追加することが目的でした。すでに既存の charset 属性がある場合には、それを "UTF-8" で上書きする必要がありました。以下は <meta> タグを追加する部分です charset 属性は String クラスのインスタンス charset を使用しています。
// charset 属性を持った <meta> タグを作成
tn = new TagNode();
tn.setTagName("meta");
tn.setAttribute("http-equiv", "\"content-type\"");
tn.setAttribute("content", "text/html; charset=" + charset);
// <head> タグ内の既存のすべての子ノードを取得
nl = head.getChildren();
// <head> タグが空 (すなわち <head></head>) の場合、
// 改行コード一つ持ったテキストノードを足す
if (nl == null) {
nl = new NodeList();
nl.add(new TextNode("\n"));
}
// 新しく作った <meta> タグを先頭に挿入
nl.prepend(tn);
nl.prepend(new TextNode("\n")); // insert newline after <head>
タグを追加しているところだけを抽出すると、別段どうということもない処理です TagNode() クラスを生成して属性をセットした後に、あらかじめ準備しておいた <head> ノードのツリーに挿入しています。ノードツリーは Node クラスの getChildren() メソッドによって NodeList クラスとして取得できます。このノードリストクラスに add() メソッドや remove() メソッドがあり、ここでは prepend() メソッドを使っています。このメソッドは引数として渡した TagNode クラスを先頭に挿入してくれます。
<head> や <body> ノード準備は、私の作ったクラスのコンストラクタ内で行っています。この部分は Parser クラスの elements() メソッドで説明されているサンプルコードを下敷きにしました。基本的な作りは全くそのまま使いました。リンクのサンプルコードでは URL を Parser クラスの引数として与えていますが、これをファイルパスにすれば手元のファイルを開いてパースするコードになります。
いくつか気づいた点
1. MetaTag クラスが用意されていたが使わなかった
一番最初のコードの部分では TagNode クラスを作って、そのタグ名を "meta" に指定しています。MetaTag クラスが準備されているので new MetaTag() とすれば良さそうだったのですが <METAHTTP-EQUIV...> という具合にタグ名の後に属性名が空白無しで続いてしまったので使うのをやめました。使い方が悪かったのか HTML Parser 2.0 のバグなのか調べてないです。
2. テキストノードの isWhiteSpace() メソッドが使えるかと思ったけど、期待した動作とは違った
charset の挿入処理とは別の部分で、テキストノードが空白文字のみで構成されているかどうかを知る必要があり TextNode に isWhiteSpace() というメソッドを見つけて「これは好都合」と思ったのですが、期待通り動きませんでした。「空白文字のみなら true」だと思っていたら、「空白文字を含んでいたら true」と動くように見えました (それってほとんどすべてのテキストノードで true じゃないのか?)。これでは使えないので java.util.regex.Pattern を使いました。
private Pattern whiteSpaces;
...
whiteSpaces = Pattern.compile("^\\s+$");
...
// 空白文字のみの場合は if 文の中に入らない
// tn は TextNode クラスのインスタンス
// TextNode クラスの getText() メソッドでテキストが取得できます
if (!whiteSpaces.matcher(tn.getText()).matches()) {
...
}
...
3. <html>、<body>、<head> タグを追加したときは setStartPosition("0") を実行する必要があった
今回の処理では、入力ファイルが <head> タグや <body> タグを持たないものがあったので、必要に応じてそれらを追加しましたが普通に追加しても追加したノードが最終結果 (私の場合は標準出力) に出てきませんでした。以下の部分は <head> タグを新たに作って <html> タグの子ノードとして追加しています。あたらに作った <head> タグには、一つの改行コードだけを持ったテキストノードを追加しています ( <head></head> というように一行になってしまうのがイヤだったので)。
/**
* Create <head> if it does not exist, and add <head> node into
* the <html> node.
*/
if (head == null) {
// まずは空っぽの <head> ノードを作る
HeadTag ht = new HeadTag();
ht.setTagName("head");
// 一つの改行コードだけを持ったテキストノードを作る
nl = new NodeList();
nl.add(new TextNode("\n")); // add newline after
tn = new TagNode(); // add tag
tn.setTagName("/head");
nl.add(tn);
// 作ったテキストノードを <head> の子ノードとする
ht.setChildren(nl);
// <html> ノードに作った <head> ノードを追加
nl = html.getChildren();
nl.prepend(head = (Node) ht);
nl.prepend(new TextNode("\n")); // add newline after >html>
// この行がイマイチわかっていない
head.setStartPosition(0);
}
最後の setStartPosition(0); という部分が、じつはよくわかっていないまま挿入してあります。こうすると最終結果に追加したノードが現れるのですが、この行がないと現れません。デバッグすると "0" としてここで設定している値は、"0" を設定しない限り "-1" になっています。
先のエントリでお話ししたとおり、この HTML パーサーはテキストの書式をすべて保持してパースしてくれるので、上記のコードを用いて charset 属性を持った meta タグを追加しても、他の部分の書式は (行頭の空白も含めて) まったく変更されません。これを実現するためなのか、各ノードにはテキストの開始位置が格納されています。あらたにノードを作ったら、その開始位置を "0" に指定しないと現れないようです。でもこれは <html> タグ、<head> タグ、<body> タグの場合だけで、<meta> タグを足した時には必要ありませんでした ... いまだ理解が足りないようです。
参考
Posted by keiichio
( 10月 16日 2007年, 12:18:19 午後 JST )
Permalink
投稿されたコメント [1]
Java HTML Parser 2.0 を使ったプロジェクトと NetBeans
最近、HTML ファイルを少しだけ加工するためのプログラムを作る必要があり、HTML Parser 2.0 を使って、<head> 内の meta タグをしらべて必要に応じて挿入する処理を書きました。この HTML Parser を選んだのは、
というのも確かに大きな理由なのですが、使い方がイマイチ把握できずに他のパーサーに切り替えようかと悩んだりしても結局使い続けたのは、
という理由が大きいです。処理されたファイルを元のファイルと比較して、予期せぬ変更が一切無いことの確認を比較的簡単に行うことができました。
書式が大幅に変わっても構文エラーが無ければ確かにそれで良いのですが、元のファイルの書式が様々で、head タグの無いものや、極端な場合は html タグが無い単なるテキストに対して元のテキストを html タグと body タグで囲んだ上で、head タグを追加して meta タグを挿入する必要があるものもあったので、実際にファイルを変換させた後に全部のファイルについて返還後にファイルがどう変わったのか元ファイルと比較したいと思っていました。比較が簡単にできることが大事だったので、もとの書式を維持してくれたのは非常にありがたかったです。diff コマンドで比較してなんとかなりました。
NetBeans のウィザードでプロジェクトを作って、ライブラリマネージャーに HTML Parser 2.0 のコンパイル済み jar ファイルと、ソースファイルの zip、javadoc のディレクトリを追加して作業をしました。javadoc を登録しておいたのでコード補完の時にドキュメントの内容が表示されて楽チンだったのですが、プロジェクトディレクトリを tar でまとめて別の場所で開いたときにライブラリが参照ができなくなりました。参照を解決するのは簡単なのですが、開くたびにライブラリ参照を解決する必要があるのもあまり良くないですし、最終的には Subversion なり CVS を介して他のメンバーとファイルを共有するので、このままではうまくありません。
ライブラリ参照の情報を最初にプロジェクトを作った環境に依存しない形で保持したいのですが、今のところ良い方法が思いつかず、Ant スクリプトを作った上で NetBeans から「既存の Ant スクリプトを使用する Java プロジェクト」として開くように変更しているところです。
Posted by keiichio
( 10月 12日 2007年, 06:21:34 午後 JST )
Permalink
投稿されたコメント [0]
Sun Studio 12, cc, -fast オプション
一年ほど前に、Sun Studio 11 の -fast オプションについてのトピックを書いたので、今回は Sun Studio 12 について、同様の内容を見てみたいと思います。
SPARC 版の C コンパイラでは -fast に関する更新はありません。Sun Studio 12 と Sun Studio 11 では同じオプションに展開されます。具体的にどのオプションに展開されるのかについては、以下のオプション等で確認できます
$ cc -c -fast myprog.c -###
x86 版の C コンパイラでは -fast に変更が加えられています。Sun Studio 12 では、-xregs=frameptr が指定されるようになりました。-fast は以下のオプションに展開されます (Solaris, と Linux で同じオプションに展開されます)。
-fns -nofstore -fsimple=2 -fsingle -xalias_level=basic -xbuiltin=%all -xdepend -xlibmil -xlibmopt -xO5 -xregs=frameptr -xtarget=native
もし、Sun Studio 11 で -fast を指定してコンパイルしてみたものを Sun Studio 12 で同様に -fast を指定すると、-xregs=frameptr 付きでコンパイルされるか否かの違いが生じます。
-xregs=frameptr
このオプションは x86 アーキテクチャのフレームポインタレジスタを汎用レジスタとして扱うように指定します。そうすることでパフォーマンスが向上することがある、とマニュアルに書いてあり、実例は思いつかないですが使えるレジスタが増えるわけですから、パフォーマンスを向上させる方向に働くというのはに納得はできます。汎用レジスタとして使用することによってフレームのアドレスが保持されなくなるので、DTrace やパフォーマンスアナライザ等のスタックを調べてプログラムの動作を追跡するツールの動作に悪影響を及ぼすというマニュアルの説明についても、その通りなのでしょう ... 実際にこのプログラムではこうだった、と報告できるのが一番良いのですが、想像になってしまうのがつらいところです。何か試して報告できるか、やってみます。
Posted by keiichio
( 10月 09日 2007年, 06:59:07 午後 JST )
Permalink
投稿されたコメント [0]
GDB を使用する時の GUI デバッガとして、NetBeans C/C++ Pack
NetBeans 5.5.1 の時点から日本語版が提供されている C/C++ Pack ですが、5.5.1 では NetBeans に追加する形式のインストーラーだったのが、6.0 では C/C++ 機能のみを持った IDE がインストールされる C/C++ Pack として提供されています。6.0 Beta 1 または開発ビルドに片貝さんが提供してくださった 5.5.1 の日本語ファイルを追加すれば、ほとんどの部分が日本語表示されます。
C/C++ Pack を使用するには、マシンにあらかじめ
gcc、GDB がインストールされている必要があります。gcc でコンパイルし、GDB でデバッグする作業を IDE から行うことができるのが NetBeans C/C++ Pack です。この C/C++ Pack を GUI デバッガとして使うのは悪くないと思います。例えば、
ソースの編集は emacs や vi 。make を実行したらデバッグするときは NetBeans C/C++ Pack
という使用方法です。IDE の GUI 上でステップ実行させたり、あるいはブレークポイントの設定やローカル変数の内容を参照ができます。
プログラミングを長いこと行っている方々は、きっとよく使うエディタは決まっているのではないかと思います。仕事がらプログラミングはさっぱり行わない私ですが、それでも時々読んだり書いたりすることがあり、その際には vi を使います。Java の場合には NetBeans のエディタが 6.0 で従来に増して高機能になったので、vi ではなくて NetBeans のエディタを使ってますが、C のソースを見たり書いたりするときは、やっぱり vi に戻ってしまいます ... 。でも、デバッグは IDE が断然便利だと思います (好みの問題ではありますが)。Solaris 上で動くプログラムを作ることが殆どですので、Sun Studio を GUI デバッガとして使い、編集は vi でというのが私のパターンですが、コンパイラとして日々 gcc を使い、GDB を使ってデバッガしている方々からみて、エディタは今現在使用しているものをそのまま使って、デバッグは NetBeans C/C++ Pack 上で...。というのはどうなんでしょう? emacs で全部できるからいらない、あるいは単体の GDB で十分。となるのでしょうか。もしかして Eclipse CDT? Eclipse CDT はデバッガはどうなってるんだろう...
GDB を使ったデバッグを GUI 上で行うツールとして NetBeans C/C++ Pack を試してみるのも悪くないのではないかと思い、こんなことを書いてみました。とは言え、まずは言っている本人がもっと使わないと ... Solaris でも Linux でも GDB でなくて dbx ばかり使っているので、dbx を使うなら Sun Studio だし ... いやいや、なるべく使うようにします。
Posted by keiichio
( 10月 04日 2007年, 07:17:20 午後 JST )
Permalink
投稿されたコメント [0]