Motion - Bug Report 2005x 04x 24x 205933

BUG: When setting low_cpu to non zero CPU load increases

Main.KennethLavrsen has entered this bug on behalf of WillCooke because the bug is so nasty that it is worth having proper traceability on. Originally reported on IRC: http://koala.ilog.fr/twikiirc/bin/irclogger_log/motion?date=2005-04-24,Sun&sel=12#l8

When you activate low_cpu the CPU load increases significantly.

Fx. from a load of 10% to 50%. Or from 50% to 99% on a slow machine.

Further observations shows that this gets worse if low_cpu value is equal to framerate.

Test case

Environment

Motion version: 3.2.1_snap14
ffmpeg version: N/A
Shared libraries: ffmpeg, mysql, postgresql
Server OS:  

-- KennethLavrsen - 24 Apr 2005 for WillCooke

Follow up

Fix record

There were 3 errors:

This was the code in motion.c

/* This will limit the framerate to 1 frame while not detecting
   motion. Using a different motion flag to allow for multiple frames per second
 */

if (cnt->conf.low_cpu && !detecting_motion) {
    /* Recalculate remaining time to delay for a total of 1/low_cpu seconds */
    if (required_frame_time+elapsedtime<(1000000/cnt->conf.low_cpu)) {
        frame_delay=(1000000/cnt->conf.low_cpu)-required_frame_time-elapsedtime;
        
        /* sleep using nanosleep. If a signal such as SIG_CHLD interrupts the
           sleep we just continue sleeping */         
        delay_time.tv_sec = 0;
        delay_time.tv_nsec = frame_delay * 1000;
        
        if (delay_time.tv_nsec > 999999999)
            delay_time.tv_nsec = 999999999;
        
        while ( nanosleep(&delay_time,&remaining_time) == -1 )
        {
            delay_time.tv_sec  = remaining_time.tv_sec;
            delay_time.tv_nsec = remaining_time.tv_nsec;
        }
    }
    /* Correct frame times to ensure required_frame_time is maintained */
    gettimeofday(&tv1, NULL);
    timenow=(tv1.tv_usec+(1000000L/cnt->conf.low_cpu)*tv1.tv_sec)-required_frame_time;
}

The issues
  • if (required_frame_time+elapsedtime<(1000000/cnt->conf.low_cpu)) is too long. We should compare the elapsed time since timenow was set and that is the elapsed time + the frame_delay we just added in the code above.
    The corrected code becomes if (frame_delay+elapsedtime<(1000000L/cnt->conf.low_cpu))
  • From this the calculation of the low_cpu frame_delay also needs to be corrected.
    frame_delay=(1000000/cnt->conf.low_cpu)-required_frame_time-elapsedtime; becomes
    frame_delay=(1000000L/cnt->conf.low_cpu)-frame_delay-elapsedtime;
  • We test for weather we should sleep but no matter if we did or not we adjust the timenow. The gettimeofday() and the setting of timenow must be moved inside the if statement so it only gets adjusted when there is a reason to do so.
  • Finally the major bug was the statement setting timenow:
    timenow=(tv1.tv_usec+(1000000L/cnt->conf.low_cpu)*tv1.tv_sec)-required_frame_time;
    This error was introduced when the feature of being able to set low_cpu to any value was added in 3.0.1. The right formular should be like this
    timenow=tv1.tv_usec+1000000L*tv1.tv_sec-required_frame_time;

This gives this new code.

/* This will limit the framerate to 1 frame while not detecting
   motion. Using a different motion flag to allow for multiple frames per second
 */

if (cnt->conf.low_cpu && !detecting_motion) {
    /* Recalculate remaining time to delay for a total of 1/low_cpu seconds */
    if (frame_delay+elapsedtime<(1000000L/cnt->conf.low_cpu)) {
        frame_delay=(1000000L/cnt->conf.low_cpu)-frame_delay-elapsedtime;
        
        /* sleep using nanosleep. If a signal such as SIG_CHLD interrupts the
           sleep we just continue sleeping */         
        delay_time.tv_sec = 0;
        delay_time.tv_nsec = frame_delay * 1000;
        
        if (delay_time.tv_nsec > 999999999)
            delay_time.tv_nsec = 999999999;
        
        while ( nanosleep(&delay_time,&remaining_time) == -1 )
        {
            delay_time.tv_sec  = remaining_time.tv_sec;
            delay_time.tv_nsec = remaining_time.tv_nsec;
        }
        /* Correct frame times to ensure required_frame_time is maintained */
        gettimeofday(&tv1, NULL);
        timenow=tv1.tv_usec+1000000L*tv1.tv_sec-required_frame_time;
    }
}

The fix will be in motion-3.2.1_snap15 and 3.1.20_snap7.

-- KennethLavrsen - 24 Apr 2005
Topic revision: r2 - 27 May 2005, KennethLavrsen
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Please do not email Kenneth for support questions (read why). Use the Support Requests page or join the Mailing List.
This website only use harmless session cookies. See Cookie Policy for details. By using this website you accept the use of these cookies.