27

私の他の質問を読んだことがあれば、私が今週末、プログラミング演習として6502CPUエミュレーターを組み立てるのに費やしたことをご存知でしょう。

CPUエミュレーターはほぼ完成しており、限られたテストからはかなり正確に見えますが、非常に高速に実行されているため、マシンの実際のクロック速度まで抑制したいと思います。

私の現在のテストループはこれです:

    // Just loop infinitely.
    while (1 == 1)
    {                
        CPU.ClockCyclesBeforeNext--;

        if (CPU.ClockCyclesBeforeNext <= 0)
        {
            // Find out how many clock cycles this instruction will take
            CPU.ClockCyclesBeforeNext = CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].CpuCycles;

            // Run the instruction
            CPU.ExecuteInstruction(CPU.Memory[CPU.PC]);

            // Debugging Info
            CPU.DumpDebug();
            Console.WriteLine(CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength);

            // Move to next instruction
            CPU.PC += 1 + CPU.OpcodeMapper.Map[CPU.Memory[CPU.PC]].ArgumentLength;                                        
        }
    }

お分かりのように、各オペコードは完了するまでに特定の時間がかかるため、CPUサイクルクロックをカウントダウンするまで次の命令を実行しません。これにより、オペコード間の適切なタイミングが提供されます。これにより、すべてが高速になります。

目標のCPU速度は1.79mhzですが、複雑さを加えても速度を1.79mhzに維持するために、クロックの問題を解決したいので、調整する必要はありません。

何か案は?

4

7 に答える 7

14

私は何年も前に Z80 エミュレーターを作成しましたが、サイクルを正確に実行するために、クロック レートを多数の小さなブロックに分割し、コアにその数のクロック サイクルを実行させました。私の場合は、エミュレートしているゲーム システムのフレーム レートに関連付けました。各オペコードは実行に必要なサイクル数を認識しており、コアは指定されたサイクル数が実行されるまでオペコードを実行し続けます。CPUコアを実行し、エミュレートされたシステムの他の部分を実行し、次の反復の開始時間までスリープする外側の実行ループがありました。

編集: 実行ループの例を追加します。

int execute_run_loop( int cycles )
{
    int n = 0;
    while( n < cycles )
    {
        /* Returns number of cycles executed */
        n += execute_next_opcode();
    }

    return n;
}

お役に立てれば。

于 2009-05-06T02:08:23.460 に答える
9

インスピレーションについては、元の QuickTime ドキュメントをご覧ください。

これはずっと前に書かれたもので、ビデオを表示するには十分な速度で静止画を交換するだけだったのですが、Apple の担当者は完全な時間管理フレームワークが必要であると判断しました。設計は最初は過剰に設計されているように見えますが、さまざまな速度要件に対処し、それらを緊密に同期させることができます。

幸運なことに、6502 は決定論的な時間動作をします。各命令にかかる正確な時間は十分に文書化されています。しかし一定ではありません。QuickTime のフレームと同様に、ビデオには「1 秒あたりのフレーム数」パラメーターがなく、各フレームは画面に表示される時間を示します。

最新の CPU は非常に非決定論的であり、マルチタスク OS は数ミリ秒 (仮想メモリ!) もフリーズする可能性があるため、予定より遅れている場合や、数マイクロ秒の仮眠を取ることができる場合は、タブを保持する必要があります。

于 2008-09-21T23:01:02.910 に答える
6

jfk が言うように、これを行う最も一般的な方法は、CPU 速度を (エミュレートされた) ビデオ出力の垂直リフレッシュに結び付けることです。

ビデオ フレームごとに実行するサイクル数を選択します。これは多くの場合マシン固有ですが、次のような方法で計算できます。

cycles = clock speed in Hz / required frames-per-second

次に、ビデオの更新がヒットするまでスリープ状態になり、その時点で CPU エミュレーションの次の n サイクルを開始します。

特に何かをエミュレートしている場合は、fps レートとプロセッサ速度を調べて、これをほぼ正しくする必要があります。

編集: 外部のタイミング要件がない場合、エミュレータが可能な限り高速に実行されるのは正常です。これは望ましい効果である場合もあれば、そうでない場合もあります:)

于 2009-09-08T11:45:00.377 に答える
3

私はクロックサイクルを使用して時間を計算し、それらは時間の差をスリープ状態にします。もちろん、これを行うには、高解像度のクロックが必要です。彼らのやり方は、回転ループで CPU を急上昇させます。

于 2008-09-21T23:00:44.473 に答える
0

オーディオ エミュレーションが実装されていて、オーディオ出力がシステム/CPU クロックに関連付けられている場合は、別のオプションを使用できます。特に、これは 8 ビットの Apple ][ コンピュータの場合に当てはまります。

通常、サウンドは固定サイズ (固定時間) のバッファーで生成されるため、これらのバッファーの操作 (データの生成など) は、同期プリミティブを介して CPU スループットに関連付けることができます。

于 2012-11-07T05:40:55.563 に答える
0

私は、時間を命令の推定量に変換する機能やその逆の機能など、もう少し一般的なユースケースに基づいたものを作成中です。

プロジェクトのホームページは @ http://net7mma.codeplex.comです。

コードは次のように始まります:(私は思う)

    #region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/

 Julius.Friedman@gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com)

Permission is hereby granted, free of charge, 
 * to any person obtaining a copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, 
 * including without limitation the rights to :
 * use, 
 * copy, 
 * modify, 
 * merge, 
 * publish, 
 * distribute, 
 * sublicense, 
 * and/or sell copies of the Software, 
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * 
 * JuliusFriedman@gmail.com should be contacted for further details.

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
 * TORT OR OTHERWISE, 
 * ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * v//
 */
#endregion
namespace Media.Concepts.Classes
{
    //Windows.Media.Clock has a fairly complex but complete API

    /// <summary>
    /// Provides a clock with a given offset and calendar.
    /// </summary>
    public class Clock : Media.Common.BaseDisposable
    {
        static bool GC = false;

        #region Fields

        /// <summary>
        /// Indicates when the clock was created
        /// </summary>
        public readonly System.DateTimeOffset Created;

        /// <summary>
        /// The calendar system of the clock
        /// </summary>
        public readonly System.Globalization.Calendar Calendar;

        /// <summary>
        /// The amount of ticks which occur per update of the <see cref="System.Environment.TickCount"/> member.
        /// </summary>
        public readonly long TicksPerUpdate;

        /// <summary>
        /// The amount of instructions which occured when synchronizing with the system clock.
        /// </summary>
        public readonly long InstructionsPerClockUpdate;

        #endregion

        #region Properties

        /// <summary>
        /// The TimeZone offset of the clock from UTC
        /// </summary>
        public System.TimeSpan Offset { get { return Created.Offset; } }

        /// <summary>
        /// The average amount of operations per tick.
        /// </summary>
        public long AverageOperationsPerTick { get { return InstructionsPerClockUpdate / TicksPerUpdate; } }

        /// <summary>
        /// The <see cref="System.TimeSpan"/> which represents <see cref="TicksPerUpdate"/> as an amount of time.
        /// </summary>
        public System.TimeSpan SystemClockResolution { get { return System.TimeSpan.FromTicks(TicksPerUpdate); } }

        /// <summary>
        /// Return the current system time in the TimeZone offset of this clock
        /// </summary>
        public System.DateTimeOffset Now { get { return System.DateTimeOffset.Now.ToOffset(Offset).Add(new System.TimeSpan((long)(AverageOperationsPerTick / System.TimeSpan.TicksPerMillisecond))); } }

        /// <summary>
        /// Return the current system time in the TimeZone offset of this clock converter to UniversalTime.
        /// </summary>
        public System.DateTimeOffset UtcNow { get { return Now.ToUniversalTime(); } }

        //public bool IsUtc { get { return Offset == System.TimeSpan.Zero; } }

        //public bool IsDaylightSavingTime { get { return Created.LocalDateTime.IsDaylightSavingTime(); } }

        #endregion

        #region Constructor

        /// <summary>
        /// Creates a clock using the system's current timezone and calendar.
        /// The system clock is profiled to determine it's accuracy
        /// <see cref="System.DateTimeOffset.Now.Offset"/>
        /// <see cref="System.Globalization.CultureInfo.CurrentCulture.Calendar"/>
        /// </summary>
        public Clock(bool shouldDispose = true)
            : this(System.DateTimeOffset.Now.Offset, System.Globalization.CultureInfo.CurrentCulture.Calendar, shouldDispose)
        {
            try { if (false == GC && System.Runtime.GCSettings.LatencyMode != System.Runtime.GCLatencyMode.NoGCRegion) GC = System.GC.TryStartNoGCRegion(0); }
            catch { }
            finally
            {

                System.Threading.Thread.BeginCriticalRegion();

                //Sample the TickCount
                long ticksStart = System.Environment.TickCount,
                    ticksEnd;

                //Continually sample the TickCount. while the value has not changed increment InstructionsPerClockUpdate
                while ((ticksEnd = System.Environment.TickCount) == ticksStart) ++InstructionsPerClockUpdate; //+= 4; Read,Assign,Compare,Increment

                //How many ticks occur per update of TickCount
                TicksPerUpdate = ticksEnd - ticksStart;

                System.Threading.Thread.EndCriticalRegion();
            }
        }

        /// <summary>
        /// Constructs a new clock using the given TimeZone offset and Calendar system
        /// </summary>
        /// <param name="timeZoneOffset"></param>
        /// <param name="calendar"></param>
        /// <param name="shouldDispose">Indicates if the instace should be diposed when Dispose is called.</param>
        public Clock(System.TimeSpan timeZoneOffset, System.Globalization.Calendar calendar, bool shouldDispose = true)
        {
            //Allow disposal
            ShouldDispose = shouldDispose;

            Calendar = System.Globalization.CultureInfo.CurrentCulture.Calendar;

            Created = new System.DateTimeOffset(System.DateTime.Now, timeZoneOffset);
        }

        #endregion

        #region Overrides

        public override void Dispose()
        {

            if (false == ShouldDispose) return;

            base.Dispose();

            try
            {
                if (System.Runtime.GCSettings.LatencyMode == System.Runtime.GCLatencyMode.NoGCRegion)
                {
                    System.GC.EndNoGCRegion();

                    GC = false;
                }
            }
            catch { }
        }

        #endregion

        //Methods or statics for OperationCountToTimeSpan? (Estimate)
        public void NanoSleep(int nanos)
        {
            Clock.NanoSleep((long)nanos);
        }

        public static void NanoSleep(long nanos)
        {
            System.Threading.Thread.BeginCriticalRegion(); 

            NanoSleep(ref nanos); 

            System.Threading.Thread.EndCriticalRegion();
        }

        static void NanoSleep(ref long nanos)
        {
            try
            {
                unchecked
                {
                    while (Common.Binary.Clamp(--nanos, 0, 1) >= 2)
                    { 
                        /* if(--nanos % 2 == 0) */
                            NanoSleep(long.MinValue); //nanos -= 1 + (ops / (ulong)AverageOperationsPerTick);// *10;
                    }
                }
            }
            catch
            {
                return;
            }
        }
    }
}

ある種の素人クロックの実装ができたら、次のようなものに進みますTimer

/// <summary>
/// Provides a Timer implementation which can be used across all platforms and does not rely on the existing Timer implementation.
/// </summary>
public class Timer : Common.BaseDisposable
{
    readonly System.Threading.Thread m_Counter; // m_Consumer, m_Producer

    internal System.TimeSpan m_Frequency;

    internal ulong m_Ops = 0, m_Ticks = 0;

    bool m_Enabled;

    internal System.DateTimeOffset m_Started;

    public delegate void TickEvent(ref long ticks);

    public event TickEvent Tick;

    public bool Enabled { get { return m_Enabled; } set { m_Enabled = value; } }

    public System.TimeSpan Frequency { get { return m_Frequency; } }

    internal ulong m_Bias;

    //

    //Could just use a single int, 32 bits is more than enough.

    //uint m_Flags;

    //

    readonly internal Clock m_Clock = new Clock();

    readonly internal System.Collections.Generic.Queue<long> Producer;

    void Count()
    {

        System.Threading.Thread Event = new System.Threading.Thread(new System.Threading.ThreadStart(() =>
        {
            System.Threading.Thread.BeginCriticalRegion();
            long sample;
        AfterSample:
            try
            {
            Top:
                System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;

                while (m_Enabled && Producer.Count >= 1)
                {
                    sample = Producer.Dequeue();

                    Tick(ref sample);
                }

                System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;

                if (false == m_Enabled) return;

                while (m_Enabled && Producer.Count == 0) if(m_Counter.IsAlive) m_Counter.Join(0);  //++m_Ops;

                goto Top;
            }
            catch { if (false == m_Enabled) return; goto AfterSample; }
            finally { System.Threading.Thread.EndCriticalRegion(); }
        }))
        {
            IsBackground = false,
            Priority = System.Threading.ThreadPriority.AboveNormal
        };

        Event.TrySetApartmentState(System.Threading.ApartmentState.MTA);

        Event.Start();

        Approximate:

        ulong approximate = (ulong)Common.Binary.Clamp((m_Clock.AverageOperationsPerTick / (Frequency.Ticks + 1)), 1, ulong.MaxValue);

        try
        {
            m_Started = m_Clock.Now;

            System.Threading.Thread.BeginCriticalRegion();

            unchecked
            {
            Start:

                if (IsDisposed) return;

                switch (++m_Ops)
                {
                    default:
                        {
                            if (m_Bias + ++m_Ops >= approximate)
                            {
                                System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;

                                Producer.Enqueue((long)m_Ticks++);

                                ulong x = ++m_Ops / approximate;

                                while (1 > --x /*&& Producer.Count <= m_Frequency.Ticks*/) Producer.Enqueue((long)++m_Ticks);

                                m_Ops = (++m_Ops * m_Ticks) - (m_Bias = ++m_Ops / approximate);

                                System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;
                            }

                            if(Event != null) Event.Join(m_Frequency);

                            goto Start;
                        }
                }
            }
        }
        catch (System.Threading.ThreadAbortException) { if (m_Enabled) goto Approximate; System.Threading.Thread.ResetAbort(); }
        catch (System.OutOfMemoryException) { if ((ulong)Producer.Count > approximate) Producer.Clear(); if (m_Enabled) goto Approximate; }
        catch { if (m_Enabled) goto Approximate; }
        finally
        {
            Event = null;

            System.Threading.Thread.EndCriticalRegion();
        }
    }

    public Timer(System.TimeSpan frequency)
    {
        Producer = new System.Collections.Generic.Queue<long>((int)(m_Frequency = frequency).Ticks * 10);

        m_Counter = new System.Threading.Thread(new System.Threading.ThreadStart(Count))
        {
            IsBackground = false,
            Priority = System.Threading.ThreadPriority.AboveNormal
        };

        m_Counter.TrySetApartmentState(System.Threading.ApartmentState.MTA);

        Tick = delegate { m_Ops += 1 + m_Bias; };
    }

    public void Start()
    {
        if (m_Enabled) return;

        m_Enabled = true;

        m_Counter.Start();

        var p = System.Threading.Thread.CurrentThread.Priority;

        System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;

        while (m_Ops == 0) m_Counter.Join(0); //m_Clock.NanoSleep(0);

        System.Threading.Thread.CurrentThread.Priority = p;

    }

    public void Stop()
    {
        m_Enabled = false;
    }

    void Change(System.TimeSpan interval, System.TimeSpan dueTime)
    {
        m_Enabled = false;

        m_Frequency = interval;

        m_Enabled = true;
    }

    delegate void ElapsedEvent(object sender, object args);

    public override void Dispose()
    {
        if (IsDisposed) return;            

        base.Dispose();

        Stop();

        try { m_Counter.Abort(m_Frequency); }
        catch (System.Threading.ThreadAbortException) { System.Threading.Thread.ResetAbort(); }
        catch { }

        Tick = null;

        //Producer.Clear();
    }

}

次に、次のようなものを使用して、実際にいくつかのロジックを複製できます

 /// <summary>
/// Provides a completely managed implementation of <see cref="System.Diagnostics.Stopwatch"/> which expresses time in the same units as <see cref="System.TimeSpan"/>.
/// </summary>
public class Stopwatch : Common.BaseDisposable
{
    internal Timer Timer;

    long Units;

    public bool Enabled { get { return Timer != null && Timer.Enabled; } }

    public double ElapsedMicroseconds { get { return Units * Media.Common.Extensions.TimeSpan.TimeSpanExtensions.TotalMicroseconds(Timer.Frequency); } }

    public double ElapsedMilliseconds { get { return Units * Timer.Frequency.TotalMilliseconds; } }

    public double ElapsedSeconds { get { return Units * Timer.Frequency.TotalSeconds; } }

    //public System.TimeSpan Elapsed { get { return System.TimeSpan.FromMilliseconds(ElapsedMilliseconds / System.TimeSpan.TicksPerMillisecond); } }

    public System.TimeSpan Elapsed
    {
        get
        {
            switch (Units)
            {
                case 0: return System.TimeSpan.Zero;
                default:
                    {
                        System.TimeSpan taken = System.DateTime.UtcNow - Timer.m_Started;

                        return taken.Add(new System.TimeSpan(Units * Timer.Frequency.Ticks));

                        //System.TimeSpan additional = new System.TimeSpan(Media.Common.Extensions.Math.MathExtensions.Clamp(Units, 0, Timer.Frequency.Ticks));

                        //return taken.Add(additional);
                    }
            }



            //////The maximum amount of times the timer can elapse in the given frequency
            ////double maxCount = (taken.TotalMilliseconds / Timer.Frequency.TotalMilliseconds) / ElapsedMilliseconds;

            ////if (Units > maxCount)
            ////{
            ////    //How many more times the event was fired than needed
            ////    double overage = (maxCount - Units);

            ////    additional = new System.TimeSpan(System.Convert.ToInt64(Media.Common.Extensions.Math.MathExtensions.Clamp(Units, overage, maxCount)));

            ////    //return taken.Add(new System.TimeSpan((long)Media.Common.Extensions.Math.MathExtensions.Clamp(Units, overage, maxCount)));
            ////}
            //////return taken.Add(new System.TimeSpan(Units));


        }
    }

    public void Start()
    {
        if (Enabled) return;

        Units = 0;

        //Create a Timer that will elapse every OneTick //`OneMicrosecond`
        Timer = new Timer(Media.Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick);

        //Handle the event by incrementing count
        Timer.Tick += Count;

        Timer.Start();
    }

    public void Stop()
    {
        if (false == Enabled) return;

        Timer.Stop();

        Timer.Dispose();           
    }

    void Count(ref long count) { ++Units; }
}

最後に、バスなどの半有用なものを作成し、バスにデータを送信するための仮想画面を作成します...

public abstract class Bus : Common.CommonDisposable
    {
        public readonly Timer Clock = new Timer(Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick);

        public Bus() : base(false) { Clock.Start(); }
    }

    public class ClockedBus : Bus
    {
        long FrequencyHz, Maximum, End;

        readonly Queue<byte[]> Input = new Queue<byte[]>(), Output = new Queue<byte[]>();

        readonly double m_Bias;

        public ClockedBus(long frequencyHz, double bias = 1.5)
        {
            m_Bias = bias;

            cache = Clock.m_Clock.InstructionsPerClockUpdate / 1000;

            SetFrequency(frequencyHz);

            Clock.Tick += Clock_Tick;

            Clock.Start();
        }

        public void SetFrequency(long frequencyHz)
        {
            FrequencyHz = frequencyHz;

            //Clock.m_Frequency = new TimeSpan(Clock.m_Clock.InstructionsPerClockUpdate / 1000); 

            //Maximum = System.TimeSpan.TicksPerSecond / Clock.m_Clock.InstructionsPerClockUpdate;

            //Maximum = Clock.m_Clock.InstructionsPerClockUpdate / System.TimeSpan.TicksPerSecond;

            Maximum = cache / (cache / FrequencyHz);

            Maximum *= System.TimeSpan.TicksPerSecond;

            Maximum = (cache / FrequencyHz);

            End = Maximum * 2;

            Clock.m_Frequency = new TimeSpan(Maximum);

            if (cache < frequencyHz * m_Bias) throw new Exception("Cannot obtain stable clock");

            Clock.Producer.Clear();
        }

        public override void Dispose()
        {
            ShouldDispose = true;

            Clock.Tick -= Clock_Tick;

            Clock.Stop();

            Clock.Dispose();

            base.Dispose();
        }

        ~ClockedBus() { Dispose(); }

        long sample = 0, steps = 0, count = 0, avg = 0, cache = 1;

        void Clock_Tick(ref long ticks)
        {
            if (ShouldDispose == false && false == IsDisposed)
            {
                //Console.WriteLine("@ops=>" + Clock.m_Ops + " @ticks=>" + Clock.m_Ticks + " @Lticks=>" + ticks + "@=>" + Clock.m_Clock.Now.TimeOfDay + "@=>" + (Clock.m_Clock.Now - Clock.m_Clock.Created));

                steps = sample;

                sample = ticks;

                ++count;

                System.ConsoleColor f = System.Console.ForegroundColor;

                if (count <= Maximum)
                {
                    System.Console.BackgroundColor = ConsoleColor.Yellow;

                    System.Console.ForegroundColor = ConsoleColor.Green;

                    Console.WriteLine("count=> " + count + "@=>" + Clock.m_Clock.Now.TimeOfDay + "@=>" + (Clock.m_Clock.Now - Clock.m_Clock.Created) + " - " + DateTime.UtcNow.ToString("MM/dd/yyyy hh:mm:ss.ffffff tt"));

                    avg = Maximum / count;

                    if (Clock.m_Clock.InstructionsPerClockUpdate / count > Maximum)
                    {
                        System.Console.ForegroundColor = ConsoleColor.Red;

                        Console.WriteLine("---- Over InstructionsPerClockUpdate ----" + FrequencyHz);
                    }
                }
                else if (count >= End)
                {
                    System.Console.BackgroundColor = ConsoleColor.Black;

                    System.Console.ForegroundColor = ConsoleColor.Blue;

                    avg = Maximum / count;

                    Console.WriteLine("avg=> " + avg + "@=>" + FrequencyHz);

                    count = 0;
                }
            }
        }

        //Read, Write at Frequency

    }
public class VirtualScreen
    {
        TimeSpan RefreshRate;    
        bool VerticalSync;    
        int Width, Height;            
        Common.MemorySegment DisplayMemory, BackBuffer, DisplayBuffer;
    }

これが私がテストした方法ですStopWatch

internal class StopWatchTests
    {
        public void TestForOneMicrosecond()
        {
            System.Collections.Generic.List<System.Tuple<bool, System.TimeSpan, System.TimeSpan>> l = new System.Collections.Generic.List<System.Tuple<bool, System.TimeSpan, System.TimeSpan>>();

            //Create a Timer that will elapse every `OneMicrosecond`
            for (int i = 0; i <= 250; ++i) using (Media.Concepts.Classes.Stopwatch sw = new Media.Concepts.Classes.Stopwatch())
            {
                var started = System.DateTime.UtcNow;

                System.Console.WriteLine("Started: " + started.ToString("MM/dd/yyyy hh:mm:ss.ffffff tt"));

                //Define some amount of time
                System.TimeSpan sleepTime = Media.Common.Extensions.TimeSpan.TimeSpanExtensions.OneMicrosecond;

                System.Diagnostics.Stopwatch testSw = new System.Diagnostics.Stopwatch();

                //Start
                testSw.Start();

                //Start
                sw.Start();

                while (testSw.Elapsed.Ticks < sleepTime.Ticks - (Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick + Common.Extensions.TimeSpan.TimeSpanExtensions.OneTick).Ticks)
                    sw.Timer.m_Clock.NanoSleep(0); //System.Threading.Thread.SpinWait(0);

                //Sleep the desired amount
                //System.Threading.Thread.Sleep(sleepTime);

                //Stop
                testSw.Stop();

                //Stop
                sw.Stop();

                var finished = System.DateTime.UtcNow;

                var taken = finished - started;

                var cc = System.Console.ForegroundColor;

                System.Console.WriteLine("Finished: " + finished.ToString("MM/dd/yyyy hh:mm:ss.ffffff tt"));

                System.Console.WriteLine("Sleep Time: " + sleepTime.ToString());

                System.Console.WriteLine("Real Taken Total: " + taken.ToString());

                if (taken > sleepTime) 
                {
                    System.Console.ForegroundColor = System.ConsoleColor.Red;
                    System.Console.WriteLine("Missed by: " + (taken - sleepTime));
                }
                else
                {
                    System.Console.ForegroundColor = System.ConsoleColor.Green;
                    System.Console.WriteLine("Still have: " + (sleepTime - taken));
                }

                System.Console.ForegroundColor = cc;

                System.Console.WriteLine("Real Taken msec Total: " + taken.TotalMilliseconds.ToString());

                System.Console.WriteLine("Real Taken sec Total: " + taken.TotalSeconds.ToString());

                System.Console.WriteLine("Real Taken μs Total: " + Media.Common.Extensions.TimeSpan.TimeSpanExtensions.TotalMicroseconds(taken).ToString());

                System.Console.WriteLine("Managed Taken Total: " + sw.Elapsed.ToString());

                System.Console.WriteLine("Diagnostic Taken Total: " + testSw.Elapsed.ToString());

                System.Console.WriteLine("Diagnostic Elapsed Seconds  Total: " + ((testSw.ElapsedTicks / (double)System.Diagnostics.Stopwatch.Frequency)));

                //Write the rough amount of time taken in  micro seconds
                System.Console.WriteLine("Managed Time Estimated Taken: " + sw.ElapsedMicroseconds + "μs");

                //Write the rough amount of time taken in  micro seconds
                System.Console.WriteLine("Diagnostic Time Estimated Taken: " + Media.Common.Extensions.TimeSpan.TimeSpanExtensions.TotalMicroseconds(testSw.Elapsed) + "μs");

                System.Console.WriteLine("Managed Time Estimated Taken: " + sw.ElapsedMilliseconds);

                System.Console.WriteLine("Diagnostic Time Estimated Taken: " + testSw.ElapsedMilliseconds);

                System.Console.WriteLine("Managed Time Estimated Taken: " + sw.ElapsedSeconds);

                System.Console.WriteLine("Diagnostic Time Estimated Taken: " + testSw.Elapsed.TotalSeconds);

                if (sw.Elapsed < testSw.Elapsed)
                {
                    System.Console.WriteLine("Faster than Diagnostic StopWatch");
                    l.Add(new System.Tuple<bool, System.TimeSpan, System.TimeSpan>(true, sw.Elapsed, testSw.Elapsed));
                }
                else if (sw.Elapsed > testSw.Elapsed)
                {
                    System.Console.WriteLine("Slower than Diagnostic StopWatch");
                    l.Add(new System.Tuple<bool, System.TimeSpan, System.TimeSpan>(false, sw.Elapsed, testSw.Elapsed));
                }
                else
                {
                    System.Console.WriteLine("Equal to Diagnostic StopWatch");
                    l.Add(new System.Tuple<bool, System.TimeSpan, System.TimeSpan>(true, sw.Elapsed, testSw.Elapsed));
                }
            }

            int w = 0, f = 0;

            var cc2 = System.Console.ForegroundColor;

            foreach (var t in l)
            {
                if (t.Item1)
                {
                    System.Console.ForegroundColor = System.ConsoleColor.Green;
                    ++w; System.Console.WriteLine("Faster than Diagnostic StopWatch by: " + (t.Item3 - t.Item2));
                }
                else
                {
                    System.Console.ForegroundColor = System.ConsoleColor.Red;
                    ++f; System.Console.WriteLine("Slower than Diagnostic StopWatch by: " + (t.Item2 - t.Item3));
                }
            }

            System.Console.ForegroundColor = System.ConsoleColor.Green;
            System.Console.WriteLine("Wins = " + w);

            System.Console.ForegroundColor = System.ConsoleColor.Red;
            System.Console.WriteLine("Loss = " + f);

            System.Console.ForegroundColor = cc2;
        }
    }
于 2015-08-06T21:27:19.980 に答える