14

無線関連のデバイスを監視するための比較的大きなシステム (これまでのところ最大 25000 回線) があります。最新版のZedGraphを使ってグラフなどを表示します。プログラムは、Win7 の VS2010 で C# を使用してコーディングされています。問題は:

  • VS 内からプログラムを実行すると、実行速度が遅くなります
  • ビルドした EXE からプログラムを実行すると、実行速度が遅くなります
  • Performance Wizard / CPU Profiler でプログラムを実行すると、Blazing Fast が実行されます。
  • ビルドした EXE からプログラムを実行し、VS を起動してプロファイラーを他のプロセスにアタッチすると、プログラムが高速化されます。

プログラムを常に高速で実行したい!

ソリューション内のすべてのプロジェクトは RELEASE に設定され、アンマネージ コードのデバッグは無効、DEBUG および TRACE 定数の定義は無効、コードの最適化 - どちらかを試しました、警告レベル - どちらかを試しました、JIT の抑制 - どちらかを試しました、要するにすべて試しましたStackOverflow で既に提案されているソリューション - どれも機能しませんでした。プログラムはプロファイラーの外では遅く、プロファイラーでは高速です。プロファイラーを他の関係のないプロセスにもアタッチすると高速になるため、問題は私のコードにあるとは思いません。

助けてください!ビジネスに不可欠なアプリケーションであり、パフォーマンスの問題が許容されないため、どこでも高速であることが本当に必要です...

更新 1 - 8 フォロー

--------------------アップデート1:--------------------

ZedGraph を独自の基本的な図面に置き換えた後も問題が発生するため、問題は ZedGraph に関連していないようです。

--------------------アップデート2:--------------------

仮想マシンでプログラムを実行しても、プログラムの実行は遅く、ホスト マシンからプロファイラーを実行しても高速にはなりません。

--------------------アップデート3:--------------------

ビデオへのスクリーン キャプチャを開始すると、プログラムも高速化されます。

--------------------アップデート4:--------------------

Intel グラフィックス ドライバーの設定ウィンドウ (このこと: http://www.intel.com/support/graphics/sb/img/resolution_new.jpg ) を開いて、ボタンの上にカーソルを常に置いていると、ボタンが光るなどします。 、私のプログラムはスピードアップします!. ただし、GPUz または Kombustor を実行しても速度が向上しないため、GPU でのダウンクロックはありません。安定した 850Mhz のままです。

--------------------アップデート5:--------------------

異なるマシンでのテスト:

-Intel HD2000 を搭載した私の Core i5-2400S では、UI の実行が遅く、CPU 使用率が ~15% です。

- Intel G41 Express を搭載した同僚の Core 2 Duo では、UI は高速に動作しますが、CPU 使用率は ~90% です (これも正常ではありません)。

-専用の Radeon X1650 を搭載した Core i5-2400S では、UI は非常に高速に動作し、CPU 使用率は ~50% です。

--------------------アップデート6:--------------------

単一のグラフを更新する方法を示すコードの抜粋 (は、使いやすくするために をgraphFFTカプセル化したものです):ZedGraphControl

public void LoopDataRefresh() //executes in a new thread
        {
            while (true)
            {
                while (!d.Connected)
                    Thread.Sleep(1000);
                if (IsDisposed)
                    return;
//... other graphs update here
                if (signalNewFFT && PanelFFT.Visible)
                {
                    signalNewFFT = false;
                    #region FFT
                    bool newRange = false;
                    if (graphFFT.MaxY != d.fftRangeYMax)
                    {
                        graphFFT.MaxY = d.fftRangeYMax;
                        newRange = true;
                    }
                    if (graphFFT.MinY != d.fftRangeYMin)
                    {
                        graphFFT.MinY = d.fftRangeYMin;
                        newRange = true;
                    }

                    List<PointF> points = new List<PointF>(2048);
                    int tempLength = 0;
                    short[] tempData = new short[2048];

                    int i = 0;

                    lock (d.fftDataLock)
                    {
                        tempLength = d.fftLength;
                        tempData = (short[])d.fftData.Clone();
                    }
                    foreach (short s in tempData)
                        points.Add(new PointF(i++, s));

                    graphFFT.SetLine("FFT", points);

                    if (newRange)
                        graphFFT.RefreshGraphComplete();
                    else if (PanelFFT.Visible)
                        graphFFT.RefreshGraph();

                    #endregion
                }
//... other graphs update here
                Thread.Sleep(5);
            }
        }

SetLineは:

public void SetLine(String lineTitle, List<PointF> values)
    {
        IPointListEdit ip = zgcGraph.GraphPane.CurveList[lineTitle].Points as IPointListEdit;
        int tmp = Math.Min(ip.Count, values.Count);
        int i = 0;
        while(i < tmp)
        {
            if (values[i].X > peakX)
                peakX = values[i].X;
            if (values[i].Y > peakY)
                peakY = values[i].Y;
            ip[i].X = values[i].X;
            ip[i].Y = values[i].Y;
            i++;
        }
        while(ip.Count < values.Count)
        {
            if (values[i].X > peakX)
                peakX = values[i].X;
            if (values[i].Y > peakY)
                peakY = values[i].Y;
            ip.Add(values[i].X, values[i].Y);
            i++;
        }
        while(values.Count > ip.Count)
        {
            ip.RemoveAt(ip.Count - 1);
        }
    }

RefreshGraphは:

public void RefreshGraph()
    {
        if (!explicidX && autoScrollFlag)
        {
            zgcGraph.GraphPane.XAxis.Scale.Max = Math.Max(peakX + grace.X, rangeX);
            zgcGraph.GraphPane.XAxis.Scale.Min = zgcGraph.GraphPane.XAxis.Scale.Max - rangeX;
        }
        if (!explicidY)
        {
            zgcGraph.GraphPane.YAxis.Scale.Max = Math.Max(peakY + grace.Y, maxY);
            zgcGraph.GraphPane.YAxis.Scale.Min = minY;
        }
        zgcGraph.Refresh();
    }

.

--------------------アップデート7:--------------------

ANTSプロファイラーを実行しただけです。ZedGraphプログラムが高速な場合の更新回数は、低速な場合に比べて正確に2 倍になることがわかります。スクリーンショットは次のとおりです。 遅いときのANTSのスクリーンショット 高速時のANTSのスクリーンショット

セクションの長さのわずかな違いを考慮すると、パフォーマンスが数学的精度で2倍異なることは非常に奇妙です。

また、GPUドライバーを更新しましたが、役に立ちませんでした。

--------------------アップデート8:--------------------

残念ながら、ここ数日間、問題を再現できません...一定の許容速度を得ています (2 週間前のプロファイラーよりも少し遅いように見えます)。 2 週間前に影響を与えていたすべての要因 (プロファイラー、ビデオ キャプチャ、または GPU ドライバー ウィンドウ)。何が原因だったのか、いまだに解明されていません...

4

5 に答える 5

9

Luaan は上記のコメントに解決策を投稿しました。これは、システム全体のタイマー解決です。デフォルトの解像度は 15.6 ミリ秒で、プロファイラーは解像度を 1 ミリ秒に設定します。

私はまったく同じ問題を抱えていました.プロファイラーが開かれたときにスピードアップする非常に遅い実行. 私の PC では問題は解消されましたが、他の PC では一見ランダムに再表示されました。また、Chrome で Join Me ウィンドウを実行すると、問題が解消されたことにも気付きました。

私のアプリケーションは、CAN バス経由でファイルを送信します。アプリは 8 バイトのデータを含む CAN メッセージをロードして送信し、確認応答を待ちます。タイマーを 15.6 ミリ秒に設定すると、各往復にちょうど 15.6 ミリ秒かかり、ファイル転送全体には約 14 分かかります。タイマーを 1 ミリ秒に設定すると、往復時間は変動しますが、4 ミリ秒まで短くなり、全体の転送時間は 2 分未満に短縮されます。

管理者としてコマンドプロンプトを開き、次のように入力することで、システムタイマーの解像度を確認したり、解像度を上げたプログラムを見つけることができます。

powercfg -energy duration 5

出力ファイルのどこかに次のものが含まれます。

プラットフォーム タイマーの解像度:プラットフォーム タイマーの解像度 デフォルトのプラットフォーム タイマーの解像度は 15.6 ミリ秒 (15625000 ナノ秒) で、システムがアイドル状態のときはいつでも使用する必要があります。タイマーの分解能を上げると、プロセッサの電源管理テクノロジが効果的でなくなる可能性があります。タイマーの解像度は、マルチメディアの再生またはグラフィック アニメーションによって増加する場合があります。現在のタイマー分解能 (100ns 単位) 10000 最大タイマー期間 (100ns 単位) 156001

私の現在の解像度は 1 ミリ秒 (100 ナノ秒の 10,000 単位) で、その後に解像度の向上を要求したプログラムのリストが続きます。

この情報と詳細については、https ://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/ を参照してください。

タイマーの解像度を上げるコードを次に示します (最初は、この質問への回答として投稿されました: how to set timer resolution from C# to 1 ms? ):

public static class WinApi
{
    /// <summary>TimeBeginPeriod(). See the Windows API documentation for details.</summary>

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
    [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]

    public static extern uint TimeBeginPeriod(uint uMilliseconds);

    /// <summary>TimeEndPeriod(). See the Windows API documentation for details.</summary>

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
    [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]

    public static extern uint TimeEndPeriod(uint uMilliseconds);
}

解像度を上げるには、次のように使用します。WinApi.TimeBeginPeriod(1);

そして、このようにデフォルトに戻ります:WinApi.TimeEndPeriod(1);

TimeEndPeriod() に渡されるパラメーターは、TimeBeginPeriod() に渡されたパラメーターと一致する必要があります。

于 2016-07-15T19:48:38.863 に答える
0

似たようなことを聞​​いたり見たりしたことがないとき。副作用を生み出しているロジックが見つかるまで、コードのセクションをコメントアウトする/関数の先頭にリターンを挿入するという常識的なアプローチをお勧めします。あなたは自分のコードを知っており、どこからチョッピングを開始すればよいか、知識に基づいて推測している可能性があります。それ以外の場合は、健全性テストとしてほとんどすべてを切り刻み、ブロックを追加し直します。一見不可能に思えるバグを追跡するのがいかに速いか、私はよく驚かされます。関連するコードを見つけると、問題を解決するための手がかりが増えます。

于 2013-05-20T03:12:08.197 に答える