2017-01-04 12 views
0

基本的には、私のコードで起動されていない外部プロセスの実行時間を計測したいと思います。これを達成するために、私は、特定のプロセスの開始のイベントをサブスクライブし、終了、プロセス名で、(このanswerに基づいて)次のコードを使用しています:プロセスの実行時間に間違った値が入っているのはなぜですか?

private ManagementEventWatcher ProcessStartWatcher(string processName) 
{ 
    string queryString = 
     "SELECT TargetInstance" + 
     " FROM __InstanceCreationEvent " + 
     "WITHIN 1 " + 
     " WHERE TargetInstance ISA 'Win32_Process' " + 
     " AND TargetInstance.Name = '" + processName + "'"; 

    // The dot in the scope means use the current machine 
    string scope = @"\\.\root\CIMV2"; 

    // Create a watcher and listen for events 
    ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString); 
    watcher.EventArrived += ProcessStarted; 
    watcher.Start(); 
    return watcher; 
} 

private ManagementEventWatcher ProcessEndWatcher(string processName) 
{ 
    string queryString = 
     "SELECT TargetInstance" + 
     " FROM __InstanceDeletionEvent " + 
     "WITHIN 1 " + 
     " WHERE TargetInstance ISA 'Win32_Process' " + 
     " AND TargetInstance.Name = '" + processName + "'"; 

    // The dot in the scope means use the current machine 
    string scope = @"\\.\root\CIMV2"; 

    // Create a watcher and listen for events 
    ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString); 
    watcher.EventArrived += ProcessEnded; 
    watcher.Start(); 
    return watcher; 
} 

private void ProcessStarted(object sender, EventArrivedEventArgs e) 
{ 
    this.processStart = DateTime.Now; 
} 

private void ProcessEnded(object sender, EventArrivedEventArgs e) 
{ 
    // use time recorded from ProcessStarted to calculate run duration, write to log file 
    this.logger.addRuntimeData((DateTime.Now - this.processStart).TotalSeconds); 
} 

addRuntimeData(double seconds)方法は次のように定義されます:

public void addRuntimeData(double seconds) 
{ 
    this.runDurations.Add(seconds); 
    if (this.runDurations.Count > Properties.Settings.Default.MaxRunDurationData) 
     this.runDurations.RemoveAt(0); 
    this.updateLog(); 
} 

public void updateLog() 
{ 
    this.logfileDirectory = Properties.Settings.Default.LogfileDirectory; 
    this.logfileFullPath = logfileDirectory + this.task.Name.toValidFilename() + this.logfileExtension; 
    Directory.CreateDirectory(logfileDirectory); // create directory if it does not already exist 
    this.toXElement().Save(this.logfileFullPath); // generate the XML and write it to the log file 
} 

今、私は時間に私が書いたテストプロセスをしようとしていて、すべてのテストプロセスを行うことはConsole.WriteLine("Test process");への単一の呼び出しであるので、記録継続のための適切な値はおおよその範囲0にする必要があります-2秒。

時々、私は適切な値を取得します。63619141321.2978秒のように、文字通り記録できなかった値を取得することがあります。これは、およそ2017.3年に相当します。これは、開始時刻が01/01/0001 00:00:01またはそのようなものとして記録されていることと関連があると私に思います。この問題にこれと関連がある可能性はありますか?

これは私が(たとえば、OSがメッセージをどのように/どのようにトリガーするかと関係がある)問題であれば、これらを明らかに無効にする方法があるデータポイント?

+5

[Bobby Tables](http://bobby-tables.com/)が表示される場合があります。 –

+0

@MattRowland lol rekt savage –

+0

おそらく、 'ProcessStarted'が起動する前に継続時間が記録され、' processStart'が初期化されるためです。 – dbc

答えて

3

ManagementEventWatcherは基本的にポーリングメカニズムであり、非常に短いプロセスの開始イベントの前に終了イベントが取得される可能性があります。開始時刻が一度も初期化されていない場合(デフォルト値は1/1/0001)、記述した内容が表示されます。現実的には、現実的なユースケースではないかもしれませんが、あなたが観察したように起こる可能性があります。私はそれを修正する最良の方法は、プロセスの開始イベントから開始時刻を記録することをやめることです。

合計実行時間を計算するために、process startedイベントを実際に表示する必要はありません。 Win32_Processインスタンスを終了イベントから取得し、CreationDateを使用してプロセスの合計実行時間を計算することができます。私は、TerminationDateがまだ設定されていないことに気づいた。その場合は、終了イベントが発生した現在の時刻を使用します。

+0

'ProcessEnded'イベントが発生したときに' CreationDate'プロパティが設定されることが保証されていますか? –

+0

いずれにせよ、あなたの答えの解は私のユースケースに最適です。正解と表示されます。ありがとう! –

+0

私はそう信じています。 CreationDateは、[Win32_Processクラス](https://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx)で「修正済み」(変更されていないことを意味する)とマークされた唯一のプロパティです)。 –

3

あなたは基本的には01/01/0001 00:00:01です。

DateTimeオブジェクトを作成すると、1/1/0001 12:00:00 AMに開始されます。 processStartは初期化せずに宣言されているため、デフォルトの開始時刻は1/1/0001 12:00:00 AMとなります。私は、ProcessStartが起動される前にProcessEndが起動されていると推測しています。

以下のコードは、記述したのと同じ結果をもたらし、宣言後に変更されないDateTimeを使用します。

private static DateTime date; 

public static void Main(string[] args) { 
    const double largeVal = 63619141321; 

    Console.WriteLine(date.ToString()); 

    double totalSeconds = (DateTime.Now - date).TotalSeconds; 
    Console.WriteLine(totalSeconds - largeVal); 

    Console.WriteLine("Press any key to continue . . . "); 
    Console.ReadKey(true); 
} 
+0

しかし 'processStart'は' new DateTime() 'ではなく' DateTime.Now'として初期化されていますか? –

+0

@ mjones.udri processStartが定義されている行をコメントできますか? –

+0

そのクラスレベルの変数。 'private DateTime processStart;'は、 'ProcessStarted'イベントハンドラが起動するまで初期化されません。コンパイラが暗黙の 'DateTime processStart = default(DateTime);'で追加したクラスレベルで初期化子なしの 'DateTime processStart; 'を宣言すると、' this.processStart = DateTime.Now; ' –

関連する問題