Isotropix Forums

Use add_timer in Python

Clarisse Scripting related topics

Use add_timer in Python

Unread postby salmoukas » Wed Mar 18, 2020 12:51 pm

Hey guys,

I want to use ix.application.add_timer in Python. So far, I failed to reproduce the SWIG AppCallback type of the callback function. I tried to use ctypes.CFUNCTYPE and ctypes.cast to generate a void (*)(void*) signature, but the SWIG type check for that parameter failed regardless. Is there a way to solve this?

As a fallback I we used the ix.application.add_to_event_loop_single pattern, as shown in the pyqt_clarisse utility of Clarisse. It works very well, except it produces 100% CPU usage. Just for clarification: the 100% CPU usage results from the pattern itself, not from our routine we call. If we just use this pattern without calling our own routine, it generates 100% CPU too. I guess that installing an event loop callback results in a bypass of any wait operation in the main loop and it starts spinning. So my educated guess is that running any QT application within Clarisse results in 100% CPU usage too. Please correct me if I am wrong. Note: our routine just executes every X ms a cheap non-blocking socket select to check for new data (we call it only when X ms elapsed).

As another fallback we tried to implement EVT_ID_APPLICATION_IDLE using "ix.api.ClarisseApp.on_idle = on_idle" and "ix.application.connect(ix.application, ix.api.EVT_ID_APPLICATION_IDLE, ix.application.on_idle)" (just getting desperate ;-)). This results in a crash of Clarisse. I can provide the stack trace in case you are interested.

Well, I understand you do not want a crowded main loop. If I were able to use add_timer, it would not be a burden for Clarisse.

If there is no other way, we will fall back to what Bridge Livelink and Clarisse Survival Kit do and create a separate process which executes commands via the command port.

I am looking forward to your insights.

Kind regards

Niklas
salmoukas
 
Posts: 4
Joined: Tue Feb 04, 2020 9:37 pm

Re: Use add_timer in Python

Unread postby dcourtois » Wed Mar 18, 2020 1:49 pm

Hi Niklas,

Can you attach a small script reproducing the issue ? As you can see in the following screenshot, running a minimal PySide window using our pyqt_clarisse helper does not produce any high CPU usage, so I'm not sure what could go wrong on your side.

And as a side note, using the pattern in pyqt_clarisse is indeed the way to integrate something with Clarisse's main loop. I'm not sure what you were trying to do in the first part of your message, but that's definitely not the way it should work :)

pyqt_in_clarisse.png
User avatar
dcourtois
 
Posts: 75
Joined: Tue Jul 25, 2017 3:15 pm

Re: Use add_timer in Python

Unread postby salmoukas » Wed Mar 18, 2020 2:26 pm

Hey!

Thanks for the quick response.

Here is the test script:

python code

class ServerLoop:
def cycle(self):
# noop as show-case, our use case is to add some non-blocking socket select here
ix.application.add_to_event_loop_single(self.cycle)


ServerLoop().cycle()


Attached a screenshot showing 100% CPU usage on macOS. Is it an macOS issue? I haven't tested on Windows yet.
Attachments
Screenshot 2020-03-18 at 14.22.50.png
salmoukas
 
Posts: 4
Joined: Tue Feb 04, 2020 9:37 pm

Re: Use add_timer in Python

Unread postby dcourtois » Wed Mar 18, 2020 2:42 pm

Hmm this is weird... At most it should only throttle 1 of your cores, so unless you're using a monocore/thread machine (which I doubt :p) it should not use all the CPU...

I tested your script here, and it behaves as expected: it uses 1 core.
And if I just add a small sleep before adding the cb to the event loop, it falls back to 0%:

python code

import time

class ServerLoop:
def cycle(self):
# noop as show-case, our use case is to add some non-blocking socket select here
time.sleep(0.1)
ix.application.add_to_event_loop_single(self.cycle)

ServerLoop().cycle()


Can you try that and tell me how it behaves ?
User avatar
dcourtois
 
Posts: 75
Joined: Tue Jul 25, 2017 3:15 pm

Re: Use add_timer in Python

Unread postby salmoukas » Wed Mar 18, 2020 3:01 pm

I think 100% equals one core on macOS; otherwise, it would show numbers larger than 100%.

Still, there is a discrepancy between my case and the QT case. I feel it is not right to add a sleep to the main loop in our handler, as this might result in adverse effects for overall performance. And I want to note that there is no sleep in the python code in your pyqt_clarisse implementation. So if I start to add sleep, it will induce different behavior.

When I add the sleep to the handler, the Clarisse UI will become sluggish. Without it, the UI is responsive but consumes one core.
salmoukas
 
Posts: 4
Joined: Tue Feb 04, 2020 9:37 pm

Re: Use add_timer in Python

Unread postby dcourtois » Wed Mar 18, 2020 3:14 pm

Ah sorry we're working remotely due to the circumstances, so I didn't notice the sluggishness of the UI.
Can you try the following:

python code

class ServerLoop:
def cycle(self):
# noop as show-case, our use case is to add some non-blocking socket select here
ix.application.add_to_event_loop_single(self.cycle)
ix.application.check_for_events()

ServerLoop().cycle()
User avatar
dcourtois
 
Posts: 75
Joined: Tue Jul 25, 2017 3:15 pm

Re: Use add_timer in Python

Unread postby salmoukas » Wed Mar 18, 2020 3:40 pm

Excellent, yes, way better!

I called check_for_events in my code first, but the order does not seem to matter.

Code: Select all
class ServerLoop:
    def cycle(self):
        # noop as show-case, our use case is to add some non-blocking socket select here
        ix.application.check_for_events()
        ix.application.add_to_event_loop_single(self.cycle)


Looks like my issues are solved! THANKS AGAIN! :-)
salmoukas
 
Posts: 4
Joined: Tue Feb 04, 2020 9:37 pm


Return to Scripting