Optimisation Discussions Advises Experiences Ideas Etc

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

Moderators: Forum Moderators, Developers

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » June 22nd, 2017, 9:48 pm

gfgtdf wrote: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.


well maybe i done mistake somewhere, you may try to test it on your machine.. plus it might be different on different version of wesnoth and different operating system.. I assume. Also maybe if u own a latest processor the results will show something like "1,1,1,1" for all these tests :D so the difference would be neglectable... ;)

At the moment I stuck with my tests a little bit.. maybe..
My code should be:
Code: Select all
wesnoth.fire("store_locations",
   { x=xbegin-xend, y=ybegin-yend, { "not", { terrain="_off^_usr" }}, variable="ns_cube"})
   wesnoth.fire("store_locations",
   { find_in="ns_cube", terrain="M*,M*^*", variable="ns_mountains"})

And I need to convert it into wesnoth.get_locations and the problem is that if I do
local loc_storage1 = wesnoth.get_locations { x=xbegin-xend, y=ybegin-yend, { "not", { terrain="_off^_usr" }} }
I can not do local loc_storage2 = wesnoth.get_locations { find_in="loc_storage2", terrain="M*,M*^*"}
Any simple ideas? Or the only way to count how many mountains was inside the loc_storage1 is to use for i,... if loc_storage1[i].terrain == Mm..... of course I have no idea how to extract elements from the table.. I will read a lot of helps.. but not sure if it's there.. might need to google lua programming language in internet to find out.. unless somebody could help? How to count amount of mountains, including impassable imountains, snow mountains etc.. (M*,M*^*) from the lua table which has many different terrains?
I realized I could work around it and shorten the top 2 rows into 1, so instead of
Code: Select all
wesnoth.fire("store_locations",
   { x=xbegin-xend, y=ybegin-yend, { "not", { terrain="_off^_usr" }}, variable="ns_cube"})
   wesnoth.fire("store_locations",
   { find_in="ns_cube", terrain="M*,M*^*", variable="ns_mountains"})
it could use just
Code: Select all
wesnoth.get_locations { x=xbegin-xend, y=ybegin-yend, { "not", { terrain="_off^_usr" }}, terrain="M*,M*^*"}
not sure why in WML i used 2 lines.. maybe because the second line was part of MACRO that was one of 3... in one of them I was counting how many mountains, in the other hills, in another forest... doesn't change the fact that I don't know how to work with lua tables..
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby Pentarctagon » June 22nd, 2017, 11:57 pm

If you're running into problems, the Lua Labs or WML Workshop(depending on the problem) would be a better place to ask than this thread.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
Pentarctagon
Forum Administrator
 
Posts: 2987
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » June 23rd, 2017, 12:51 am

Well I converted whole WML into LUA, without using wesnoth.fire and there is no speed gain.. they seem to perform the same despite lua cycles usually 20 times faster.. and wesnoth.get_locations is at least 2 times faster.. here are 3 cycles while and 2 wesnoth.get_locations and the code takes LONG to perform.. on a map like conquest- Jel'wan
So the only untested part and I assume the bottleneck is this code:
Code: Select all
   local NS_HIT_X = helper.rand(xbegin..".."..xend)
   local NS_HIT_Y = helper.rand(ybegin..".."..yend)

vs
Code: Select all
{VARIABLE_OP NS_HIT_X rand $xbegin..$xend}
{VARIABLE_OP NS_HIT_Y rand $ybegin..$yend}


plus i found some other issues in code.. and I will have a new question in my lua topic..
PS. corrected some issues and now it looks like lua actually does have a speed gain.. speed gain depends on conditions.. So there is a tiny tiny gain if part of the code with random generation is used, and a massive huge gain if it is not used.. also in some circumstances it is still slower than wml.. and i dont understand why. tired for today, everything was buggy as a nightmare
Last edited by enclave on June 23rd, 2017, 2:13 am, edited 1 time in total.
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby gfgtdf » June 23rd, 2017, 1:04 am

In wesnoth 1.12 helper.rand is indeed expected to be slightly slower than the wml counterpart ([set_variable] rand=). This has changed in wesnoth 1.13 where wesnoth.random was added and the wesnoth.set_vaiable implementation was moved to lua.
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.
gfgtdf
Developer
 
Posts: 912
Joined: February 10th, 2013, 2:25 pm

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby Pentarctagon » June 23rd, 2017, 1:23 am

I'd also recommend putting all the code for your tests in your first post as well, so people can see it without needing to scroll through the entire thread. Tests that have a significant difference in performance between the implementations(macro vs fire_event, WML vs lua, etc) might also make decent unit tests.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
Pentarctagon
Forum Administrator
 
Posts: 2987
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » June 25th, 2017, 9:20 pm

Testing helper.rand vs math.random vs math.random wesnoth.synchronize_choice vs wesnoth.fire("set_variable", {rand...}) with a rule: to save result as wml variable.
Please have a look at codes, I could make mistakes.. specially in synchronize_choice.
Code: Select all
#define RAND1
[lua]
code = <<
   for j=0,65000,1 do
      local NS_HIT_X = helper.rand("10..100")
      wesnoth.set_variable("wml_rand",NS_HIT_X)
   end
>>
[/lua]
#enddef

#define RAND2
[lua]
code = <<
   for j=0,65000,1 do
      local NS_HIT_X = math.random(10,100)
      wesnoth.set_variable("wml_rand",NS_HIT_X)
   end
>>
[/lua]
#enddef

#define RAND3
[lua]
code = <<
   for j=0,65000,1 do
      local NS_HIT_X = math.random(10,100)
      wesnoth.set_variable("wml_rand",wesnoth.synchronize_choice(function() return { value = NS_HIT_X } end).value)
   end
>>
[/lua]
#enddef

#define RAND4
[lua]
code = <<
   for j=0,65000,1 do
   wesnoth.fire("set_variable", {name="wml_rand",rand="10..100"})
   end
>>
[/lua]
#enddef


helper.rand 1908,1922,1914,1964
math.random 150,181,177,170
math.random wesnoth.synchronize_choice 1077,1066,1053,1044
wesnoth.fire("set_variable", {rand...}) 1560,1556,1580,1579

very interesting.. I guess math random has a disadvantage of inability to select random from non-number.. can't pick a string from list of strings.. etc and is faster.. even if synchronized after.. (if i used synchronization code correctly)

So we have some conclusion thoughts.. 1) do not use helper.rand if you are on wesnoth 1.12 and if you need fast speed, where you cycle through random generated numbers.. 2) better use wesnoth.fire instead.. because WML [set_variable] rand is quicker than lua helper.rand (according to my previous tests wesnoth.fire is same speed as WML corresponsing tag) 3) If you don't need synchronization for some reason (and only dealing with numbers).. for example using random generation for animation, use math.random its 10 times faster than any alternative. 4) and if you need synchronization and not afraid to mess with synchronization and need speed, use math.random, then synchronize the result.. you will still win some 50% speed, am i right?

Now testing math.random wesnoth.set_variable 162,164,169,159
vs math.random local 40,54,45,48

So we get some more speed if we don't save it as WML variable (looks like saving variable consumes 120 units of speed in 65k loop), so helper.rand local could be 120 units speed faster than helper.rand wesnoth.set_variable if you don't need to save it as WML.. but it will still be quite significantly slower than wesnoth.fire("set_variable", {rand...}) variable..
not sure how helper.rand local would be compared vs wesnoth.fire("set_variable", {rand...}) wesnoth.get_variable, assume helper would still be slower a bit..
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » June 26th, 2017, 4:17 pm

Well I finally found what was slowing lua code down...
And I don't understand why...
Code: Select all
      local ns_check_if_wrong_terrain = #wesnoth.get_locations  { x=NS_HIT_X, y=NS_HIT_Y, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}}}
      if ns_check_if_wrong_terrain>0 then
         wesnoth.set_terrain(NS_HIT_X, NS_HIT_Y, "Mm")
      end

This lua code above is much MUCH much MUCH slower than WML version of it:
Code: Select all
[store_locations]
   x,y=$NS_HIT_X,$NS_HIT_Y
      [not]
         terrain=M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr
      [/not]
   variable=ns_check_if_wrong_terrain
[/store_locations]
   [if]
      [variable]
         name=ns_check_if_wrong_terrain.length
         greater_than=0
      [/variable]
   [then]
      {MODIFY_TERRAIN Mm $NS_HIT_X $NS_HIT_Y}
   [/then]
   [/if]

Tested on Jel'wan (conquest minus add-on) map. In a small cycle (lua is 400 speed units faster WITHOUT this code, and 600 speed units slower WITH this code). BUT if map is covered with Gg everywhere lua code is faster again. On 2p Arcanclave Citadel (default era map) lua code is faster with or without this code.. So something makes it very slow on complicated maps like Jel'wan!
Any ideas? (I will post 65k loop of both codes in a minute...)

Test results without a loop... performed 1 time on a single cell.. filters are slow..
Code: Select all
#define LOCS1
[lua]
code = <<
local x1 = 10
local y1 = 10
   local ns_check_if_wrong_terrain = #wesnoth.get_locations  { x=x1, y=y1, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}}}
>>
[/lua]
#enddef

#define LOCS2
[lua]
code = <<
local x1 = 10
local y1 = 10
   local ns_check_if_wrong_terrain = #wesnoth.get_locations  { x=x1, y=y1, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}}}
      wesnoth.set_variable("ns_check_if_wrong_terrain", ns_check_if_wrong_terrain)
>>
[/lua]
#enddef

#define LOCS3
[lua]
code = <<
local x1 = 10
local y1 = 10
wesnoth.fire("store_locations",
   { x=x1, y=y1, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}},  variable="ns_check_if_wrong_terrain"})
>>
[/lua]
#enddef

#define LOCS4
[store_locations]
x,y=10,10
[not]
terrain=M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr
[/not]
variable=ns_check_if_wrong_terrain
[/store_locations]
#enddef


10.10 is Gs^Ft (forested grass)
{LOCS1} 44,42,36,40wesnoth.get_locations
{LOCS2} 40,46,36,48wesnoth.get_locations set_variable
{LOCS3} 49,39,39,78wesnoth.fire("store_locations"..)
{LOCS4} 36,44,40,38[store_locations]

10.10 is Gg (plain grassland)
{LOCS1} 36,45,43,45wesnoth.get_locations
{LOCS2} 38,46,35,41wesnoth.get_locations set_variable
{LOCS3} 39,42,23,42wesnoth.fire("store_locations"..)
{LOCS4} 46,45,29,33[store_locations]

Other complicated terrains like impassable or villages shown same speeds as forested grass test.

So now I will compare the wesnoth.get_locations without set_variable in a 100 times loop vs wesnoth.fire("store_locations"..), 65k loop just never seem to end..
Code: Select all
local ns_check_if_wrong_terrain = wesnoth.get_locations  { x=x1, y=y1, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}}}
vs
Code: Select all
wesnoth.fire("store_locations",
   { x=x1, y=y1, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}},  variable="ns_check_if_wrong_terrain"})


10.10 is Gs^Ft (forested grass) 100 times loop
{LOCS1} 2019,2080,2031 wesnoth.get_locations
{LOCS3} 2035,2036,2045 wesnoth.fire("store_locations"..)
{LOCS4} 2023,2027,2032 [store_locations] via {REPEAT}

10.10 is Gg (plain grassland) 100 times loop (normal Jel'wan map as it comes)
{LOCS1} 2028,2036,2071 wesnoth.get_locations
{LOCS3} 2027,2066,2075 wesnoth.fire("store_locations"..)
{LOCS4} 2032,2015,2036 [store_locations] via {REPEAT}

And now a stupid thing :) Whole map is covered with Gg and we are doing same 100 times loop test would color it into red if was allowed because it needs attention...
10.10 is Gg (plain grassland) 100 times loop (whole map is only Gg)
{LOCS1} 632,628,628wesnoth.get_locations
{LOCS3} 614,624,622wesnoth.fire("store_locations"..)
{LOCS4} 610,615,627[store_locations] via {REPEAT}

So.. idk.. no comments. Just look the bottom 2 tests where the only difference was the whole map was Gg and in the other one it wasnt.. ?????
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » June 26th, 2017, 6:47 pm

Very very very strange behaviour... when testing wesnoth.get_locations 1v1 against [store_locations] it shows same speed.. but when used together with "other lua" it becomes slower.. I don't understand it!!!!! And "other lua" is much faster than "other wml" when I remove "wesnoth.get_locations" from it. And wesnoth.fire("store_locations"..) also becomes slower for some reason. I see no point to try to optimise WML using lua anymore, at least when dealing with terrains.

Example is this code, try it on map like "Jel'wan" or "Valeria", can be found in New Setters add-on.

Lua version, slower than WML: (shortcut with: {LUA_SETTLERS_FILL_MAP_WITH_MISSING_TERRAINS 8 1 0 1 0 1 1} )
Code: Select all
#define LUA_SETTLERS_FILL_MAP_WITH_MISSING_TERRAINS SIZE COMPARISON1 REPEAT_FOREST COMPARISON2 REPEAT_HILLS COMPARISON3 REPEAT_MOUNTAINS
{VARIABLE ns_size {SIZE}}
{VARIABLE ns_comparison1 {COMPARISON1}}
{VARIABLE ns_comparison2 {COMPARISON2}}
{VARIABLE ns_comparison3 {COMPARISON3}}
{VARIABLE ns_repeat_forest {REPEAT_FOREST}}
{VARIABLE ns_repeat_hills {REPEAT_HILLS}}
{VARIABLE ns_repeat_mountains {REPEAT_MOUNTAINS}}
[lua]
code = <<
local comparison1 wesnoth.get_variable("ns_comparison1")
local comparison2 wesnoth.get_variable("ns_comparison2")
local comparison3 wesnoth.get_variable("ns_comparison3")
local w,h,b = wesnoth.get_map_size()
local ns_size = wesnoth.get_variable("ns_size")
local ns_repeat_mountains = wesnoth.get_variable("ns_repeat_mountains")

local ybegin = 1
local yend = ns_size

    while (ybegin<=h)
   do
         local xbegin = 1
         local xend = ns_size
         while (xbegin<=w)
         do
local ns_mountains = #wesnoth.get_locations  { x=tostring(xbegin).."-"..tostring(xend), y=tostring(ybegin).."-"..tostring(yend), terrain="M*,M*^*"}
 if ns_mountains<tonumber(wesnoth.get_variable("ns_comparison3")) then
   for j=0,tonumber(ns_repeat_mountains),1 do
     local NS_HIT_X = math.random(xbegin,xend)
      NS_HIT_X = wesnoth.synchronize_choice(function() return { value = NS_HIT_X } end).value
     local NS_HIT_Y = math.random(ybegin,yend)
      NS_HIT_Y = wesnoth.synchronize_choice(function() return { value = NS_HIT_Y } end).value
        
      local ns_check_if_wrong_terrain = #wesnoth.get_locations  { x=NS_HIT_X, y=NS_HIT_Y, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}}}
      if ns_check_if_wrong_terrain>0 then
         wesnoth.set_terrain(NS_HIT_X, NS_HIT_Y, "Mm")
      end
   end
 end   
         xbegin = xbegin + ns_size
         xend = xend + ns_size
          if xend > w then
            xend = w
          end
         end

   ybegin = ybegin + ns_size
   yend = yend + ns_size
    if yend > h then
      yend = h
    end
    end
>>
[/lua]
{CLEAR_VARIABLE ns_size}
{CLEAR_VARIABLE ns_comparison1}
{CLEAR_VARIABLE ns_comparison2}
{CLEAR_VARIABLE ns_comparison3}
{CLEAR_VARIABLE ns_repeat_forest}
{CLEAR_VARIABLE ns_repeat_hills}
{CLEAR_VARIABLE ns_repeat_mountains}
#enddef


WML version, faster than LUA: (shorcut with: {WML_SETTLERS_FILL_MAP_WITH_MISSING_TERRAINS 8 (less_than=1) 0 (less_than=1) 0 (less_than=1) 1})
Code: Select all
#define WML_SETTLERS_FILL_MAP_WITH_MISSING_TERRAINS SIZE COMPARISON1 REPEAT_FOREST COMPARISON2 REPEAT_HILLS COMPARISON3 REPEAT_MOUNTAINS
[store_map_dimensions]
variable=ns_map_size
[/store_map_dimensions]
##
{VARIABLE ybegin 1}
{VARIABLE yend {SIZE}}
##
[while]
[variable]
name=ybegin
less_than_equal_to=$ns_map_size.height
[/variable]
[do]
   {VARIABLE xbegin 1}
   {VARIABLE xend {SIZE}}
   ##
   [while]
   [variable]
   name=xbegin
   less_than_equal_to=$ns_map_size.width
   [/variable]
   [do]
   ##
   [store_locations]
   x=$xbegin-$xend
   y=$ybegin-$yend
   [not]
   terrain=_off^_usr
   [/not]
   variable=ns_cube
   [/store_locations]
   ##
   {FIND_IF_ANY_MOUNTAINS_ADD_MOUNTAINS {COMPARISON3} {REPEAT_MOUNTAINS}}
   ##
   {VARIABLE_OP xbegin add {SIZE}}
   {VARIABLE_OP xend add {SIZE}}
   [/do]
   [/while]
{VARIABLE_OP ybegin add {SIZE}}
{VARIABLE_OP yend add {SIZE}}
[/do]
[/while]
##
{CLEAR_VARIABLE ns_cube}
{CLEAR_VARIABLE xend}
{CLEAR_VARIABLE xbegin}
{CLEAR_VARIABLE ybegin}
{CLEAR_VARIABLE yend}
#enddef



#define FIND_IF_ANY_MOUNTAINS_ADD_MOUNTAINS COMPARISON REPEATS
[store_locations]
find_in=ns_cube
terrain=M*,M*^*
variable=ns_mountains
[/store_locations]
##
[if]
[variable]
name=ns_mountains.length
{COMPARISON}
[/variable]
[then]
{REPEAT {REPEATS} (
{VARIABLE_OP NS_HIT_X rand $xbegin..$xend}
{VARIABLE_OP NS_HIT_Y rand $ybegin..$yend}
########################
[store_locations]
x,y=$NS_HIT_X,$NS_HIT_Y
[not]
terrain=M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr
[/not]
variable=ns_check_if_wrong_terrain
[/store_locations]
[if]
[variable]
name=ns_check_if_wrong_terrain.length
greater_than=0
[/variable]
[then]
########################
{MODIFY_TERRAIN Mm $NS_HIT_X $NS_HIT_Y}
########################
[/then]
[/if]
{CLEAR_VARIABLE ns_check_if_wrong_terrain}
########################
)}
[/then]
[/if]
##
{CLEAR_VARIABLE ns_mountains}
{CLEAR_VARIABLE NS_HIT_X}
{CLEAR_VARIABLE NS_HIT_Y}
#enddef


LUA speed on Jel'wan is: 2125
WML speed is: 1488
LUA speed without wesnoth.get_locations: 24
Spoiler:

WML speed without store_locations: 415
Spoiler:


it all just makes no sense.
PS. after looking at my WML code I shortened it and it became even faster, while lua remains crap - 2 times slower!!!!.
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » June 26th, 2017, 7:50 pm

Ok, I found it.. :D
This is silly but..
I can't believe its trully working..!

I replaced:
Code: Select all
      local ns_check_if_wrong_terrain = #wesnoth.get_locations  { x=NS_HIT_X, y=NS_HIT_Y, { "not", { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"}}}
      if ns_check_if_wrong_terrain>0 then
         wesnoth.set_terrain(NS_HIT_X, NS_HIT_Y, "Mm")
      end

with
Code: Select all
local bool ns_check_if_wrong_terrain = wesnoth.match_location(NS_HIT_X, NS_HIT_Y, { terrain="M*,W*,M*^*,W*^*,Ai*,Ai*^*,Rrc,Q*,X*,Q*^*,X*^*,Iwr,Rp^Ecf,Rp^Dr,_off^_usr"})
      if ns_check_if_wrong_terrain == false then
         wesnoth.set_terrain(NS_HIT_X, NS_HIT_Y, "Mm")
      end

and instead of my fastest speed that I could achieve with WML: 1000
it does it on the fly, with speed of 14 !!!!!!!!!!! all you can do is blink and its done!

When you need to check the specific coordinate, DO NOT USE wesnoth.get_locations, use wesnoth.match_location or whatever else, but NOT wesnoth.get_locations!
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » July 26th, 2017, 5:11 pm

Tried to do [fire_event] using {REPEAT} macro 2000 times and speed result was 200.. Which is not extremely bad.. It means that you may sometimes mix lua with fire_events.. but if you need huge speed boost I would not recommend fire_events firing more than 2000 times.. If you plan to make a fast code that calculates more than 2000 things via fire events then better find the other way, don't use fire_event.. use pure lua. Even 1000 fire events may significantly slow things down.

Just for comparison, lua can perform quite a big code with speed of 20.. VERY FAST. (it may include more than 2000 calculations of 1 line or longer)
1000 fire events of tiny TINY TINY code (like 1 line size) would be around 5 times slower, around speed of 100.. and I guess (not sure) that every 1000 speed is 1 second. 1 second is something you will most likely notice! (like a little lag or delay between actions..) I think that less than 200 would be unnoticed for human eye in most cases and around 500 would be acceptable. But keep in mind that every user has different computer.. if an AMD 6 core may show it as speed of 200.. some strong i7 may perform it with speed of 1, maybe... and some old dual core AMD or single core Pentium.. would give you a much bigger delay I assume.. Never tested this, only assuming, as I can not test it, or rather say don't want to test it now.. But will test it some day and put here for comparison.. It should be interesting.. how different devices or operating systems perform same calculations.
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » August 8th, 2017, 8:21 pm

Optimization problems when converting macros into fire events..
All seems simple.. you have a lot of code.. you have macros inside macros.. you want to cut the savefile size or increase performance, you know what you are doing.. you done it a lot of times.. but!

From time to time.. your game turns into a mess!

It is known that when you fire event from some event.. then the fired event inherits the parent event variables...
For example:
Code: Select all
[event]
name=capture
first_time_only=no
{FIRE_EVENT message_which_side_lost_a_village} ## keep in mind that this macro {FIRE_EVENT} doesn't exist by default, you need to create it.
[/event]

[event]
name=message_which_side_lost_a_village
first_time_only=no
[message]
message="fire_event_1: side $owner_side lost a village"
[/message]
[/event]

This will work perfectly fine.. same as if you would just done it WITHOUT fire event like below:
Code: Select all
[event]
name=capture
first_time_only=no
[message]
message="without fire event: side $owner_side lost a village"
[/message]
[/event]


Yeah, nothing changes.. you could convert macros into fire event.. and use $owner_side inside your fired event.. same as inside macro.. COOL!

BUT if you write this:
Code: Select all
[event]
name=capture
first_time_only=no
[message]
message="without fire event: side $owner_side lost a village at $x1,$y1
[/message]
{FIRE_EVENT message_which_side_lost_a_village}
[/event]

[event]
name=message_which_side_lost_a_village
first_time_only=no
[message]
message="fire_event_1: side $owner_side lost a village at $x1,$y1
[/message]
[/event]

What do you think you will get? CRAP.. lot of crap.. specially if your code is not only delivering a silly message..
The message without fire event will be saying "without fire event: side 2 lost a village at 13,14"
The message inside fired event will be saying "fire_event_1: side 2 lost a village at 0,0"

So fire events inherit something from parent event.. BUT some things, like $x1 $y1 get eaten.. and turned into ZEROES.
When you convert your code into fire events, make sure to replace all coordinates with your own variables!!!
For example this should work fine:
Code: Select all
[event]
name=capture
first_time_only=no
{VARIABLE xx $x1}
{VARIABLE yy $y1}
{FIRE_EVENT message_which_side_lost_a_village}
[/event]

[event]
name=message_which_side_lost_a_village
first_time_only=no
[message]
message="fire_event_1: side $owner_side lost a village at $xx,$yy
[/message]
{CLEAR_VARIABLE xx}
{CLEAR_VARIABLE yy}
[/event]


But trust me, this may create a lot of headache if you ignore this.. Stderr.txt will not show any errors, owner_side will be working fine.. side_number will be working fine.. you will be wondering what went wrong.. and this is as simple as stupid as this.. $x1=0 $y1=0
So when you convert your macros into fire events, make sure to change $x1 and $y1, do NOT reply on them!!
Good luck! :)
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby Sapient » August 9th, 2017, 12:51 am

Try adding this to your FIRE_EVENT definition:
Code: Select all
[primary_unit]
    x,y=$x1,$y1
[/primary_unit]
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
User avatar
Sapient
Developer
 
Posts: 4373
Joined: November 26th, 2005, 7:41 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » September 3rd, 2017, 8:19 pm

Another test of WML against lua in speed comparison.
Storing locations and loops are the main subjects of comparison..


So codes below will be doing exactly the same thing and they are coded quite like a mirror, they will remove all leaders from map and then put them back on map with distance between them set according to settings, with only 1 rule that the leaders should appear on land, not water or impassable.

WML
Code: Select all
[event]
name=start
first_time_only=yes
{TT_BEGIN} ##timer begin
##############################
{VARIABLE ns_min_dist $NS_preload_options_shuffled_sides_minimal_distance}
##########################
                  [if]
                  [variable]
                  name=ns_min_dist
                  not_equals=0
                  [/variable]
                  [then]
[store_locations]
[not]
terrain=W*,W*^*,Xv,_off^_usr
[/not]
variable=ns_test_locations
[/store_locations]
   [if]
   [variable]
   name=ns_test_locations.length
   greater_than=$ns_min_dist
   [/variable]
   [then]
      [store_unit]
      kill=yes
      [filter]
      canrecruit=yes
      [/filter]
      variable=ns_all_kings_stored
      [/store_unit]
{VARIABLE ns_king_rand_start_counter 0}
{FOREACH ns_test_locations ntl_i}
[if]
[variable]
name=ns_king_rand_start_counter
less_than=$ns_all_kings_stored.length
[/variable]
[then]
   [store_locations]
   x,y=$ns_test_locations[$ntl_i].x,$ns_test_locations[$ntl_i].y
      [and]
   [not]
   [filter]
   canrecruit=yes
   [/filter]
   radius=$ns_min_dist
   [/not]
      [/and]
   variable=ns_test_inner_locations
   [/store_locations]
      [if]
      [variable]
      name=ns_test_inner_locations.length
      greater_than=0
      [/variable]
      [then]
         [unstore_unit]
         x,y=$ns_test_locations[$ntl_i].x,$ns_test_locations[$ntl_i].y
         variable=ns_all_kings_stored[$ns_king_rand_start_counter]
         animate=no
         [/unstore_unit]
         {VARIABLE_OP ns_king_rand_start_counter add 1}
         {CLEAR_VARIABLE ns_test_inner_locations}
      [/then]
      [else]
         {CLEAR_VARIABLE ns_test_inner_locations}
      [/else]
      [/if]
[/then]
[/if]
{NEXT ntl_i}
   [/then]
   [/if]
                     [/then]
                     [/if]
{CLEAR_VARIABLE ns_all_kings_stored}
{CLEAR_VARIABLE ns_test_locations}
{CLEAR_VARIABLE ns_test_inner_locations}
{CLEAR_VARIABLE ns_king_rand_start_counter}
{TT_END} ##timer end
[/event]


LUA
Code: Select all
[event]
name=start
first_time_only=yes
{TT_BEGIN} ##timer begin
[lua]
code = <<
local ns_min_dist = wesnoth.get_variable("NS_preload_options_shuffled_sides_minimal_distance")
if ns_min_dist ~= 0 then
   local ns_test_locations = wesnoth.get_locations { {"not", { terrain = "W*,W*^*,Xv,_off^_usr" } }}
   local w,h,b = wesnoth.get_map_size()
   if (w > ns_min_dist) or (h>ns_min_dist) then
      wesnoth.fire("store_unit",{kill="yes", {"filter", {canrecruit=true}},variable="ns_all_kings_stored"})
      local ns_king_rand_start_counter = 0
      for i, ns_pairs_locations in ipairs(ns_test_locations) do
         if ns_king_rand_start_counter<wesnoth.get_variable("ns_all_kings_stored.length") then
            local ns_test_inner_locations = wesnoth.match_location(ns_pairs_locations[1], ns_pairs_locations[2], { radius=ns_min_dist , { "filter", { canrecruit=true } } })
            if ns_test_inner_locations == false then
               wesnoth.fire("unstore_unit",{animate=no,x=ns_pairs_locations[1],y=ns_pairs_locations[2],variable="ns_all_kings_stored["..ns_king_rand_start_counter.."]"})
               ns_king_rand_start_counter = ns_king_rand_start_counter + 1
            end
         end
      end
   end
end
>>
[/lua]
{TT_END} ##timer end
[/event]


And the result speeds were:
WML - 17k (I assume it equals to 17 seconds) Really slow, waiting clock appears, gives a feeling that game is lagging and will crash or never unfreeze.
lua - 0.7k (less than a second then..) Really quick.. doesn't give you time to think about anything really..
So 20 times faster with lua..
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby Ravana » September 3rd, 2017, 8:51 pm

For the record, I consider the experiment of releasing preprocessed ageless success. My testing showed 3x faster loading, and player feedback has been positive.
User avatar
Ravana
Moderator
 
Posts: 1482
Joined: January 29th, 2012, 12:49 am
Location: Estonia

Re: Optimisation Discussions Advises Experiences Ideas Etc

Postby enclave » September 4th, 2017, 4:19 pm

Ravana wrote:For the record, I consider the experiment of releasing preprocessed ageless success. My testing showed 3x faster loading, and player feedback has been positive.


Hi Ravana, thats great!
Maybe you could tell in a little bit more details then what exactly the situation was before and what has changed now? 3x faster loading is a massive speed gain! How did you manage to achieve that?
(For those who doesn't know, we are talking about add-on called "ageless", it has a massive amount of custom units and images, therefore it has a size of more than 50MB, in other words it's HUGE! One of the biggest add-ons at least!)
enclave
 
Posts: 534
Joined: December 15th, 2007, 8:52 am

PreviousNext

Return to Coder’s Corner

Who is online

Users browsing this forum: No registered users and 2 guests