MonkeyX speed

Monkey Archive Forums/Monkey Discussion/MonkeyX speed

zxretrosoft(Posted March) [#1]
Hello guys,

I have a little concern.

I'm trying to do a simple counter, it seems to me that it is MonkeyX very slow :/ (I have not tried Monkey2.)
(Target Desktop_Game_(Glfw3), HTML5 is much slower.)
If I do the same thing in a different language, it's much faster.

Time counting 0-1000:
MonkeyX 16,31 sec.
AGK2 1,86 sec.
PureBasic 0,1 sec.





Gerry Quinn(Posted March) [#2]
Monkey is updating and rendering 60 frames per second, and adding 1 to the count every frame.. just like you told it to! Total time 1000/60 = 16 seconds.

Your results don't really have anything to do with Monkey's speed. It's spending all its time just waiting for the next update. If you control the frame rate and count the same way in the other languages, you'll get the same result.

You should have no trouble getting 60 frames per second with plenty of things happening on screen. It's as fast as many other languages used for computer games nowadays.

To put it another way: every frame you add one to a count and print a string. But you could do a thousand things like that every frame, and it would run just as fast.


zxretrosoft(Posted March) [#3]
It also occurred to me. But if there is for example SetUpdataRate 1000, speed is the same. Unfortunately.


Gerry Quinn(Posted March) [#4]
I think there's a limit - you can't update faster than you can render, and 60 frames per second may be the maximum that can be shown. But regardless of that, there's no issue here to worry about. For example, try putting this in your render loop:



Instant 'speed up' by a factor of 10... and you can make it 100 if you don't mind the text going on top of itself!

If you run some of the examples in 'bananas', you'll see that they work fine. I'm sure there are some that paint lots of things on the screen.

Monkey is certainly not designed to be a super high performance language, but for 99% of users it will be more than fast enough.


zxretrosoft(Posted March) [#5]
Yes, I understand. I wanted to try to use MonkeyX for a complicated calculation. And I got there a billion combinations, so for this example, speed is important.
It is a pity that there is the limit. But, well, thank you for your answer! I was interested.

I assume that the same situation is with Monkey2.


Gerry Quinn(Posted March) [#6]
To do a complicated calculation at max speed, do it in App.OnCreate() and don't print out the results until it's done! Why render when you could be calculating?

The desktop target is the fastest as it will be compiled to C++. Monkey probably won't give the fastest possible C++ translation, but it will be fast enough. Quite likely within a factor of 2-3 of what you would get with [non-fancy] native C++. Maybe even identical, depending on the problem and how you go about it.

Seriously, the limit you have found is simply a limit on how many times you can print to the screen every second. It has *nothing* to do with how fast calculations can be done. I would guess that the Monkey desktop target would typically be faster than standard Java for such calculations. And dozens of times faster than Python. Lots of people use Java and Python for complicated calculations.



Result 1250025000... and it's almost instant.


zxretrosoft(Posted March) [#7]
Wow, cool! Thank you very much - a big help!

Please, you could still prove to be a whole code? I'll try it then do it after the weekend. I am now on PC sporadically. Thank you!!!


Gerry Quinn(Posted March) [#8]
There's nothing more to do... just stick what I posted at the start of OnCreate() in your current program, or any other program! (The only change you have to make is to change the name of count, or else delete where you defined a variable of the same name.) It will add up all the numbers from 1 to 50000, print the results, and then carry on with the rest of the program exactly as before.

Basically, if you just want to do a lot of calculations, you don't need all the updating and rendering stuff. Those are for just for presenting apps with a nice user interface.


zxretrosoft(Posted March) [#9]
Yes I understand. Thank you very much, Gerry! ;-)

So, I've done my whole calculation that I need. Everything is well, it seems that it is too fast.
(It calculates the combination of the times and the best combined time (sum) will print on the screen.)

Now, the problem is that MonkeyX included no GOTO command :D

If I do it this way over jumps on methods, so there is early error: "maximum call stack size exceeded". Otherwise everything (see the first calculations at the beginning) works correctly.




DruggedBunny(Posted March) [#10]
Your OnCreate function seems to call itself in certain circumstances, and is also called by dal(), but it's so complicated I can't tell what's meant to be happening... perhaps some of the code inside OnCreate should just be in a separate function that's called by OnCreate and dal()?

Also, it doesn't look like you need the mojo framework for this code. Mojo is event/callback-based, which doesn't seem liike the right fit for this procedural code. Perhaps it could just be placed in a Main () function, plus dal (), with the OnCreate () code placed in a separate function?

That way you can ignore the frame-waiting that comes with event-based Mojo...

Eg.

Function Main ()

    If ... 
        dal ()
    Else
        OtherStuff ()
    Endif

End Function

Function dal ()
    ...
End Function

Function OtherStuff ()
    ' The code from OnCreate goes here
End Function



Gerry Quinn(Posted March) [#11]
You know you can still use different classes, functions etc. freely? The only reason to call at the start of OnCreate() is to do everything before mojo starts up its update-render framework. You could even do everything in Monkey's Main() function, without importing mojo at all, and print to the console. I see you are calling OnCreate() recursively - that's not really ideal though i'm not certain what you are trying to do. It's possible that structuring it that way is causing unnecessary stuff to be done, and certainly the multiple calls to Seed( Millisecs() ) probably shouldn't be happening.

If the call stack gets exceeded, you probably can adjust it in the C++ compiler (and there are other ways to get around the absence of a goto statement). But I think the default stack size is at least 1 MB anyway, so exceeding it is normally due to either putting something on it that's too big (e.g. all your pixels in a bad flood-filling algorithm), or else a bug.

I think you are getting too hung up on complications that don't really exist. What you are doing is the sort of thing that needs very little framework. Mojo starts up with a framework suited to making apps, but you don't have to go through it - you can just ignore it by doing everything before it starts up - i.e, in OnCreate().

Try something like this:



Feel free to include all sorts of extra methods or classes. You don't have to worry about anything special with regard to mojo.App etc.


zxretrosoft(Posted March) [#12]
I think you understand it very well. Thanks a lot!!

Your code gives me an error "Type 'App' not found". I am doing something wrong?


Gerry Quinn(Posted March) [#13]
Sorry, it wasn't meant to be a complete program. You'll need to import mojo (or just mojo.app) as usual since the App class is being extended. And I think you need to import it to get the Millisecs() function anyway.

Here is a complete calculation program that doesn't use app at all. It imports mojo.app just so it can call Millisecs():




In practice, it's no different doing it this way or doing it in App.OnCreate(). If your program generated graphics, you'd want to put in in an app, so you can render it nicely afterwards.


zxretrosoft(Posted March) [#14]
Gerry Quinn
Thank you, I will try to do so! It is actually an infinite calculation where again and again throws random numbers (0-17 with certain conditions), and then examines the time between them. If it is better, it will print.

DruggedBunny
Thank you, I will try this case too. Thanks! ;-)


Gerry Quinn(Posted March) [#15]
Maybe the infinite loop is why you had issues with the call stack. A structure like this might work better - you can see how there is effectively a 'goto start' if the results are not interesting enough to print:




zxretrosoft(Posted March) [#16]
Hmmm, it seems that it does not work. Probably I am doing something wrong. It seems that the Method 'New' remain unnoticed...

This is a transcript of the program into your structure.





To illustrate, here's how it works in Basic AGK2.
(Below is the sum of the times and the line is only informative number of combinations.)

https://www.youtube.com/watch?v=W55sWQY3IdY


And this is a functional code in AGK2 (to illustrate).



And this - to illustrate - in PureBasic:




Gerry Quinn(Posted March) [#17]
When I ran it, I got maximum call stack exceeded. The problem is due to InitData() calling itself. That's not my structure :)

More generally, though, you'd probably get the same if Calculate() called itself recursively the same way. Recursion only works if there's something that will stop it and go back eventually. You are using recursion where you need a loop. I don't know PureBasic but I see it has a Do loop. In Monkey the equivalent of Do is Repeat.

There are no labelled breaks in Monkey, but a properly structured program doesn't need them.


Gerry Quinn(Posted March) [#18]
[EDIT: my first fix was bugged, correct version now]

[EDIT AGAIN: I thought I fixed it, but I didn't. Seems Repeat.. Until True doesn't work with Continue. But I changed it to a For loop, and I think the problem is that your data never reaches the correct conditions. At least not in 1000 runs.

Anyway, the original was crashing because conditions were never achieved and the call stack filled up before a result was found.


Okay... I think I fixed it. See how InitData() works now... it keeps trying until it gets a set it likes, then finishes. No recursion needed. I also changed Seed = Millisecs() so it is only called once. Since I don't understand your program, I don't know if the output is correct, but at least there is output :)

The only changes I made are at the start and end of InitData()



Output:



Anyway, you can do your infinite loop this way, maybe it will stop eventually!




zxretrosoft(Posted March) [#19]
Hm, the first case seems to be OK, but then it's not looking for a better time.

OK, my English is terrible, but I'll try to explain it.
We solve one interesting thing:) it's a hell of a puzzle :)

This is a solution in the game the Saboteur II ( http://www.clivetownsend.com )

1. In the game is 15 tapes
2. In the game is 1 terminal (No. 17)
3. In the game is the 1 button to turn off the fence (No. 16).

Here is my map:


The aim is to collect 14 tapes, put them into the terminal and off the fence.
It follows that the penultimate or last must be No. 17 (Terminal). The fence you can turn off at any time.

pp=14 'počet pásek = required number of tapes (English)
x1 'number of tapes in combination
x2 'if the fence off (1=OK)



You can start collecting from the No. 1, No. 2, No. 3 or No. 4.



The condition is that you must have 14 tapes, so that you could put into the terminal.

(Small condition is that the tape No. 6 and No. 7 are close together, so that is a random field, always I'll connect. i.e. tapes 6 and 7 are always behind.)



I know the times between individual tapes (1-2, 1-3, 1-4, 1-5.... 2-1, 2-3.... etc.). That is, all combinations. But for collect all tapes is there a permutations of 15! It is over 1000 billions.

I believe that the tape No. 15 is so far away that it is not to be expected. Therefore, I discarded it (ie. I give at the end of the field).



I'm looking for the best path, with the shortest amount of time.
(The best combination I've found so far is 647.5 sec. 1-3-4-5-6-7-8-9-10-11-12-13-2-16-14-17)

The program simulates browsing of this game. The program attempts to randomly shuffle the array (with those terms, see above). Add up the individual times. If the time is better than the previous, so it prints (like here: https://www.youtube.com/watch?v=W55sWQY3IdY )

When the program fast enough (and I hope that the MonkeyX will be the fastest), I can find the time the best way ever. (PureBasic is unfortunately quite slow, the AGK2 even slower.)

I hope it's understandable :-))
Once again I apologize for the English! Thank you for everything! ;-)


Gerry Quinn(Posted March) [#20]
Interesting! A way of generating all permutations would be faster, but the random method has the advantage of being easy to program.

I think that for code like this, Monkey will be pretty fast. The problem is intrinsically slow, and language speed only multiplies it by a constant factor. One improvement would be to replace the Select statement in 'kontrola posbíraných pásek with If a[i] >= 1 Or a[i] <= 15.


muddy_shoes(Posted March) [#21]
OP, you're trying to solve a version of the travelling salesman problem. It's a well studied problem in computer science so you might benefit from reading at least the Wikipedia page to get some idea of what you're tackling. If you're not just coding your own solver for fun you'll likely find existing code/tools that you can make work for you.


zxretrosoft(Posted March) [#22]
Yes, it's a nice problem. But I believe that I'm dealing with it correctly.. This is a typical heuristic algorithm. In PureBasic it works (see above), now I'm trying to override it in MonkeyX - and it is not easy. But I believe that MonkeyX will be the fastest ;-)


Gerry Quinn(Posted March) [#23]
I honestly don't know anything about PureBasic speed. But chances are that it is also fast enough. It won't be three times slower than Monkey, or three times faster. Which means three days running the slower language will be better than one day running the faster one.

The only commonly used language that I see people really getting into trouble with due to its general (lack of) speed is Python. And that's mostly for real-time stuff. For your purposes, language speed shouldn't really matter. Just set up your program so you can let it run overnight. If you are not comfortable with saving and reading files, just type in the old best time before you start each run! (Actually, with your random system, you don't even need to to that.)


muddy_shoes(Posted March) [#24]
I've had a bit of a look at your code and I have a few suggestions:

1. Your code seems to have been written based on arrays with the index starting at 1. Monkey arrays are indexed from 0. Somewhere along the line this is going to trip you up.
2. Look at changing InitData to always generate a valid route. There's no reason to be generating invalid routes that are then rejected by a test.
3. Replace your enormous If elseif elseif elseif... construction in Calculate with a two dimensional array. The whole thing can be reduced to a simple costArray[a][b] lookup and it will be far faster.

With changes 2&3 and the desktop target I'm seeing around 2 million routes per second on my i5 laptop, which brings just brute force searching every possibility over a few days within reach even if you don't want to look into fancier algorithms.


zxretrosoft(Posted March) [#25]
Thank you very much!

Please, have you the code in MonkeyX? Rather whole. Still I can not do the right version.


zxretrosoft(Posted March) [#26]
OK, maybe try all combinations.

How do I make algorithm array where all the permutations?

First combination, Start:



First combination
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17

Second combination
2,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17

Third combination
2,3,1,4,5,6,7,8,9,10,11,12,13,14,15,16,17

etc.


Gerry Quinn(Posted March) [#27]
This might help you: it's Java code for the Johnson Trotter algorithm:

http://introcs.cs.princeton.edu/java/23recursion/JohnsonTrotter.java.html

(There are others - I picked Java because it may be the easiest to translate into Monkey, but I could be wrong.)


muddy_shoes(Posted March) [#28]
Here's the code I played around with. You'll need to check over the specifics as I'm not entirely clear on the rules you're applying. By the way. I put the costs in a TSP solver I coded up a while back and it found [4,5,7,6,8,9,10,11,12,13,3,1,2,16,14,17]. It's not an exhaustive solver so that may not be the shortest route even if I've got the rules/costs correct but maybe it's of use to you.




zxretrosoft(Posted March) [#29]
Thank you very VERY much! Brilliant, that is exactly it!

It works correctly, by me. I just a little bit don't understand how it works field Field costs: Float [] [] = [
I explore it. It's an elegantly optimized :)


Gerry Quinn:
Thanks a lot, I can rewrite it to a MonkeyX, it will be useful for the problems of a similar type :-))


Thank you very much again to all! Great help!

P.S. Best time I've found so far = 647.55.