Qt application core affinity

I’m using Boot2Qt on an apalis iMX8QP board. As the iMX8QP contains 4 Cortex A53 cores as well as a Cortex A73 core, I’d like to force the main thread of my Qt application to be executed only on the A73 core in order to gain in performance. So, at the start of my main(), I execute this function:

cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(coreNo, &mask);
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
    qCritical()<<"Error while executing sched_setaffinity to set affinity";
    assert(false);
}

The application is then executed on Core A73, but then all the different threads, whether created manually with QThread or automatically with QtConcurrent for example, are also executed on Core A73 and are not distributed between the other A53 cores. i understand that i could reuse sched_setaffinity at the start of each execution of other threads, but that’s not the point. so is there any way of forcing the main thread to run on a particular core without neglecting the use of the other cores by the subsequently created threads?

Hello @Romain.Donze

I am not aware of any other way, of doing it. According to the POSIX thread library,
pthread_create(3) - Linux manual page (man7.org)

The new thread inherits copies of the calling thread’s capability sets (see capabilities(7)) and CPU affinity mask (see sched_setaffinity(2)).

Why don’t you want to use this approach?

Best regards,
Josep

Following this thread. The reason to avoid the approach is that he wants to dedicate the thread to a specific code. Just read through the pthread create doc, and nothing is mentioned about using specific cores. Probably abstracted away.

Perhaps the OP needs to trust the OS to hand the cpu cores?

I’m going to chime in here because I’m a cranky old man and this is one of my industry wide pet peeves. I’m not belittling, disparaging, or attacking any singular individual though some might think that.

Let me also preface this by stating that if you are forced to use Qt you have my deepest sympathies. That application framework is really showing its age. The single-thread-i-ness of its design really hampers good development.

I started out in IT when the Commodore Super PET ruled the land. 8-inch floppies were on their way out and IBM had yet to even think about introducing the PC. Back there and then we were all forced to go to college to get a degree. On that educational journey we were forced to learn a great many things. None of us ever used the advanced math, but most of us used everything else.

This was the time of real computers and real operating systems. We neither had nor wanted threads. The process design of each OS was so robust it was trivial to create many sub-processes. The process level accounting was so complete we knew any process launched as a sub-process, though it was a full stand-alone process, would be cleaned up with the parent went away. The operating system charged every nanosecond of CPU, byte of memory, and block of storage to an account for each user. Many users were leasing time either directly or through a company and we charged for everything. An RL02 1.2 MEG removable disk pack cost $5,000, so yes, we charged for everything and the OS had to have that level of process accounting.

People who come from the platforms designed to have hundreds-to-thousands of simultaneous users always design from a process level, not thread. While we can and do use threads, we limit them to low priority things that don’t really matter.

Dennis Richie, when creating UNIX, was creating a single user OS that could run a few batch/background tasks. This was to be in stand-alone telephone switches and the whole terminal/login thing was just so someone could set up the switch or monitor it during trouble shooting. He created something so light it doesn’t even qualify as a thread on the bigger machines. Then he and/or the C language group created something even lighter they called a thread.

Linus was basically cloning UNIX despite how such a statement honks him off. He didn’t design it to handle thousands of interactive users charging back for every resource used. This is why Linux and UNIX are notorious for “dangling threads.” The problem has even bubbled its way to Java and many other VM based languages.

People who have never worked on anything other than an x86 or ARM based system (many of whom also never got an IT degree) try to do everything with threads. Sadly, threads are not a good tool. They are a roll of duct tape.

Docker containers are the latest attempt by the Linux world to fix a completely botched process design. You can read my previous answer about how to communicate across containers here. For instructions/pointers on how to assign containers to cores, start here.

If you are running a single executable under a Yocto built Linux, you can use the C system() function to create additional processes. You also need to install taskset in your build if it is not already there.
Doc showing how to move an existing PID to a core.

Launch a program from command line tied to a specific core.

Know this.

Because of the feeble process accounting in Linux, what you launch won’t go away when the launching process dies. You will have to defend against auto-launching processes that didn’t die when your primary fell over and got auto-restarted by some kind of watchdog application. A “lock file” is not a good or reasonable choice unless you are creating it on a RAM disk that goes away with restart.

Most people who didn’t work on the big stuff stumble bad when it comes to process synchronization and restart coordination so they reach for Docker. Not a perfect solution but a kinda-sorta-good-enough-for-many solution.

1 Like