Как измерить время выполнения программы (внутри программы), не считая таких вещей, как паузы во время отладки? - PullRequest
1 голос
/ 09 марта 2011

Одна из распространенных проблем, возникающих у меня при отладке, заключается в том, что что-либо, зависящее от времени, дает сбой всякий раз, когда я приостанавливаю программу.Например, если вы прервете сетевое соединение после 1 минуты бездействия с другой стороны, остановка отладчика на минуту приведет к разрыву соединения.

Я уже сталкивался с подобной проблемой для тестирования, где я хотел долгопериоды времени, чтобы пройти.Мое решение заключалось в том, чтобы ввести интерфейс IClock с методами ElapsedTime и Wait, поэтому, например, программа прошла бы в RealTimeClock, но тестирование прошло бы в ManualClock.

Я хочу сделать DebugClock, который делает паузукогда отладчик делает паузу.

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

Ответы [ 2 ]

1 голос
/ 10 марта 2011

Это мое «наивное» решение, которое я хотел бы улучшить.Я ставлю это как ответ, чтобы не затопить вопрос кодом.

Public Class ProgramClock
    Implements IClock

    '''<summary>Used to check for pauses. Only a singleton because it uses a periodic callback.</summary>'
    Private Class BackingClockSingleton
        Private Shared ReadOnly PausePeriod As TimeSpan = 5.Seconds
        Private Shared ReadOnly TickPeriod As TimeSpan = 3.Seconds

        '''<summary>Checked periodically to catch overly long periods.</summary>'
        '''<remarks>Stored as a weak reference to allow cleanup when there are no ProgramClock instances justifying the periodic timer usage.</remarks>'
        Private Shared _backClock As WeakReference
        Private Shared _lastElapsedTime As TimeSpan
        Private Shared _lostTime As TimeSpan
        Private Shared ReadOnly _lock As New Object()

        Public Shared Function GetElapsedTime() As TimeSpan
            Return PokeElapsedTime(scheduleNextPoke:=False).Value
        End Function
        Private Shared Function PokeElapsedTime(ByVal scheduleNextPoke As Boolean) As TimeSpan?
            SyncLock _lock
                Dim clock = DirectCast(_backClock.Target, IClock)
                If clock Is Nothing Then Return Nothing

                Dim t = clock.ElapsedTime
                Dim dt = t - _lastElapsedTime
                _lastElapsedTime = t

                If dt > PausePeriod Then _lostTime += dt
                If scheduleNextPoke Then
                    clock.AsyncWait(TickPeriod).ContinueWithAction(Sub() PokeElapsedTime(scheduleNextPoke:=True))
                End If

                Return t - _lostTime
            End SyncLock
        End Function

        Public Shared Function AsyncWaitUntil(ByVal t As TimeSpan) As Task
            Contract.Ensures(Contract.Result(Of Task)() IsNot Nothing)
            SyncLock _lock
                Dim clock = DirectCast(_backClock.Target, IClock)
                If clock Is Nothing Then Throw New Exceptions.InvalidStateException("Attempted to wait without a backing clock.")
                Return clock.AsyncWaitUntil(t)
            End SyncLock
        End Function

        Public Shared Function GetBackingClockReferenceToHold() As Object
            Contract.Ensures(Contract.Result(Of Object)() IsNot Nothing)
            SyncLock _lock
                Dim clock = DirectCast(_backClock.Target, IClock)
                If clock Is Nothing Then
                    _lostTime = 0.Seconds
                    _lastElapsedTime = 0.Seconds
                    clock = New SystemClock()
                    _backClock = New WeakReference(clock)
                    PokeElapsedTime(scheduleNextPoke:=True)
                End If
                Return clock
            End SyncLock
        End Function
    End Class

    Private ReadOnly _backingClockReference As Object
    Private ReadOnly _initialElapsedTime As TimeSpan

    <ContractInvariantMethod()> Private Sub ObjectInvariant()
        Contract.Invariant(_backingClockReference IsNot Nothing)
    End Sub

    Public Sub New()
        Me._backingClockReference = BackingClockSingleton.GetBackingClockReferenceToHold()
        Me._initialElapsedTime = BackingClockSingleton.GetElapsedTime()
    End Sub

    Public Function AsyncWaitUntil(ByVal time As TimeSpan) As Task Implements IClock.AsyncWaitUntil
        Return BackingClockSingleton.AsyncWaitUntil(time + _initialElapsedTime)
    End Function

    Public ReadOnly Property ElapsedTime As TimeSpan Implements IClock.ElapsedTime
        Get
            Return BackingClockSingleton.GetElapsedTime() - _initialElapsedTime
        End Get
    End Property
End Class
0 голосов
/ 09 марта 2011

Я бы просто сделал это.

class DebugClock implements Runnable {
  private volatile int secondsElapsed = 0;


  public void run() {
     try {
       while( true ) {
         Thread.sleep( 1000 );
         secondsElapsed++;
       }
     } catch( InterruptedException ex ) {}
  }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...