Dealing with routines that need time (Android)

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
When you have a routine that takes up more time than a frame, you'll be sure that Android will go beserk and ask you to wait or quit the app. It's a dealbreaker everytime. It does not help that you put this code in OnUpdate. So I was thinking, Is there a way to start a thread?

The other platforms does not seem to need such a thing even. Only Android freeze up. I would love to see if anyone has a solution for it?
I was thinking to cut up the routine into pieces so that each piece could be done within a frame, but its easier said than done..

The msg that pops up in the console every time this happens always begins with :
"Poll() failed (interrrupted system call)"
 
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
Got the threading extracted and converted to cxs, but I don't know what to do with it yet. Maybe some other one can.

Regarding any examples I will have to check if I can produce some sensible examples.
So far I tried to splice the heavy algorithm and kind of succeeded. On Android its working stable and okayish speed.
Not even close to the instant all-in-one-go-within-one-frame that HTML and Desktop can deal with.

EDIT trying to create useful examples..

But threading, ya, this is interesting development!
 

Attachments

  • threading.zip
    15.5 KB · Views: 3
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
This was the simplest example I could come up with, that works on my Samsung Note2 (the screen goes completely blank it does not even start outputting graphcis becuse its overloaded). If you wait or tap the screen it will eventually give you the poll errormessge in the console.

*If* the device being test is so powerful that it *can* handle this particular example, then it should behave like it does on my HTML/DESKTOP meaning OnUpdate will cripple OnRender's speed.

You could add a zero or two in the for..next loop to try it to get behaviour on a powerful device.
So if you have a routine that you need to do that does not fit within a frame.. it might take say, ..5 sec.. it will do the same.
These things needs to be done in a safe low-priority thread.

Code:
Import mojo2

Function Main()
    New MyGame()
End Function

Class MyGame Extends App
  
    Field canvas : Canvas
    Field xx:Int = 0
  
    Method OnCreate()
        canvas = New Canvas
        SetSwapInterval 1
        SetUpdateRate 0
    End Method

     Method OnUpdate()
      
        For Local temp:Int = 0 To 100000000
        Next

    End Method
  
     Method OnRender()
         xx = xx + 1
         xx = xx Mod 600
         canvas.Clear 0,0,0 
      
             For Local y = 0 Until 256 Step 4
                 For Local x = 0 Until 256 Step 4
                    canvas.SetColor 1,0,0
                    canvas.DrawRect x*32,y*32,30,30
                Next
            Next
          
            canvas.DrawRect xx,100,80,80
        canvas.Flush
    End Method
  
End Class
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
If you touch the screen a lot on the example it can actually crash and close itself quickly.
 

SLotman

Active member
3rd Party Module Dev
Joined
Jul 3, 2017
Messages
173
Why are you doing a for loop up to 100 million? Of course that will freeze your device - you're counting to 100M at whatever you set your UpdateRate to. :p

If your update rate is 60, you are repeating that piece of code ~every 17ms. That's waaay to much.

Try setting your update rate to 1 and it will probably work out.
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
Why are you doing a for loop up to 100 million? Of course that will freeze your device - you're counting to 100M at whatever you set your UpdateRate to. :p

If your update rate is 60, you are repeating that piece of code ~every 17ms. That's waaay to much.

Try setting your update rate to 1 and it will probably work out.
Well I don't. If you read all the posts they all just a substitiion for a really heavy routine that you cannot cut into pieces.

Android does not seem to care about setting 0 versus 60 , i dont know if thats meant to be or is a bug. I tried 60 versus 0 and got the same speed. I never tried 1 though, and what if the routine is more than 1 second? its still not a perfect solution if that would work.
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
Besides, you have only ONE extra co-routine besides OnRender, and that's OnUpdate.. and that's where you do input output like keyboard reading.

You don't not want to use that single thread you have and being forced to read dpads and keyboard etc only once per second.
 
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
I tried OnUpdate 0.1 but of course only OnUpdate 1 worked. It would have been kind of nice but still we need fast inputs..

The perfect setup would be something like:

* A Render thread.

* A Fast thread for low impact but quick things like dpad/keys,touch etc). You wouldn't need more fast threads, as low impact things that only need slower updates could use Mike's new timer module from here.

* A slower low priority thread for heavy things that gets whatever time is left over. You could put a mixed load on to this, so you wouldn't need more threads. As long i'ts easy to add and throw away what the thread runs.
 
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
My solution for now became to take the algorithm and cut it to pieces and I made a flag so the first time you call it it goes through an initial process, while all the other times it just cycles through whatever it should do, and you call it repeatedly once (or a few times) every OnUpdate. Each call it does a suitable amount of work for a maximum of 3-14ms. Eventually one of the calls will leave you with a flag telling you its finished.

In a way its the opposite of timers; you dont' divide the time but you divide the actual chore.
It's not very intuitive, but it's okay for now.

EDIT That thread code looks really good for a later project for sure. Maybe it's possible to setup the ideal setup I described above using it.
 
Last edited:

SLotman

Active member
3rd Party Module Dev
Joined
Jul 3, 2017
Messages
173
If you read all the posts they all just a substitiion for a really heavy routine that you cannot cut into pieces.
I did read everything, and I highly doubt that your code can't be divided into smaller chunks. For example: if you are processing large images, try dividing them into chunks and processing one at a time. The same way a game is divided into 'states', you can apply the same logic for everything.

And of course UpdateRate 0 won't work: that will make your logic run as fast as possible, its just the opposite of what I suggested :p

If those aren't good enough solutions, you can always write the necessary code directly into JAVA and just import it into Cerberus. I've done it myself when I need voice synthesis and recognition - its not that hard to get something working. Just look at the default libs themselves to understand the workflow.
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
I managed to cut it down but I at the same time really hate the globals that I need to make it happen.
There's no way to have static local variables in Cerberus functions or methods right?

Because, you'll need variables that are kept alive inside the function from call to call. It would be so much better if they weren't accessible from the outside.
 

SLotman

Active member
3rd Party Module Dev
Joined
Jul 3, 2017
Messages
173
There's no way to have static local variables in Cerberus functions or methods right?
You can have Globals inside a Class:


Code:
Class MyClass
    Global globalVar:int
   
    Function func1()
        globalVar +=1
    End Function
   
    Method New()
        globalVar = 1
    End Method
End Class

Local mc:MyClass = new MyClass()
Print MyClass.globalVar ' prints 1
MyClass.func1()
Print MyClass.globalVar ' prints 2
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
Don't I have to say private for that?

Hmm I'm using functions though as that's where I am right now with the project, Is there any solutions for functions?
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
602
Don't I have to say private for that?
Yes, Private is needed if you want to forbid access to it from an other module. Be aware that Private doesn't restrict access from another class or functions from within the same module. So, you can basically have private globals that are used by your functions, if you put functions and globals into the same separate module.
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
Exactly what counts as a module?

I'm trying to find the best way of expressing myself in Cerberus while I'm learning. I tend to use this setup right now :
* main.cxs
* functions.cxs
* imports.cxs
(which only imports mojo2 and defines globals so far)

imports.cxs gets imported to both functions.cxs and main.cxs and this works fine so far,
but I might need to re-design everything now..
 
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
Got it working. From here I will try to get more elegant code when I see what more could be done. But this is a great start. Thanks!
 
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
This works great actually, I feel much better about coding Cerberus on Android now.
But the question remains *what* if a heavy routine happens because it could be an API call to the System? Something that takes time.
And you need to be able to resolve that, I guess callbacks is the way to go?
 
Top Bottom