Buchempfehlung
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Umfassend, aber leicht verständlich führt dieses Buch in die Programmierung von ATMEL AVR Mikrocontrollern ein. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Code-Beispiel

Code-Beispiele » Kleine Helferlein

Counter.Bas von MichaelW

Lizenz:Erster Autor:Letzte Bearbeitung:
k. A.Redakteurytwinky 14.01.2015

Hier finden Sie neuere Macros: Externer Link!Neue "Cycle count macros for 32 and 64-bit code"

''=============================================================================
#Include "windows.bi"
''=============================================================================

Dim Shared As LongInt counter_cycles
Dim Shared As Integer _counter_loopcount_, _counter_loopcounter_
Dim Shared As Integer _process_priority_class_, _thread_priority_

#Macro COUNTER_BEGIN( loop_count, process_priority, thread_priority )
    _counter_loopcount_ = loop_count
    _process_priority_class_ = GetPriorityClass(GetCurrentProcess())
    _thread_priority_ = GetThreadPriority(GetCurrentProcess())
    SetPriorityClass(GetCurrentProcess(), process_priority)
    SetThreadPriority(GetCurrentProcess(), thread_priority)
    _counter_loopcounter_ = _counter_loopcount_
    Asm
        Xor eax, eax
        cpuid               '' serialize
        rdtsc               '' get reference loop start count
        push edx            '' preserve msd (most significant dword)
        push eax            '' preserve lsd
        Xor eax, eax
        cpuid               '' serialize
        .balign 16
      0:                    '' start of reference loop
        Sub DWORD Ptr _counter_loopcounter_, 1
        jnz 0b              '' end of reference loop
        Xor eax, eax
        cpuid               '' serialize
        rdtsc               '' get reference loop end count
        pop ecx             '' recover lsd of start count
        Sub eax, ecx        '' calc lsd of reference loop count
        pop ecx             '' recover msd of start count
        sbb edx, ecx        '' calc msd of reference loop count
        push edx            '' preserve msd of reference loop count
        push eax            '' preserve lsd of reference loop count
        Xor eax, eax
        cpuid               '' serialize
        rdtsc               '' get test loop start count
        push edx            '' preserve msd
        push eax            '' preserve lsd
    End Asm
    _counter_loopcounter_ = _counter_loopcount_
    Asm
        Xor eax, eax
        cpuid               '' serialize
        .balign 16
      1:                    '' start of test loop
    End Asm
#EndMacro

''=============================================================================

#Macro COUNTER_END()
    Asm
        Sub DWORD Ptr _counter_loopcounter_, 1
        jnz 1b              '' end of test loop
        Xor eax, eax
        cpuid               '' serialize
        rdtsc
        pop ecx             '' recover lsd of start count
        Sub eax, ecx        '' calc lsd of test loop count
        pop ecx             '' recover msd of start count
        sbb edx, ecx        '' calc msd of test loop count
        pop ecx             '' recover lsd of reference loop count
        Sub eax, ecx        '' calc lsd of corrected loop count
        pop ecx             '' recover msd of reference loop count
        sbb edx, ecx        '' calc msd of corrected loop count
        mov DWORD Ptr [counter_cycles], eax
        mov DWORD Ptr [counter_cycles+4], edx
    End Asm
    SetPriorityClass(GetCurrentProcess(),_process_priority_class_)
    SetThreadPriority(GetCurrentProcess(),_thread_priority_)
    counter_cycles /= _counter_loopcount_
#EndMacro

''=============================================================================

Alte Version:

'====================================================================
'' The COUNTER_BEGIN and COUNTER_END macros provide a convenient
'' method of measuring the processor clock cycle count for a block
'' of code. These macros must be called in pairs, and the block of
'' code must be placed in between the COUNTER_BEGIN and COUNTER_END
'' macro calls. The clock cycle count for a single loop through the
'' block of code, corrected for the test loop overhead, is returned
'' in the shared variable COUNTER_CYCLES.
''
'' These macros capture the lowest cycle count that occurs in a
'' single loop through the block of code, on the assumption that
'' the lowest count is the correct count. The higher counts that
'' occur are the result of one or more context switches within the
'' loop. Context switches can occur at the end of a time slice, so
'' to minimize the possibility of the loop overlapping the time
'' slice the COUNTER_BEGIN macro starts a new time slice at the
'' beginning of the loop. If the execution time for a single loop
'' is greater than the duration of a time slice (approximately 20ms
'' under Windows), then the loop will overlap the time slice, and
'' if another thread of equal priority is ready to run, then a
'' context switch will occur.
''
'' A higher-priority thread can “preempt” a lower priority thread,
'' causing a context switch to occur before the end the time slice.
'' Raising the priority of the process (thread) can reduce the
'' frequency of these context switches. To do so, specify a higher
'' than normal priority class in the priority_class parameter of
'' the COUNTER_BEGIN macro. REALTIME_PRIORITY_CLASS specifies the
'' highest possible priority, but using it involves some risk,
'' because your process will preempt *all* other processes,
'' including critical Windows processes, and if the timed code
'' takes too long to execute then Windows may hang, even the NT
'' versions. HIGH_PRIORITY_CLASS is a safer alternative that in
'' most cases will produce the same cycle count.
''
'' You can avoid the bulk of the context switches by simply
'' inserting a few second delay in front of the first macro
'' call, to allow the system disk cache activity to subside.
''
'' For the loop_count parameter of the COUNTER_BEGIN macro, larger
'' values increase the number of samples and so tend to improve
'' the consistency of the returned cycle counts, but in most cases
'' you are unlikely to see any improvement beyond a value of about
'' 1000.
''
'' Note that the block of code must be able to withstand repeated
'' looping, and that this method will not work for timing a loop
'' because the lowest cycle count that occurs will be when the
'' loop falls through.
''
'' These macros require a Pentium-class processor that supports
'' the CPUID (function 0 only) and RDTSC instructions.
'====================================================================
#include once "windows.bi"

Dim Shared _counter_tsc1_ As Ulongint, _counter_tsc2_ As Ulongint
Dim Shared _counter_overhead_ As Ulongint, counter_cycles As Ulongint
Dim Shared _counter_loop_counter_ As Uinteger

Sub _counter_code1_
    asm
        '
        ' Use same CPUID input value for each call.
        '
        Xor eax, eax
        '
        ' Flush pipe and wait for pending ops to finish.
        '
        cpuid
        '
        ' Read Time Stamp Counter.
        '
        rdtsc
        '
        ' Save count.
        '
        mov [_counter_tsc1_], eax
        mov [_counter_tsc1_+4], edx
    End asm
End Sub

Sub _counter_code2_
    asm
        Xor eax, eax
        cpuid
        rdtsc
        mov [_counter_tsc2_], eax
        mov [_counter_tsc2_+4], edx
    End asm
End Sub

'' Unlike the #define directive, the #macro directive
'' allows inline asm.
''
#macro COUNTER_BEGIN( loop_count, priority_class )
    _counter_overhead_ = 2000000000
    counter_cycles = 2000000000
    SetPriorityClass( GetCurrentProcess(), priority_class )
    Sleep_(0)                 '' Start a new time slice
    ''
    '' The nops compensate for the 10-byte instruction (that
    '' initializes _counter_loop_counter_) between the alignment
    '' directive and the loop label, which ideally needs to be
    '' aligned on a 16-byte boundary.
    ''
    asm
      .balign 16
      nop
      nop
      nop
      nop
      nop
      nop
    End asm
    For _counter_loop_counter_ = 1 To loop_count
        _counter_code1_
        _counter_code2_
        If (_counter_tsc2_ - _counter_tsc1_) < _counter_overhead_ Then
            _counter_overhead_ = _counter_tsc2_ - _counter_tsc1_
        Endif
    Next
    Sleep_(0)                 '' Start a new time slice
    asm
      .balign 16
      nop
      nop
      nop
      nop
      nop
      nop
    End asm
    For _counter_loop_counter_ = 1 To loop_count
        _counter_code1_
#endmacro
''
'' *** Note the open FOR loop ***
''
#define COUNTER_END _
        _counter_code2_ :_
        If (_counter_tsc2_ - _counter_tsc1_) < counter_cycles Then :_
            counter_cycles = _counter_tsc2_ - _counter_tsc1_ :_
        Endif :_
    Next :_
    SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS ) :_
    counter_cycles -= _counter_overhead_

Zusätzliche Informationen und Funktionen
  • Das Code-Beispiel wurde am 22.08.2007 von Redakteurytwinky angelegt.
  • Die aktuellste Version wurde am 14.01.2015 von RedakteurVolta gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen