Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. QElapsedTimer reporting strange values from within QThread
QtWS25 Last Chance

QElapsedTimer reporting strange values from within QThread

Scheduled Pinned Locked Moved Solved Mobile and Embedded
21 Posts 5 Posters 2.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • JeKK666J JeKK666

    I changed the WheelProbeThread to subclass QObject instead of QThread, changed its void run() method to be a void process() slot, and added the folllowing in the main thread:

        QThread *t = new QThread();
        wheelProbeMonitor->moveToThread(t);
        connect(t, SIGNAL(started()), wheelProbeMonitor, SLOT(process()));
        t->start();
    

    following the directions given here, but unfortunately the glitches didn't stop (value to be read should be consistent around 200):
    debugger screenshot
    I'm getting even more inclined to think this doesn't concern Qt at all, as much as the underlying scheduler or the sysfs library, although i'm still open to any other suggestion to improve the Qt part.

    Thanks,
    Jack

    CP71C Offline
    CP71C Offline
    CP71
    wrote on last edited by CP71
    #7

    @JeKK666
    Maybe you already moved the following code into the process function!

    speedTimer = new QElapsedTimer();
    speedTimer->start();

    If not I'd try

    JeKK666J 1 Reply Last reply
    0
    • CP71C CP71

      @JeKK666
      Maybe you already moved the following code into the process function!

      speedTimer = new QElapsedTimer();
      speedTimer->start();

      If not I'd try

      JeKK666J Offline
      JeKK666J Offline
      JeKK666
      wrote on last edited by
      #8

      @CP71 If i understand correctly, you are referring to the issue where objects in the QThread object constructor are actually instantiated by the parent thread: i thought this problem would be bypassed by using the worker thread way suggested by @KroMignon

      Still haven't learned Lambdas...

      CP71C 1 Reply Last reply
      0
      • JeKK666J JeKK666

        @KroMignon yes i do; is that conceptually wrong?

        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #9

        @JeKK666 maybe you should give your processor/process time to actually write into that file, that you're polling?

        I'm unsure how the system will handle such a permanent poll!

        Add a msleep to that of maybe 1 ms ? (200ms to 1 seems like a decent enough resolution)


        Not the kind of advice I give often :P


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply
        0
        • JeKK666J JeKK666

          @CP71 If i understand correctly, you are referring to the issue where objects in the QThread object constructor are actually instantiated by the parent thread: i thought this problem would be bypassed by using the worker thread way suggested by @KroMignon

          CP71C Offline
          CP71C Offline
          CP71
          wrote on last edited by
          #10

          @JeKK666
          From my experience is better to allocate any objects into run/process for thread affinity.

          From maya post:

          627a568e-0196-413d-ba16-e6aacf8bb957-image.png

          JonBJ 1 Reply Last reply
          0
          • JeKK666J JeKK666

            @KroMignon yes i do; is that conceptually wrong?

            KroMignonK Offline
            KroMignonK Offline
            KroMignon
            wrote on last edited by KroMignon
            #11

            @JeKK666 said in QElapsedTimer reporting strange values from within QThread:

            yes i do; is that conceptually wrong?

            As written before, using a forever loop will lock the event loop, so no signal/slot are handled for all instances runing in this thread.
            I would suggest you to:

            • create the QEleapsed timer in the rigth thread
            • call processEvents(QEventLoop::AllEvents);in foreverloop
            void WheelProbeThread::run() {
                char* buf[4];
                short len;
            
                QElapsedTimer speedTimer;
                speedTimer.start();
                while (1) {
                    pollRetVal = poll(pollingFileDescriptors, 1, -1);
                    if(pollingFileDescriptors[0].revents & POLLPRI) { //probe click
                        len = read(pollingFileDescriptors[0].fd, buf, 4); //mandatory to make system register interrupt as served
                        lseek(pollingFileDescriptors[0].fd, 0, 0);
                        emit probeClick();
                        emit timeBetweenClicks(speedTimer.restart()); //measure delta t between read pulses
                    }
                    QThread::currentThread()->eventDispatcher()->processEvents(QEventLoop::AllEvents);
                }
            }
            

            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

            J.HilkJ 1 Reply Last reply
            1
            • CP71C CP71

              @JeKK666
              From my experience is better to allocate any objects into run/process for thread affinity.

              From maya post:

              627a568e-0196-413d-ba16-e6aacf8bb957-image.png

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #12

              @CP71
              Suggestion from me. (I know nothing about devices/embedded/real-time! Nor about bicycles.)

              If @KroMignon's latest sorts you out, well and good.

              Otherwise, given your use of poll(), can't you write a test, standalone, non-thread, non-UI, non-even-Qt command-line program which just sits and returns the times? Having by-passed everything else, at least you then know whether your timings are just they way they are because they are generated like that from whatever lower-level?

              CP71C 1 Reply Last reply
              3
              • JonBJ JonB

                @CP71
                Suggestion from me. (I know nothing about devices/embedded/real-time! Nor about bicycles.)

                If @KroMignon's latest sorts you out, well and good.

                Otherwise, given your use of poll(), can't you write a test, standalone, non-thread, non-UI, non-even-Qt command-line program which just sits and returns the times? Having by-passed everything else, at least you then know whether your timings are just they way they are because they are generated like that from whatever lower-level?

                CP71C Offline
                CP71C Offline
                CP71
                wrote on last edited by
                #13

                @JonB
                Don't warry! You, be patient with my English! ;)

                Did you move the creation of QEleapsedTimer?
                Did you see any improvements?

                1 Reply Last reply
                0
                • JeKK666J Offline
                  JeKK666J Offline
                  JeKK666
                  wrote on last edited by
                  #14

                  @J-Hilk thanks, i tried to add a QThread::msleep(1) after fseek, didn' seem to make a percivable difference; also, please note that no file writing occurs on my side, unless we consider the cursor moving performed by fseek as writing.

                  @CP71 thanks, i also tried your suggestion by moving all the allocations in the run() method/process() slot, didn't seem to change the overall behavior.

                  @KroMignon thank you for your interest in my question; i'm sorry i don't fully understand your statement concerning "no signal/slot are handled for all instances runing in this thread": it seems to me that you are implying my code should not work at all because of the infinite loop, but that clearly isn't a problem: the thread is descheduled as soon as its operations are done, i.e. when hitting the next blocking poll(), so that the main thread can resume and carry on execution with the values reported via the timeBetweenClicks signal; could you please elaborate more?

                  @JonB that is the silliest and most brilliant suggestion i could have dreamed of... >.<'
                  it occured to me while reading your post that i have already cross compiled at least five CLI c programs that test hardware and its functionalities, so obviously the first thing to do would be to test the whole lower level below Qt...
                  Excellent point!

                  Still haven't learned Lambdas...

                  KroMignonK 1 Reply Last reply
                  0
                  • KroMignonK KroMignon

                    @JeKK666 said in QElapsedTimer reporting strange values from within QThread:

                    yes i do; is that conceptually wrong?

                    As written before, using a forever loop will lock the event loop, so no signal/slot are handled for all instances runing in this thread.
                    I would suggest you to:

                    • create the QEleapsed timer in the rigth thread
                    • call processEvents(QEventLoop::AllEvents);in foreverloop
                    void WheelProbeThread::run() {
                        char* buf[4];
                        short len;
                    
                        QElapsedTimer speedTimer;
                        speedTimer.start();
                        while (1) {
                            pollRetVal = poll(pollingFileDescriptors, 1, -1);
                            if(pollingFileDescriptors[0].revents & POLLPRI) { //probe click
                                len = read(pollingFileDescriptors[0].fd, buf, 4); //mandatory to make system register interrupt as served
                                lseek(pollingFileDescriptors[0].fd, 0, 0);
                                emit probeClick();
                                emit timeBetweenClicks(speedTimer.restart()); //measure delta t between read pulses
                            }
                            QThread::currentThread()->eventDispatcher()->processEvents(QEventLoop::AllEvents);
                        }
                    }
                    
                    J.HilkJ Offline
                    J.HilkJ Offline
                    J.Hilk
                    Moderators
                    wrote on last edited by
                    #15

                    @KroMignon said in QElapsedTimer reporting strange values from within QThread:

                    As written before, using a forever loop will lock the event loop, so no signal/slot are handled for all instances runing in this thread.

                    the OP only emits a signal, that is handled in the parent thread with an even loop running, so that should be no problem here


                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    1 Reply Last reply
                    1
                    • JeKK666J JeKK666

                      @J-Hilk thanks, i tried to add a QThread::msleep(1) after fseek, didn' seem to make a percivable difference; also, please note that no file writing occurs on my side, unless we consider the cursor moving performed by fseek as writing.

                      @CP71 thanks, i also tried your suggestion by moving all the allocations in the run() method/process() slot, didn't seem to change the overall behavior.

                      @KroMignon thank you for your interest in my question; i'm sorry i don't fully understand your statement concerning "no signal/slot are handled for all instances runing in this thread": it seems to me that you are implying my code should not work at all because of the infinite loop, but that clearly isn't a problem: the thread is descheduled as soon as its operations are done, i.e. when hitting the next blocking poll(), so that the main thread can resume and carry on execution with the values reported via the timeBetweenClicks signal; could you please elaborate more?

                      @JonB that is the silliest and most brilliant suggestion i could have dreamed of... >.<'
                      it occured to me while reading your post that i have already cross compiled at least five CLI c programs that test hardware and its functionalities, so obviously the first thing to do would be to test the whole lower level below Qt...
                      Excellent point!

                      KroMignonK Offline
                      KroMignonK Offline
                      KroMignon
                      wrote on last edited by KroMignon
                      #16

                      @JeKK666 said in QElapsedTimer reporting strange values from within QThread:

                      thank you for your interest in my question; i'm sorry i don't fully understand your statement concerning "no signal/slot are handled for all instances runing in this thread": it seems to me that you are implying my code should not work at all because of the infinite loop, but that clearly isn't a problem: the thread is descheduled as soon as its operations are done, i.e. when hitting the next blocking poll(), so that the main thread can resume and carry on execution with the values reported via the timeBetweenClicks signal; could you please elaborate more?

                      Sorry, my failure. The problem is only if you want to handle slots with this thread. By emitting a signal, the event is stored in the receiver thread event loop. So if this loop is not locked, there is no problem.

                      But as @JonB suggest, you should look with a simple C program if the problem is not at low level (driver and/or system level).

                      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                      1 Reply Last reply
                      1
                      • JeKK666J Offline
                        JeKK666J Offline
                        JeKK666
                        wrote on last edited by
                        #17

                        So, i'm back with results from the lower levels:
                        console screenshot

                        After logging a 100 values or so, results would suggest the problem lies somewhere in the Qt infrastructure; might as well be some unknown (to me) overhead, or some werid stuff going on about QElapsedTimer.

                        The next logical step, to me, would be to try using the simpler c code i wrote for the CLI program that runs in the screenshot to exclude QElapsedTimer from the equation, and see what results i can get.
                        Thanks @JonB for reminding me of stuff i made in the last year or so, at work, which i had completely forgot about!
                        We'll see how it goes from there.

                        Thanks,
                        Jack

                        Still haven't learned Lambdas...

                        1 Reply Last reply
                        1
                        • JeKK666J Offline
                          JeKK666J Offline
                          JeKK666
                          wrote on last edited by
                          #18

                          I've substituted the QElapsedTimer with the C library time.h, using the clock_gettime(...) function in the same way i did in the cli test program: i get the same inconsistent results, nothing changed (implementation as described here).

                          I can then conclude it's not the fault of the QElapsedTimer class, instead it has likely more to do with QThread, or threads in general, anyways the system i devised does not seem reliable enough to do what i need.

                          Since the CLI program itself seems quite precise instead, i might as well run something similar in the background, and the use IPC to retreive the value from Qt, or perhaps i could simply write the value to a file on one side and read it from Qt.

                          Still haven't learned Lambdas...

                          1 Reply Last reply
                          0
                          • JeKK666J Offline
                            JeKK666J Offline
                            JeKK666
                            wrote on last edited by JeKK666
                            #19

                            Update! @JonB
                            While i was tampering and not making any useful test, i accidentally left the CLI program running in an ssh shell, telling me the time deltas between clicks, and i noticed that everything was going fine, until... i launched the Qt application.
                            All of a sudden i was getting the same randomly halved times in CLI as i was getting before within Qt, using QElapsedTimer!

                            This begged further investigation, and i was able to determine that the glitches persist even after the Qt app is closed, until the next reboot; this led me to think that there is something that I did during the app initialization that messed up some system timers or whatnot.
                            So the first test that i performed was to remove my whole application from its cointainer (basically everything is contained within the mainwindow class) and running only this snippet, which prints an image on the framebuffer and then loiters around doing nothing:

                            #include <QSplashScreen>
                            //#include <QApplication>
                            #include "mainwindow.h"
                            
                            int main(int argc, char *argv[]) {
                            	QApplication a(argc, argv);
                            
                            	QPixmap pixmap(":images/logo.jpg");
                            	QSplashScreen splash(pixmap);
                            	splash.show();
                            
                                // MainWindow w;
                            	// w.show();
                                
                                return a.exec();
                            }
                            

                            Surprisingly enough, this was enough to witness the glitches on the interrupt's time reading... so, do i have to conclude that the Qt framework in itself has a way of messing around with my system, rendering it unusable even after the Qt application is closed?
                            Perhaps it's too heavy for the CPU or stuff? Or maybe i should find a more up to date BSP, which might contain several bugfixes and hopefully concerning this specific use case?

                            I also narrowed down that the exact reason of why the reported times are almost exactly half of the nominal time, the reason being the interrupt is fired twice (or poll() returns twice, who knows), but why would such a thing happen or how is this related to the Qt application being executed is far beyond me...

                            For now it looks like i'll have to use different hardware, unless some miracle happens.
                            Thanks,
                            Jack

                            Still haven't learned Lambdas...

                            JonBJ 1 Reply Last reply
                            0
                            • JeKK666J JeKK666

                              Update! @JonB
                              While i was tampering and not making any useful test, i accidentally left the CLI program running in an ssh shell, telling me the time deltas between clicks, and i noticed that everything was going fine, until... i launched the Qt application.
                              All of a sudden i was getting the same randomly halved times in CLI as i was getting before within Qt, using QElapsedTimer!

                              This begged further investigation, and i was able to determine that the glitches persist even after the Qt app is closed, until the next reboot; this led me to think that there is something that I did during the app initialization that messed up some system timers or whatnot.
                              So the first test that i performed was to remove my whole application from its cointainer (basically everything is contained within the mainwindow class) and running only this snippet, which prints an image on the framebuffer and then loiters around doing nothing:

                              #include <QSplashScreen>
                              //#include <QApplication>
                              #include "mainwindow.h"
                              
                              int main(int argc, char *argv[]) {
                              	QApplication a(argc, argv);
                              
                              	QPixmap pixmap(":images/logo.jpg");
                              	QSplashScreen splash(pixmap);
                              	splash.show();
                              
                                  // MainWindow w;
                              	// w.show();
                                  
                                  return a.exec();
                              }
                              

                              Surprisingly enough, this was enough to witness the glitches on the interrupt's time reading... so, do i have to conclude that the Qt framework in itself has a way of messing around with my system, rendering it unusable even after the Qt application is closed?
                              Perhaps it's too heavy for the CPU or stuff? Or maybe i should find a more up to date BSP, which might contain several bugfixes and hopefully concerning this specific use case?

                              I also narrowed down that the exact reason of why the reported times are almost exactly half of the nominal time, the reason being the interrupt is fired twice (or poll() returns twice, who knows), but why would such a thing happen or how is this related to the Qt application being executed is far beyond me...

                              For now it looks like i'll have to use different hardware, unless some miracle happens.
                              Thanks,
                              Jack

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by
                              #20

                              @JeKK666
                              I don't know. It would be interesting if someone else comments, because they will know more than I. But your claim/finding that having had a Qt program show a splashscreen and then exit, and still affect timings after that, sounds fishy.

                              Qt doesn't somehow do things which are not provided by your OS. It just makes appropriate calls. If there is something wrong in its code that would be a Qt bug, but otherwise it's down to your OS.

                              Since this has become a discussion, there is one thing I don't get, and I hope an expert will clarify. My lack of understanding is because I know nothing about embedded/Yocto. For a desktop Linux or Windows at least, it seems to me: you are relying on a timer to tell you how far apart some events are. But how do you know when your thread or process will be scheduled for a time slice? In a desktop OS at least, after your poll() gets notified of one event, it could take ages and miss events till the next time that piece of code with the poll() gets called again. Is that not right?

                              JeKK666J 1 Reply Last reply
                              0
                              • JonBJ JonB

                                @JeKK666
                                I don't know. It would be interesting if someone else comments, because they will know more than I. But your claim/finding that having had a Qt program show a splashscreen and then exit, and still affect timings after that, sounds fishy.

                                Qt doesn't somehow do things which are not provided by your OS. It just makes appropriate calls. If there is something wrong in its code that would be a Qt bug, but otherwise it's down to your OS.

                                Since this has become a discussion, there is one thing I don't get, and I hope an expert will clarify. My lack of understanding is because I know nothing about embedded/Yocto. For a desktop Linux or Windows at least, it seems to me: you are relying on a timer to tell you how far apart some events are. But how do you know when your thread or process will be scheduled for a time slice? In a desktop OS at least, after your poll() gets notified of one event, it could take ages and miss events till the next time that piece of code with the poll() gets called again. Is that not right?

                                JeKK666J Offline
                                JeKK666J Offline
                                JeKK666
                                wrote on last edited by JeKK666
                                #21

                                @JonB I'll try to explaining as per my understanding.
                                The sysfs library provides some sort of "abstraction layer removal": the endpoint on which poll() is called represents a hardware resource (in this case a GPIO pin) made accessible in user space; it allows creation of a construct which resembles registering an interrupt service routine to react to an asynchronous event in the most timely manner, much as you would do in a microcontroller.
                                In Linux, hardware level access is restricted to kernel space applications, so one would need to write his own driver that access memory locations corresponding to, for instance, GPIO registers, register an IRQ number and all other sorts of voodoo I'm not very familiar about, having worked mostly with bare microcontrollers (no FreeRTOS involved).

                                So, when you call poll() on the sysfs endpoint the thread blocks, waiting for a level change on the pin, coherent with the edge selected; once the transition occurs, the interrupt fires and sysfs will notify (somehow) the thread polling the endpoint, allowing it to execute ASAP.
                                It has its limits compared to a kernel driver, but for my frequency range (10-20hz) headroom should be plenty.
                                Same rules for basic ISRs apply, so code executed must be minimal, like setting a flag and let the main thread do the heavy lifting, or in this specific case compute the difference between the time now() and the last time this function was called.

                                Sysfs itself is quite dated, i read somewhere that the version I'm using was deprecated some 3 years ago, but with the module i have it's the simplest option available.

                                I totally agree with your observations about the issue being in the OS, somewhere, for now I'll just move on to the next toy project, but i will regularly check back on this thread to see if more impressions come in, an apparently simple issue revealed itself to be a rather intricate mess :)

                                Still haven't learned Lambdas...

                                1 Reply Last reply
                                3

                                • Login

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved