Timer interval increase (SOLVED) lazarus / 1-Linux ---------------------------------------------------------------------- ziocharly · 2015-05-04 09:19 My application on Raspberry PI use TTimer component to update continuously the status of my user interface (approximately each 200 mSec.). The strange behavior is that the time interval grows (about 10 mSec. each hour) when the application remains active... I also tried to use FPTimer (cThreads), but the problem still remain... Note that, under Windows, everything works perfectly, without any drift in the time interval set. RBPI hardware > card rev. 1 ver.2 RBPI OS > Debian Raspbian GNU V.7.8 Wheezy  Lazarus > 1.2.4  (23.02.2015) FPC > 2.6.4 (SNV Rev. 43696) Any suggestion is appreciated ! ---------------------------------------------------------------------- dogriz · 2015-05-04 10:55 Raspberry Pi does not have Real Time Clock (RTC), so I guess that can be the source of your problem. ---------------------------------------------------------------------- Cyrax · 2015-05-04 11:27 You can create/buy your own RTC module for Rasperry. ---------------------------------------------------------------------- ziocharly · 2015-05-04 12:29 Thanks for fast reply !      perhaps I have not explained well, I'm aware that real time is missing on RBPI, I'm also aware of additional daughter card that implements this functionality. My consideration/problem concerns only the interval of the TTimer, which continues to be incremented, without any possibility of adjust ! I am not worried about the scan rate frequency, but its continuous increment: one day after power up the application, the time, set to 200 msec., becomes 2 seconds ! This is unacceptable... ---------------------------------------------------------------------- Cyrax · 2015-05-04 13:45 How about you create a thread which checks if TTimer.Interval is in required value and if it is not, adjust it accordingly. ---------------------------------------------------------------------- rvk · 2015-05-04 14:03 Quote from: Cyrax on May 04, 2015, 03:45:04 pmHow about you create a thread which checks if TTimer.Interval is in required value and if it is not, adjust it accordingly. That would only work if the TTimer.Interval value really does increase. But if that's the case you could also just set the Interval to 200 each time it's executed. If the TTimer.Interval stays at 200 and the real interval is about 2 seconds after a day... that's a real problem. @ziocharly, What happens if the TTimer is disabled and enabled every hour? Does the interval increase then too? ---------------------------------------------------------------------- ziocharly · 2015-05-04 14:24 @Cyrax The strangest thing is that even if you change the time.interval value does not change the real time interval, or better, is possible only increase the value but not reduce/fix it !  @rvk One of the first things that I tried was to setup again the interval value, in each ontimer cycle (or when needed) but it does not work! Last attempt of today: - removed the timer from the form - create a new TTimer runtime   TimerScan:= TTimer.Create(self);   TimerScan.OnTimer:= @TimerScanTimer;   TimerScan.Interval:= 200;  - destroy my TTimer, if the interval it's not ok - finally TimerScan.free onClose. Also in this way still does NOT work ! No errors but the interval of new created timer still the same (long) !   I almost sold my chances... There is no possible solution to launch an 'event' on a regular time interval ??? ---------------------------------------------------------------------- rvk · 2015-05-04 14:29 What happens if you create a new timer with, say, 2000 ms? Does it take 20 seconds after a day? Or 10 x 10ms (=100ms) more after an hour or so? What you should find out, is, if another interval with a new timer takes proportional more time then your original. If so, then there must be something really screwed up internally with the TTimer (or depended underlying technology) on RasPi. ---------------------------------------------------------------------- ziocharly · 2015-05-04 14:49 I've to try this suggestion. After the first trials, most frequent is the 'onTimer' call, before the defect occurs and the interval increase... ...but it is possible that no one has noticed this behavior ! ---------------------------------------------------------------------- avra · 2015-05-04 22:07 Quote from: ziocharly on May 04, 2015, 11:19:30 amAny suggestion is appreciated !http://wiki.freepascal.org/EpikTimer ---------------------------------------------------------------------- taazz · 2015-05-04 22:25 Quote from: avra on May 05, 2015, 12:07:05 amQuote from: ziocharly on May 04, 2015, 11:19:30 amAny suggestion is appreciated !http://wiki.freepascal.org/EpikTimer Its not equivalent. Epik timer does not support intervals can only measure (fairly) accurately time intervals but it is not a replacement for ttimer. It needs work before it can replace ttimer. ---------------------------------------------------------------------- dogriz · 2015-05-05 05:32 What is the system load at app runtime? ---------------------------------------------------------------------- User137 · 2015-05-05 08:00 Why not compare TTime difference given by Now() function? You can run TTimer with interval such as 50ms then. In long term it will be 100% as accurate as the system time is. ---------------------------------------------------------------------- ziocharly · 2015-05-05 08:36 @avra as taazz post, the epiktimer don't have onTimer event that fireup my update procedure, with configured interval... @dogriz the app must read cyclically an external device, connected through ethernet and update the GUI. The entire whole process is performed in 20 to 30 msec. @User137 I already use, inside onTimer event, the instruction Now in order to check the real interval performed: procedure TFormMain.TimerRead(Sender: TObject); begin   Elapsed:= MilliSecondsBetween(Now, Interval);   StatusBar.Panels[0].Text:= 'Timer rate : '+ IntToStr(Elapsed) + ' mSec.';     if Elapsed > myScanRate then   begin      ... my GUI update ...   end;   Interval:= Now; end; The problem is that also the TimerRead (50 mSec. timer), lauched only to check the time Elapsed (with now istruction), increase his interval ! It would be enough have the launch of one procedures in a regular interval, that does not change over time ... As already confirmed this issue appears only on RBPI en environment. Really strange !!! ---------------------------------------------------------------------- dogriz · 2015-05-05 08:56 Did you try this: procedure TFormMain.TimerRead(Sender: TObject); begin   TimerRead.Enabled := False;   //do your GUI update and other stuff     TimerRead.Enabled := True; end; ---------------------------------------------------------------------- mse · 2015-05-05 09:01 Quote from: ziocharly on May 05, 2015, 10:36:03 am@dogriz the app must read cyclically an external device, connected through ethernet and update the GUI. The entire whole process is performed in 20 to 30 msec. And what is the system load? If it is 100% (also caused by other processes) the timer interval may become inaccurate. Are you sure your process does not hang somewhere? ---------------------------------------------------------------------- ziocharly · 2015-05-05 11:48 @dogriz yes, enabled false/true tested: any change. @mse app load around 15-20% of CPU with 150 Mb ram free... Last test of this morning: this issue not affected RBPI 2 card that work perfectly with same OS (wheezy 7.8 kernel 3.17) FPC 2.6.4 Lazarus 1.2.4 ---------------------------------------------------------------------- taazz · 2015-05-05 13:11 Try this test app does it have the same problems? ---------------------------------------------------------------------- ziocharly · 2015-05-05 19:43 Sorry for the results of RBPI 2 test: the behavior it's just the same, only delayed on the time... Afther 8 hours of power up the 200 mSec. interval become 700 mSec.... @taazz Today I've already implemented a separate thread, and seems work well ! Tomorrow I'm happy to test your sample app. Thank you  so much !!! ---------------------------------------------------------------------- User137 · 2015-05-07 02:02 Quote from: ziocharly on May 05, 2015, 10:36:03 amprocedure TFormMain.TimerRead(Sender: TObject); begin   Elapsed:= MilliSecondsBetween(Now, Interval);   StatusBar.Panels[0].Text:= 'Timer rate : '+ IntToStr(Elapsed) + ' mSec.';     if Elapsed > myScanRate then   begin      ... my GUI update ...   end;   Interval:= Now; end;The code is wrong. The time it takes from Elapsed := ... to Interval := ... is big enough to in long term cause delay. Try: Code: [Select]procedure TFormMain.TimerRead(Sender: TObject); var Current, Elapsed: TTime; begin   Current:=Now;   Elapsed:= MilliSecondsBetween(Current, Interval);   StatusBar.Panels[0].Text:= 'Timer rate : '+ IntToStr(Elapsed) + ' mSec.';     if Elapsed > myScanRate then   begin      ... my GUI update ...     // And also do this inside the IF. Otherwise it can skip ticks.     Interval:= Current;   end; end; ---------------------------------------------------------------------- ziocharly · 2015-05-11 07:25 Dear all Forum User,     sorry for the delay in my reply, it was due to the tests carried out : after dozens of tests, it is not yet clear why the CPU use, after some hours of operation, grows up to 100% deteriorating both the interval of the timer, or the precision of the running thread. Only on RBPI environment, the strange thing is that only a single repetitive timer, creates this issue ! More quickly, as is frequently the TTImer interval is called... With a separate thread this behavior is more or less the same. To restore the correct timing is enough close and reopen the application! Note that there are no particular increases in the use of memory... There is someone who knows this situation and has suggestions, and/or recommendations to avoid this problems? ---------------------------------------------------------------------- User137 · 2015-05-11 09:30 What do you have in there code-wise? As of now we can't even guess what could be wrong. But here is 1 testapp i made: Code: [Select]type   { TForm1 }   TForm1 = class(TForm)     Memo1: TMemo;     Timer1: TTimer;     procedure FormCreate(Sender: TObject);     procedure Timer1Timer(Sender: TObject);   private     LastEvent, Interval, StartTime: TTime;     Counter: int64;     procedure TimedEvent;   public   end; var   Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); begin   Interval:=encodetime(0, 0, 1, 0);   LastEvent:=Now;   StartTime:=LastEvent end; procedure TForm1.Timer1Timer(Sender: TObject); var diff: TTime; begin   diff:=Now-LastEvent;   if diff>Interval then begin     TimedEvent;     LastEvent:=LastEvent+Interval;   end; end; procedure TForm1.TimedEvent; var i: integer; begin   // Update GUI   memo1.Lines.Clear;   memo1.Lines.Add(format('%d:%d',[counter div 60, counter mod 60]));   memo1.Lines.Add(timetostr(LastEvent-StartTime));   inc(counter); end; ---------------------------------------------------------------------- ziocharly · 2015-05-12 19:51 @User137 your sample, with some minor changement, work perfectly on RBPI 1. So, the TTimer interval don't change ! Right now I'm trying to understand where is the real problem inside my code. I think it's really important to know where is the problem for all people that use a complex RBPI Lazarus application... 1.st of all I've limited the uses library in order to locate where is the code that making increasing the CPU use. Finally, tomorrow, I hope to have the expected answer ! ---------------------------------------------------------------------- ziocharly · 2015-05-15 10:43 Finally the reason of CPU overload has been identified !   Sometime simple things are consolidated and are not considered: this was my error ! It is incredible, but responsible for the CPU usage drift was the continuous 'statusbar' updating !  This instruction : StatusBar.Panels[X].Text:= '...Some status text... ';     where X is the destination panel, called each time that TTImer is fireup cause a continuos CPU % increase (around to 1% each 2 minutes). It was enough remove this statement and the CPU usage is now stable and smooth !!! I have to do more control, but this issue is not present in Windows environment, and is not present in other library object, like simple LABEL... I hope this information will be useful, in the future, to someone. Thanks to all forum users for support and help. ---------------------------------------------------------------------- ziocharly · 2015-05-18 20:09 ? How to ? The problem on statusbar text assignement has been confirmed ! In order to fix this issue, on status bar object, how it's possible to sent the official report to Lazarus developpers? Someone have idea how to do? Thanks. ---------------------------------------------------------------------- Cyrax · 2015-05-18 23:18 Update status bar only in specific periods, like after 100 or 1000 TTimer events. ---------------------------------------------------------------------- ziocharly · 2015-05-19 08:11 @Cyrax your suggestion delay only the problem, don't solve... From my point of view the 'statusbar' behavior need to be fixed !