2008-09-21 3 views
22

Если вы прочитали мой другой номер question, вы узнаете, что я провел в эти выходные, собрав эмулятор процессора 6502 в качестве упражнения для программирования.Эмуляция процессора и блокировка определенной тактовой частоты

Эмулятор процессора в основном завершен и, кажется, довольно точна из моего ограниченного тестирования, однако он работает невероятно быстро, и я хочу затормозить его до фактической тактовой частоты машины.

Мой текущий цикл испытаний заключается в следующем:

// 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 Cycle , Это обеспечивает правильное время между кодами операций, а именно то, что вся вещь проходит быстро.

Целевая скорость процессора составляет 1,79 МГц, однако я бы хотел, чтобы любое решение проблемы часов поддерживало скорость на 1,79 мГц, даже когда я добавляю сложность, поэтому мне не нужно ее корректировать.

Любые идеи?

ответ

4

Я бы использовал тактовые циклы для вычисления времени, и они спали разницу во времени. Конечно, для этого вам нужны часы с высоким разрешением. Они, как вы это делаете, собираются шипить процессор в прядильных циклах.

7

Взгляните на оригинальную документацию Quicktime для вдохновения.

Это было написано давно, когда видеоизображение означало просто замену неподвижных кадров на достаточно высокой скорости, но ребята из Apple решили, что им нужна полная структура управления временем. Сначала дизайн выглядит чрезмерно сложным, но он позволяет им иметь дело с различными требованиями к скорости и поддерживать их в сильной синхронизации.

Вам повезло, что 6502 имеет детерминированное временное поведение, точное время, которое принимает каждая инструкция, хорошо документировано; но это не постоянно. некоторые инструкции занимают 2 цикла, другие 3. Как и в режиме QuickTime, в кадре нет параметра «кадров в секунду», каждый кадр указывает, как долго он будет находиться на экране.

Поскольку современные процессоры настолько детерминированы, и многозадачные ОС могут даже зависнуть на несколько секунд (виртуальная память!), Вы должны сохранить вкладку, если вы отстаете от графика, или если вы можете занять несколько микросекунд ,

9

Я написал эмулятор Z80 много лет назад, и чтобы выполнить точное выполнение цикла, я разделил тактовую частоту на несколько небольших блоков и имел ядро, выполняющее много тактов. В моем случае я привязал его к частоте кадров игровой системы, которую я подражал. Каждый код операции знал, сколько циклов потребовалось для выполнения, и ядро ​​будет продолжать работать с кодами операций до тех пор, пока не будет выполнено указанное количество циклов. У меня был внешний цикл цикла, который запускал ядро ​​процессора, и запускал другие части эмулируемой системы, а затем спал до времени начала следующей итерации.

EDIT: Добавление примера цикла запуска.

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

    return n; 
} 

Надеюсь, это поможет.

4

Как говорит jfk, наиболее распространенный способ сделать это: привязать скорость процессора к вертикальному обновлению (эмулируемому) видеовыходу.

Выберите количество циклов для запуска на видеокадр.Это часто конкретная машина, но вы можете вычислить его что-то вроде:

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

Тогда вы также можете сделать сон, пока обновление видео не попали, в какой момент вы начинаете следующий п циклы эмуляции процессора ,

Если вы эмулируете что-то в частности, вам просто нужно найти скорость fps и скорость процессора, чтобы получить это примерно правильно.

EDIT: Если у вас нет внешних требований к синхронизации, то для эмулятора нормально работать как можно быстрее. Иногда это желаемый эффект, а иногда и нет :)

0

Другой вариант доступен, если реализована звуковая эмуляция, и если аудиовыход привязан к часам системы/ЦП. В частности, я знаю, что это относится к 8-разрядному Apple] [компьютерам.

Обычно звук генерируется в буферах фиксированного размера (это фиксированное время), поэтому работа (генерация данных и т. Д.) Этих буферов может быть привязана к пропускной способности процессора через примитивы синхронизации.

1

Да, как уже говорилось, в большинстве случаев вам не нужен эмулятор процессора для эмуляции инструкций с одинаковой скоростью реальной вещи. То, что воспринимает пользователь, это вывод вывода (то есть аудио- и видеовыходы), поэтому вам нужно только синхронизировать с такими выходами, что не означает, что вы должны обязательно иметь точную скорость эмуляции процессора.

Другими словами, если частота кадров видеовхода составляет, скажем, 50 Гц, то пусть эмулятор процессора работает так быстро, как можно, чтобы нарисовать экран, но обязательно вывести рамы экрана с правильной скоростью (50 Гц). С внешней точки зрения ваш эмулятор эмулирует с правильной скоростью.

Попытка быть точным в цикле даже во время выполнения не имеет смысла в многозадачной ОС, такой как Windows или Linux, потому что время обучения эмулятора (типично 1uS для графических процессоров 80-х годов) и временной интервал планирования современного ОС сопоставимы.

Попытка вывести что-то со скоростью 50 Гц является гораздо проще, вы можете сделать очень хорошо на любой современной машине

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/ 

[email protected]/(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: 
* 
* 
* [email protected] 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; } 
} 

Наконец, создайте что-нибудь полу полезное, например. a Bus, а затем, возможно, виртуальный экран для передачи данных на шину ...

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; 
     } 
    } 
Смежные вопросы