- PR -

[C#] 状況に応じてコンパイルのタイミングを細かく制御したい

投稿者投稿内容
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-09-04 09:32
<背景>
実行時の応答性能を安定させたい。
実行前に全ソースコードのコンパイルを済ませておきたい。
更に、状況に応じてコンパイルのタイミングを細かく制御したい。

Q1.セットアップウィザードにNgen.exeを組み込む方法が最善ですか?
Q2.セットアップウィザードにNgen.exeを組み込む方法が分かりません。
Q3.下記ケース1、2、あるいは3のような操作を使い分けできますか?

<ケース1>
コンパイル方法:起動時に毎回全ソースコードをコンパイルする。
コンパイル時期:起動時(毎回)
利点:ターゲットマシンのCPUに最適化できる。
欠点:起動時間が遅い。

<ケース2>
コンパイル方法:
事前にネイティブコードのファイルを作成しておく。
毎回の起動時にはネイティブコードのファイルを読み込む。
コンパイル時期:事前(1回のみ)
利点:起動時間が速い。
欠点:ターゲットマシンのCPUに最適化できない。

<ケース3>
(※ケース1と2の両方の良さを持つ方法)
コンパイル方法:
起動時にネイティブコードファイルがあるかチェックする。
ネイティブコードファイルが無ければ生成する。
コンパイル時期:起動時(初回のみ)
利点:ターゲットマシンのCPUに最適化できる。起動時間が速い。
欠点:特になし。(初回のみ起動時間が遅い)

宜しくお願いします。
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-09-04 11:03
諸農です。

.NET Framework入門
3.Common Language Runtime(1)
― CLRの内部構造とプログラム実行の流れ ―


を見ると.NET Frameworkのデフォルトの動作がケース3に当てはまりそうな気がします。
意図している事と違うようでしたらご容赦してくださ。

_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-09-04 23:38
ご回答ありがとうございます。
ですが、わたしが意図していた内容とは違っています。
デフォルトでは、アプリケーション終了時にネイティブコードも消失します。
これは下記のような欠点があります。
(1) 毎回起動がとても遅くなる。
(2) 例外処理は応答性能が安定しない。
特に(2)はリアルタイム処理にとっては深刻な問題になり得ます。
main()の実行が開始する時点では全てのコンパイルを済ませておくのが必須です。
Ngen.exeについて言及したのはこのためです。
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-09-05 02:06
諸農です。

参考になるかどうか判りませんが。

JIT Compilation and Performance - To NGen or Not to NGen?

注意点は色々あるようですね。

あと、これは宣伝ページになるのですが、インストールターゲットの
環境別ネイティブイメージのGenerateに使えそうですね。
#Windows専用になるとは思いますが。

How to Add a Native Image Generation
to the Installation Package for a .Net Application


それと私見になりますが、究極のパフォーマンスを必要と考えているの
でしたら、.NETと言う選択肢よりも実行ファイルをCPU別に作成できる
オプション機能を持ったアンマネージドなコンパイラを使った方がいい
かもしれませんね。。

--変な日本語だったので修正しました--

_________________
諸農和岳
Powered by Borland Delphi/C++Builder & Microsoft VS.NET

[ メッセージ編集済み 編集者: Jubei 編集日時 2004-09-05 02:15 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-09-05 17:56
 で、JITコンパイラによって、どれくらい起動パフォーマンスが落ちるのでしょうか?つまり、「どれくらいのコード量の実行ファイルを、どのCPUで、どれくらいのメモリを積んでいるとき、コンパイルに何秒かかる。CPUを変えたとき、メモリ量を変えたとき、どういう関係がある」のか、調査できているのか、ということです。
 それの調査もせずにただ「毎回コンパイルするからユーザの操作性に影響があるほどパフォーマンスが悪い」とするのは、間違っていると思います。我々技術者は、調査による実績を比較することで、判断するべきです。それによって、本当の「コスト・パフォーマンス」を求めるできではないでしょうか。
 つまり、何らかのコードを書くとそれだけコストが上がるわけですが、その労力に見合うだけのパフォーマンス改善が見られるのでしょうか。
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-09-06 09:44
ご回答ありがとうございます。
「起動時のコンパイルにかかる時間を計測し、見合う効果があるか調査すべき」
という点についてはご指摘の通りと思います。
今回は初期化ロジックをボタンに仕込み、
アプリケーションを終わらせずに再実行させることで、
初期化の時間が数分の一に短縮されるのを確認済みです。

製造ラインでリアルタイム制御に使用するプログラムなので
通常のビジネスアプリケーション以上に応答性能の安定性に神経を使います。
応答性能だけを考えるならC++を採用するという選択肢もあると思いますが、
開発生産性、信頼性のことも総合的に考えると、
C#で済ませられるならそれに越したことは無いと実感しています。

どなたかインストール用のプロジェクトにNgen.exeによるネイティブコード
の変換を組み込む方法を教えてくださればありがたいです。
(難しいのでしょうか?)
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-09-06 10:27
引用:

ひろしさんの書き込み (2004-09-06 09:44) より:
アプリケーションを終わらせずに再実行させることで、
初期化の時間が数分の一に短縮されるのを確認済みです。


これってどちらかというと、ネイティブコンパイルの時間じゃなくてCLRの起動の時間の問題じゃないですかね?
ngen.exeを実行していても、この傾向はそうは変わらないんじゃないかと思いますが…
引用:

どなたかインストール用のプロジェクトにNgen.exeによるネイティブコード
の変換を組み込む方法を教えてくださればありがたいです。
(難しいのでしょうか?)


インストール時のカスタムの動作でngen.exeを実行させることができたんじゃなかったですかね?
どこかで見た記憶があるんですが…

と思ったら、こんなのありました。
チュートリアル : カスタム動作を使用して、インストール中にアセンブリをプリコンパイルする
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-09-07 11:51
ご回答ありがとうございます。

チュートリアル : カスタム動作を使用して、インストール中にアセンブリをプリコンパイルする

上記を見ながらC#でプロジェクトを記述してみています。
ソースがVB.NETなのでいくつか分からない部分があります。
アドバイスよろしくお願いします。

C#

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;

namespace InstallClass
{
/// <summary>
/// InstallClass の概要の説明です。
/// </summary>
[RunInstaller(true)]
public class InstallClass : System.Configuration.Install.Installer
{
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;

public InstallClass()
{
// この呼び出しはデザイナで必要です。
InitializeComponent();

// TODO: InitializeComponent 呼び出しの後に初期化処理を追加します。
}

/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
// Private Declare Function GetCORSystemDirectory Lib "mscoree.dll" (<MarshalAs(UnmanagedType.LPWStr)> ByVal Buffer As System.Text.StringBuilder, ByVal BufferLength As Integer, ByRef Length As Integer) As Integer

[DllImport("mscoree.dll")] public static extern int GetCORSystemDirectory(StringBuilder Buffer ,int BufferLength,ref int Length);

public override void Install(IDictionary savedState)
{

base.Install (savedState);
// ***************************************************
// 下記のディクショナリから値を取り出す方法が分からない
// ****************************************************
string Args = this.Context.Parameters.Item("Args");

if(Args == "")
{
throw new InstallException("No arguments specified");
}
// Gets the path to the Framework directory.
StringBuilder Path = new StringBuilder(1024);
int Size;
GetCORSystemDirectory(Path, Path.Capacity,ref Size);
Process P;
// Quotes the arguments, in case they have a space in them.
// **********************************************************
// パタメータの引き渡し方は合っているでしょうっか?
// **********************************************************
ProcessStartInfo Si = new ProcessStartInfo(Path.ToString()+"ngen.exe ", @""""+Args+@"""");
Si.WindowStyle = ProcessWindowStyle.Hidden;
try
{
P = Process.Start(Si);
P.WaitForExit();
}
catch (Exception e)
{
throw new InstallException(e.Message);
}
}
#region コンポーネント デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}


スキルアップ/キャリアアップ(JOB@IT)