Menu ▾ ▴

Inaccurate isochronous traffic scheduling on Windows

Rony Ross
2022-03-21
2022-03-24
  • Rony Ross

    Rony Ross - 2022-03-21

    Windows uses an HW timer that wakes the system every 15.6ms (default). Live Audio/Video streaming application (e.g., Teams) usually set it to 1ms using timeBeginPeriod

    iperf2 does not change the timer resolution, which makes its isochronous TX scheduling inaccurate.
    In the first capture below, you can see that iperf2 schedule only 49pps instead of the requested 60pps.
    In the second capture, the timer resolution was set to 1ms by another application. As a result, iperf2 managed to schedules 60pps.

    I suggest to add option for setting the timer resolution. The default value for isochronous should be 1ms

     
  • Robert McMahon

    Robert McMahon - 2022-03-21

    ok, thanks for this. Let me take a look.

    Bob

     
    • Robert McMahon

      Robert McMahon - 2022-03-24

      I've opened a ticket for this. Did you happen to get it to compile and work?

       
  • Robert McMahon

    Robert McMahon - 2022-03-24

    Cross compile is failing - need to debug

    [rjmcmahon@ryzen3950 iperf2-code]$ git diff
    diff --git a/include/headers.h b/include/headers.h
    index 12974e8..2234273 100644
    --- a/include/headers.h
    +++ b/include/headers.h
    @@ -175,6 +175,9 @@ typedef bool _Bool;
         #include <winsock2.h>
         #include <ws2tcpip.h>
         #include <process.h>
    +#if HAVE_ISOCHRONOUS
    
    +    #include <mmsystem.h>
    +#endif
    
     /* define EINTR, just to help compile; it isn't useful */
         #ifndef EINTR
    diff --git a/src/isochronous.cpp b/src/isochronous.cpp
    index f1fd494..74389ec 100644
    --- a/src/isochronous.cpp
    +++ b/src/isochronous.cpp
    @@ -62,7 +62,12 @@ FrameCounter::FrameCounter (double value, const Timestamp& start) : frequency(va
     }
     FrameCounter::FrameCounter (double value) : frequency(value) {
     #ifdef WIN32
    
    -    /* Create timer */
    +#if HAVE_ISOCHRONOUS
    +    // adjust the windows internal timer period to one millisecond
    +    int timeperiod=1;  //units is milliseconds
    +    timeBeginPeriod(timeperiod);
    +#endif
    +/* Create timer */
         my_timer = CreateWaitableTimer(NULL, TRUE, NULL);
         if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
            WARN_errno(1, "SetThreadPriority");
    @@ -77,6 +82,11 @@ FrameCounter::FrameCounter (double value) : frequency(value) {
     FrameCounter::~FrameCounter () {
     #ifdef WIN32
         /* Clean resources */
    +#if HAVE_ISOCHRONOUS
    +    // undo the timeBeginPeriod
    +    int timeperiod=1;  //units is milliseconds
    +    timeEndPeriod(timeperiod);
    +#endif
         if (my_timer)
            CloseHandle(my_timer);
     #endif
    [rjmcmahon@ryzen3950 iperf2-code]$ make -j
    make  all-recursive
    make[1]: Entering directory '/home/rjmcmahon/Code/cross-compile/iperf2-code'
    Making all in compat
    make[2]: Entering directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/compat'
    make[2]: Nothing to be done for 'all'.
    make[2]: Leaving directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/compat'
    Making all in doc
    make[2]: Entering directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/doc'
    make[2]: Nothing to be done for 'all'.
    make[2]: Leaving directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/doc'
    Making all in include
    make[2]: Entering directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/include'
    make[2]: Nothing to be done for 'all'.
    make[2]: Leaving directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/include'
    Making all in src
    make[2]: Entering directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/src'
    i686-w64-mingw32-g++ -DHAVE_CONFIG_H -I. -I..  -I../include -I../include  -Wall  -O2 -O2  -MT isochronous.o -MD -MP -MF .deps/isochronous.Tpo -c -o isochronous.o isochronous.cpp
    mv -f .deps/isochronous.Tpo .deps/isochronous.Po
    i686-w64-mingw32-g++ -Wall  -O2 -O2  -O2  -pthread  -DHAVE_CONFIG_H  -o iperf.exe Client.o Extractor.o isochronous.o Launch.o active_hosts.o Listener.o Locale.o PerfSocket.o Reporter.o Reports.o ReportOutputs.o Server.o Settings.o SocketAddr.o gnu_getopt.o gnu_getopt_long.o histogram.o main.o service.o socket_io.o stdio.o packet_ring.o tcp_window_size.o pdfs.o  ../compat/libcompat.a -lws2_32  -static-libstdc++ -static
    /usr/lib/gcc/i686-w64-mingw32/10.3.1/../../../../i686-w64-mingw32/bin/ld: isochronous.o:isochronous.cpp:(.text+0x137): undefined reference to `_imp__timeBeginPeriod@4'
    /usr/lib/gcc/i686-w64-mingw32/10.3.1/../../../../i686-w64-mingw32/bin/ld: isochronous.o:isochronous.cpp:(.text+0x1ff): undefined reference to `_imp__timeEndPeriod@4'
    collect2: error: ld returned 1 exit status
    make[2]: *** [Makefile:478: iperf.exe] Error 1
    make[2]: Leaving directory '/home/rjmcmahon/Code/cross-compile/iperf2-code/src'
    make[1]: *** [Makefile:597: all-recursive] Error 1
    make[1]: Leaving directory '/home/rjmcmahon/Code/cross-compile/iperf2-code'
    make: *** [Makefile:537: all] Error 2
    
     

Log in to post a comment.