Optimisation Discussions Advises Experiences Ideas Etc

Discussion of all aspects of the game engine, including development of new and existing features.

Moderator: Forum Moderators

enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Ok.. I have 1.12 so I had to replace your 1.13 [for][do][/do][/for] with macro {REPEAT 500000 ()} Funny thing is that REPEAT macro is using same counter name.. so if you do REPEAT inside REPEAT you will get a mess. (be careful everyone if you are using REPEAT.. maybe even better to avoid using it.. if you have many macros inside macros then you may at some point forget that you are using it inside each other)
I done each test 10 times the results are:
TEST1: 3064,3065,3081,3073,3091,3082,3085,3092,3071,3069 (using macro {VARIABLE})
TEST2: 3294,3347,3352,3346,3376,3341,3331,3364,3359,3333 (using lua code and wesnoth.set_variable)
TEST3: 2611,2643,2632,2632,2630,2603,2632,2620,2646,2630 (creating new wml tag with lua and using it)
Then I couple of times tried each of these one by one and results were:
2966,3367,2611
2911,3267,2598
Included test4 as last value
2998,3385,2649,855

TEST4 has the following code:

Code: Select all

#define TEST4
[set_variable]
  name=start
  time=stamp
[/set_variable]
     [lua]
	       code=<<
	 for i=0,500000,1 do
        wesnoth.set_variable("test", 5)
		end
      >>
    [/lua]
[set_variable]
  name=end
  time=stamp
[/set_variable]
 {VARIABLE difference $end}
 {VARIABLE_OP difference add -$start}
[message]
  message="test4: $start - $end = $difference"
[/message]
#enddef
And the results were:
TEST4: 858,870,872,885,863,891,907,862,859,869 (using pure lua for cycle.. for i=...)

According to my PC the slowest was to use [lua] code = << wesnoth.set_variable >> [/lua]
I guess because [lua] tag itself takes some time..
A little bit faster was macro {VARIABLE}
The fastest of WML was the self-created tag [set_test_variable]
And more than 3 times faster was to use lua for cycle.. for opposing to WML cycle [while]

TEST5: 2999,3004,2998,3008,2996,2994,3004,3015,3019,3006
test 5 had simple code instead of {VARIABLE} in TEST1 it had

Code: Select all

[set_variable]
  name=test
  value=5
[/set_variable]
so it turned to be.. some 2% faster than using MACRO (nobody will feel the difference without timing)

All 5 tests again: 2943,3303,2615,841,2971 (funny, this time {VARIABLE} was quicker than [set_variable], I guess my PC was busier with something in background by the time of test5 than during test1)

and TEST6: 6214,6252,6229,6255,6239,6247,6272,6239,6213,6213
where the code follows:

Code: Select all

#define TEST6
[set_variable]
  name=start
  time=stamp
[/set_variable]
{REPEAT 500000 (
[fire_event]
name=test6
[/fire_event]
 )}
[set_variable]
  name=end
  time=stamp
[/set_variable]
 {VARIABLE difference $end}
 {VARIABLE_OP difference add -$start}
[message]
  message="test6: $start - $end = $difference"
[/message]
#enddef

Code: Select all

[event]
name=test6
first_time_only=no
[set_variable]
  name=test
  value=5
[/set_variable]
[/event]
And in a simple test like set variable 5.. fire_event is only 2 times slower than macro or wml tags.. but close to 10 times slower than pure lua cycle for

And lastly I will test again {VARIABLE} against [set_variable] just by doing it 5 times 1 by 1..
TEST1 TEST5 TEST1 TEST5 TEST1 TEST5 TEST1 TEST5 TEST1 TEST5
3031,3009,2999,3011,3042,3002,3018,3029,3036,3022
which is...
TEST1 3031,2999,3042,3018,3036 (Average: 3025)
TEST5 3009,3011,3002,3029,3022 (Average: 3014)
Hmm well.. its either there is less than 1% difference when checked 1 by 1 or there is no difference at all.
I would say using {VARIABLE} is exactly the same fast as [set_variable] and probably the difference I see is only due to difference in background load of my PC..


Ok to summarise:
My wesnoth 1.12 on windows7 with AMD 6 core Fx-6100 CPU gave these results:
TEST1: 3064,3065,3081,3073,3091,3082,3085,3092,3071,3069 (using macro {VARIABLE})
TEST2: 3294,3347,3352,3346,3376,3341,3331,3364,3359,3333 (using lua code and wesnoth.set_variable)
TEST3: 2611,2643,2632,2632,2630,2603,2632,2620,2646,2630 (creating new wml tag with lua and using it)
TEST4: 858,870,872,885,863,891,907,862,859,869 (using pure lua for cycle.. for i=...)
TEST5: 2999,3004,2998,3008,2996,2994,3004,3015,3019,3006 (using [set_variable] instead of {VARIABLE})
TEST6: 6214,6252,6229,6255,6239,6247,6272,6239,6213,6213 (using [fire_event] for [set_variable])

While Pentarctagon had the following 3 tests:
TEST1: 4485 (using {VARIABLE}) was slowest unlike me, where slowest was TEST2
TEST2: 3699 (using [lua] wesnoth.set_variable was quicker than using {VARIABLE} unlike me..
TEST3: 2406 (using custom wml tag was quicker than anything, same as me) significantly faster
So either his operating system and/or wesnoth version difference made {VARIABLE} be slower than on my PC or his PC was much more loaded during calculation of TEST1.

That's a lot of bloody text...
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by Ravana »

You did not count that WML [while], used by {REPEAT} has limit of 2^16.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Pentarctagon wrote:So directly calling wesnoth.set_variable via a simpler WML tag was close to 2x faster, but given that it took 500,000 calls to create a difference of ~2 seconds, actually writing code this way seems beyond even micro-optimization in most cases.
Well if you have tens of such little things inside some macro inside some macro... it can create huge difference.. and with a basic variable example fire event was only 2 times slower than macro while with big code it was around 10 times slower.. so we could imagine that lua in real big code could then create even more difference.. And i seen some code with my own eyes where WML was taking a lot longer than lua for the same task.. not sure why exactly.. maybe nothing to do with lua vs wml..
code was similar to this one for WML:

Code: Select all

{FOREACH ns_allowed_build nsfbci}
[item]
x,y=$ns_allowed_build[$nsfbci].x,$ns_allowed_build[$nsfbci].y
image="terrain/grid.png~BG(0,180,0)~O(40%)"
team_name=$player[$side_number].team_name
[/item]
{NEXT nsfbci}
basically it was highlighting a huge lot of hexes into green color.. and in WML you can see how they are drawn slowly.. and even the waiting clock appears.
but with lua code, similar to this:

Code: Select all

[lua]
code = <<
top = wesnoth.get_variable("ns_allowed_build.length")-1
for k = 0, top , 1 do
wesnoth.add_tile_overlay(wesnoth.get_variable("ns_allowed_build[" .. tostring(k) .. "].x"), wesnoth.get_variable("ns_allowed_build[" .. tostring(k) .. "].y"), { image = "terrain/grid.png~BG(0,180,0)~O(40%)" })
end
>>
[/lua]
the hexes were highlighted with a blink of the eye.. without waiting clock and without showing you how they are drawn from left to right slowly one by one..
Maybe the difference in speed was because of the difference between [item] and wesnoth.add_tile_overlay .. as far as i understand the lua tag can not make it visible only to allies.. and thats why i used slow wml instead ;(
basically it makes huge difference.. depending what you are trying to do.. for graphics with huge calculations or randomization of maps.. seems like using WML is a very very bad idea..
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Ravana wrote:You did not count that WML [while], used by {REPEAT} has limit of 2^16.
you mean lua is even faster then?
and fire_event even slower?
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by Ravana »

It means you tested 65k repetitions against 500k repetitions.
gfgtdf
Developer
Posts: 1431
Joined: February 10th, 2013, 2:25 pm

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by gfgtdf »

enclave wrote: Funny thing is that REPEAT macro is using same counter name.. so if you do REPEAT inside REPEAT you will get a mess
yes, iirc this was actuall fixed in 1.13 at some point but zookeepter said it's better to keep this bahviour for backwards compability. Although since you can just use [for] directly in 1.13 this shouldn't be a problem anymore.
enclave wrote: basically it was highlighting a huge lot of hexes into green color.. and in WML you can see how they are drawn slowly..
That's becasue [item] redraw= defaults to yes, so it redraws after every [item]
enclave wrote: but with lua code, similar to this:
Note that the overlay is not kept over save/load cycles. (see the documentation of wesnoth.add_tile_overlay) so you have to readd then in every preload event.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Ravana wrote:It means you tested 65k repetitions against 500k repetitions.
Ill repeat the tests for 65000 :) i kept all my macros ;) will not take long ;)

TEST1 3048,3074,3142,3119,3133,3100,3095,3068,3123,3121
TEST5 3150,3087,3075,3091,3123,3090,3104,3092,3108,3119
TEST2 3525,3521,3291,3282,3267,3275,3257,3293,3300,3261
TEST3 2591,2596,2575,2590,2605,2587,2585,2586,2586,2601
TEST4 113,115,112,111,114,112,113,112,113,113
TEST6 6174,6163,6148.......

Ok so pure lua cycle is at least around 25 times quicker than wml cycle..
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

gfgtdf wrote: That's becasue [item] redraw= defaults to yes, so it redraws after every [item]
Note that the overlay is not kept over save/load cycles. (see the documentation of wesnoth.add_tile_overlay) so you have to readd then in every preload event.
oh thanks so much gfgtdf! you helped me improve something :) and ill keep in mind the need to redraw the lua!
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Couple more tests.. to compare to test1 and test6

TEST1 2970,2962,2980 ...{VARIABLE test 5}
TEST6 6239,6229,6218 ...[fire_event] [event] name=test6 ... {VARIABLE test 5} [/event] [/fire_event]
TEST7 6713,6710,6724 ...[lua] code = << wesnoth.fire_event("test6") >> [/lua]
TEST8 3421,3423,3430 [lua] code = << for i=0,65000,1 do wesnoth.fire_event("test6") end >> [/lua]

So if you make variable 5 through fire event, but use lua loop for, then it takes almost the same time as using just {REPEAT 65000 ({VARIABLE test 5})}, while firing event through lua alone gives no performance gain :) so looks like that if in theory you put all your action into fire events and then write the rest of your code in lua it could save MBs of space in savefile and not compromise the speed.. if you are not a confident lua writer it might be a way... but a strange way.. in practice, looks like the best way is to use lua when you need lightning speed.. or use fire_event when speed doesnt matter.. use macro when speed and savefile size doesnt matter.. using hybrid of lua loop of fire events might make sense in certain circumstances still..
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Well i have tested lua for and while against each other:
for - 3430,3421,3422 {65k times doing fire event {VARIABLE test 5}
while - 3415,3414,3405 {65k times doing fire event {VARIABLE test 5}

for - 3027,3051,3009 {just 500k times doing wesnoth.set_variable("test","5")}
while - 3006,3050,3009 {just 500k times doing wesnoth.set_variable("test","5")}

so they are same.. I just recently converted my wml into lua and gained no speed at all, wml was even faster.
The code will follow soon.
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by Ravana »

I understand previous testing already showed that it is fire_event that is slow.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Finally got time to compare wml vs lua using wesnoth.fire

WML code:
Spoiler:
the code will check every 8x8 hexes of map and see if there is any mountains on this 8x8 territory.. if there is no mountains then it will add 1 mountain in a random spot of this 8x8. The macro looks like so: {WML_SETTLERS_FILL_MAP_WITH_MISSING_TERRAINS 8 (less_than=1) 0 (less_than=1) 0 (less_than=1) 1}
It's originaly meant to put hills and forests too, but for testing purposes I left only mountains as it's easier to chase the result also..
The lua alternative I made for this WML code looks like so:
Spoiler:
and comparing these 2 methods, I gained 0 speed using lua.. I even lost some somewhere.. difference is not huge, but basically is completely not worth converting the WML above into LUA above. In the next few code/speed comparison tests we will try to find out.. what is slowing down lua.. why we not gained any speed when converted wml into lua..

For testing is best to use bigger maps.. for example 2p - Arcanclave Citadel.. because there you can see time difference better. but I will make a map become all Gg (plain grassland before each test). And will actually compare terrain change via wml and then lua speed.

So let's first compare speed of terrain modification using lua/lua wesnoth.fire/wml.. converting whole Arcanclave Citadel map into plain grassland "Gg"
Via WML [while] and [terrain]

Code: Select all

[store_map_dimensions]
   variable=ns_map_size
[/store_map_dimensions]
{VARIABLE ybegin 1}
   [while]
      [variable]
         name=ybegin
         less_than_equal_to=$ns_map_size.height
      [/variable]
   [do]
	{VARIABLE xbegin 1}
	[while]
	   [variable]
	      name=xbegin
	      less_than_equal_to=$ns_map_size.width
	   [/variable]
	   [do]
		[terrain]
		   terrain=Gg
		   x=$xbegin
		   y=$ybegin
		[/terrain]
	      {VARIABLE_OP xbegin add 1}
	   [/do]
	[/while]
      {VARIABLE_OP ybegin add 1}
   [/do]
[/while]
Via lua while and wesnoth.fire:

Code: Select all

[lua]
code = <<
local w,h,b = wesnoth.get_map_size()
local ybegin = 1
    while (ybegin<=h)
	do
			local xbegin = 1
			while (xbegin<=w)
			do
				wesnoth.fire("terrain", { terrain="Gg", x=xbegin, y=ybegin })
				xbegin = xbegin + 1
			end
	ybegin = ybegin + 1
	end
>>
[/lua]
Via lua while and wesnoth.set_terrain:

Code: Select all

[lua]
code = <<
local w,h,b = wesnoth.get_map_size()
local ybegin = 1
    while (ybegin<=h)
	do
			local xbegin = 1
			while (xbegin<=w)
			do
				wesnoth.set_terrain(xbegin, ybegin, "Gg")
				xbegin = xbegin + 1
			end
	ybegin = ybegin + 1
	end
>>
[/lua]
So the speed results are:
270,270,264 WML [terrain]
111,119,99 wesnoth.fire("terrain"...)
12,12,12 wesnoth.set_terrain
And as we can see... The lua cycle whileitself made speed about double faster.. and then when we compared wesnoth.fire to wesnoth.set_terrain... we got 10 times more speed from wesnoth.set_terrain... and total of using lua is more than 20 times faster... but in my spoiler lua code that I converted from WML I used both while and wesnoth.set_terrain AND lost speed!!! Why!?

We will try to figure out in my next experiments! - where I'm going to try different random generators (including OOS famous math.rand.. possibly sync things in the end) and possibly compare wesnoth.fire("store_locations"...) to wesnoth.get_locations (if I figure out how to use these ipairs, lol, if somebody could explain me, please do.. it will help a lot, but for today i'm tired experimenting.. spent at least an hour or 2 already).

One thing is very very clear.. if you are trying to gain speed from WML to LUA conversion.. do NOT use wesnoth.fire.. its obviously slow.. Just for fun I might compare wesnoth.fire("fire_event"..) with wesnoth.fire_event in next post too..
So we have to convert all wesnoth.fire from the spoiler lua code into other lua alternative and see where it going to get us.. Thanks for reading!
User avatar
Ravana
Forum Moderator
Posts: 2934
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by Ravana »

You dont need to worry about ipairs, you can treat it as normal array. Most that ipairs does is allow you iterate over them in pairs of (index, value). I think it does something special if your data structure has holes in it, but that should not apply here.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by enclave »

Well I tried [store_locations] vs wesnoth.fire("store_locations"..) vs wesnoth.get_locations {}
The codes are as follows for 3 of them..

Code: Select all

#define WML_STORE_ALL_GG
[store_locations]
terrain="Gg"
variable="ns_wml_stored_gg"
[/store_locations]
{VARIABLE ns_wml_stored_gg_count $ns_wml_stored_gg.length}
#enddef

#define LUA_FIRE_STORE_ALL_GG
[lua]
code = <<
			wesnoth.fire("store_locations",
   { terrain="Gg" ,variable="ns_lua_fire_stored_gg"})
   wesnoth.set_variable("ns_lua_fire_stored_gg_count",wesnoth.get_variable("ns_lua_fire_stored_gg.length"))
	>>
[/lua]
#enddef

#define LUA_STORE_ALL_GG
[lua]
code = <<
local ns_lua_stored_gg = wesnoth.get_locations { terrain = "Gg" }
local v = #ns_lua_stored_gg
wesnoth.set_variable("ns_lua_stored_gg_count",v)
	>>
[/lua]
#enddef
Map was 2p - Arcanclave Citadel.. Each macro was first covering whole map with Gg terrains...
Then timer was timing how long it will take to store whole map by terrain filter (Gg).. and count how many hexes stored.
Well every result shown the count of 2215 hexes..
And the speeds were:
WML [store_locations] 85,83,85,86
lua wesnoth.fire("store_locations"..) 85,87,87,84
lua wesnoth.get_locations {} 29,28,37,36

So wesnoth.fire done it exactly same fast as wml [store_locations], but wesnoth.get_locations done it 2 and nearly 3 times quicker. So again.. wesnoth.fire is a slow way to do things in lua. Use wesnoth.get_locations to increase speed nearly twice.. (and if you have filters inside filters I assume speed will be even quicker and quicker, so you may get 10 times better speed if your loop is using a row of store_locations.. in next post I will try it, enough for today!)

I think today I learned how to count lua table entries.. just use local your_variable_name = #lua_table_name
Still no idea how to extract the data from lua tables (more or less..), but I know at least one example: for i,loc in ipairs(wesnoth.get_locations { terrain = "Gg" }) do so will try it in future posts..

PS. Ravana you said I can treat it as normal array.. could you write example please.. how would you write this code without ipairs?

Code: Select all

-- replace all grass terrains by roads
for i,loc in ipairs(wesnoth.get_locations { terrain = "Gg" }) do
    wesnoth.set_terrain(loc[1], loc[2], "Rr")
end
If somebody could write me a 1 by 1 element extraction I could compare these 2 methods speed... maybe ipairs doubles the speed? and what is inside loc[1] and loc[2] in this example? is loc[1] similar to wml loc.x, and loc[2] to wml loc.y or its something different..? I really really really don't understand this :)
gfgtdf
Developer
Posts: 1431
Joined: February 10th, 2013, 2:25 pm

Re: Optimisation Discussions Advises Experiences Ideas Etc

Post by gfgtdf »

enclave wrote: And the speeds were:
WML [store_locations] 85,83,85,86
lua wesnoth.fire("store_locations"..) 85,87,87,84
lua wesnoth.get_locations {} 29,28,37,36
Hmm this does suprise me a little. Of course [store_locations] interally uses wesnoth.get_locations so it cannot be faster than that. And [store_locations] also have to store the locations and the terrain codes in wml vaiables. But i still expected this difference to be neglectable, this test though, shows that it takes nearly twice as long.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
Post Reply