WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Registering for all events / asynchronous code execution (https://www.wowinterface.com/forums/showthread.php?t=58074)

LudiusMaximus 06-30-20 03:24 AM

Registering for all events / asynchronous code execution
 
I need kind of an event log for one of my addons.
Is there a concise way to register a frame for all possible events?

Fizzlemizz 06-30-20 03:27 AM

RegisterAllEvents
/etrace might also be useful.

LudiusMaximus 06-30-20 03:32 AM

Thanks for the instant and very concise reply! ;)
I guess I could have googled this myself... :o

Regarding the remark: "It is not advisable to use this for anything except debugging purposes, as the incurred performance penalty is quite large." Do you think this is still an issue with today's computers? I have never noticed that having /eventtrace open would give me any performance penalties.

Fizzlemizz 06-30-20 03:40 AM

It depends on how much "extra" processing you might add to the event call(s).

On it's own it's probably not an overly great burden.

LudiusMaximus 06-30-20 03:44 AM

All right, I will give it a try.

I just want to continuously log the events of the most recent second or so, such that under certain circumstances I can see what has just happened.

Thanks again!

SDPhantom 06-30-20 05:27 AM

It'll keep calling your OnEvent handler for literally everything. Especially in combat, this happens a lot. Calling a Lua function is the most taxing operation you can do. The best you can do is to make sure the game spends the least time possible in Lua code. Even if it's just an empty function.

LudiusMaximus 06-30-20 05:40 AM

Quote:

Originally Posted by SDPhantom (Post 336261)
Calling a Lua function is the most taxing operation you can do. The best you can do is to make sure the game spends the least time possible in Lua code. Even if it's just an empty function.

That's interesting. Are you saying that calling a function is significantly more taxing than it would be to execute the function's code "inline"? When I code I try to use functions wherever I can to avoid writing the same code more than once. Does this make my code less efficient as more functions are called?

Another thing I was wondering: Is it more efficient to have one frame listening to several events and decide what to do depending on the event within the one OnEvent function. Or to have several frames each listening to only one event? Or does this make no difference?

SDPhantom 06-30-20 06:21 AM

Quote:

Originally Posted by LudiusMaximus (Post 336262)
That's interesting. Are you saying that calling a function is significantly more taxing than it would be to execute the function's code "inline"?

All Lua operations are relatively quick, but compared to C code and being called literally thousands of times, this adds up. Also this is comparing simple operations like creating a table, assigning a variable, indexing, etc. A single line of code often has many of these operations in it.



Quote:

Originally Posted by LudiusMaximus (Post 336262)
When I code I try to use functions wherever I can to avoid writing the same code more than once. Does this make my code less efficient as more functions are called?

It's a balancing act between speed, readability, and maintainability. You shouldn't have separate functions for code that's only being run for one place or be calling a function that you know does nothing in a situation you can avoid.

The overall goal is to have code that's easy to read and maintain, but not be too wasteful of CPU time if you can help it.



Quote:

Originally Posted by LudiusMaximus (Post 336262)
Another thing I was wondering: Is it more efficient to have one frame listening to several events and decide what to do depending on the event within the one OnEvent function. Or to have several frames each listening to only one event? Or does this make no difference?

This is another balancing act. It's weighing between having many frames call one function independently or having one frame loop through a list of others, calling an iterator in a for loop to retrieve each one. Comparing the two, I would say it makes no difference.

LudiusMaximus 06-30-20 07:03 AM

Thanks for the advice.

One more thing I have been thinking about. Do you think there will ever by a major update that will allow something like "asynchronous" execution of lua code?

At the moment it seems that the framerate is determined by whoever is slower: the GPU rendering the game world or the CPU executing any pending UI code. Normally, the UI does not take that much time. But actions like e.g. opening the "Appearances" frame brings with it a massive momentary FPS drop. The same is true to a lesser degree for just openning your bagpack (also without any addons). And even picking up an item while your backpack is open leads to 1-2 frames with a lower rate than the GPU would be able to render.

How fundamentally different would it be if the GPU does its thing rendering the game world as fast as possible and the lua code does its thing taking as long as it needs without throttling the FPS...?

SDPhantom 06-30-20 10:50 AM

Lua is a single-threaded scripting engine, so async threads are impossible. You can fake it though by spreading your workload using coroutines or other fancy coding. You end up passing execution around like a hot potato instead of it truly being asynchronous.

It may be possible for Blizzard to separate the render and Lua into their own threads, but that's entirely up to them.

kurapica.igas 06-30-20 09:50 PM

Quote:

Originally Posted by LudiusMaximus (Post 336265)
Thanks for the advice.

One more thing I have been thinking about. Do you think there will ever by a major update that will allow something like "asynchronous" execution of lua code?

At the moment it seems that the framerate is determined by whoever is slower: the GPU rendering the game world or the CPU executing any pending UI code. Normally, the UI does not take that much time. But actions like e.g. opening the "Appearances" frame brings with it a massive momentary FPS drop. The same is true to a lesser degree for just openning your bagpack (also without any addons). And even picking up an item while your backpack is open leads to 1-2 frames with a lower rate than the GPU would be able to render.

How fundamentally different would it be if the GPU does its thing rendering the game world as fast as possible and the lua code does its thing taking as long as it needs without throttling the FPS...?

This could be done with the Lua's coroutine, and since the Lua is single thread, so you don't need worry about the thread lock. We can yield those coroutines to make sure they don't cost too much in one frame to prevent fps dropping by the Lua codes.

But it's not easily to be done, we can't make all authors to use the coroutines, also we can't make all authors to use the coroutines under the same framework.

You can check my Scorpio-Async FrameWork for some ideas. Since most addons I used are created by my own, I can make all codes processed without fps dropping, but that only works for myself.

Somebody told me, the Scorpio is largely used in hack-apps like automatic combat for performance, it's sad that it's popular in a wrong direction.

LudiusMaximus 07-01-20 12:59 AM

Quote:

Originally Posted by kurapica.igas (Post 336268)
I can make all codes processed without fps dropping.

Wow, this sounds amazing. I cannot even begin to understand how this works. :)
I mean you somehow have to "pass the execution around" (like SDPhantom said) from frame to frame, right? So when WoW is running at 120 FPS you do less lua executions per frame than when it is running at 60 FPS? How does your framework estimate how many lua executions "fit" into one frame, before the FPS would drop??

kurapica.igas 07-01-20 04:15 AM

Quote:

Originally Posted by LudiusMaximus (Post 336269)
Wow, this sounds amazing. I cannot even begin to understand how this works. :)
I mean you somehow have to "pass the execution around" (like SDPhantom said) from frame to frame, right? So when WoW is running at 120 FPS you do less lua executions per frame than when it is running at 60 FPS? How does your framework estimate how many lua executions "fit" into one frame, before the FPS would drop??

Task an example:

Lua Code:
  1. Scorpio "ScorpioTest" ""
  2.  
  3. __Async__()
  4. __SlashCmd__ "sct" "start"  -- use `/sct start` to start the process
  5. function bigCycle()
  6.     local time = GetTime()
  7.     local prev = 0
  8.     for i = 1, 10^7 do
  9.         if i%10 == 0 then
  10.             Continue() -- The frame will freeze if miss this
  11.  
  12.             if time ~= GetTime() then
  13.                 -- Means the thread is resumed in the next frame OnUpdate
  14.                 time = GetTime()
  15.  
  16.                 -- Here is the current time and the cycle count of the previous phase
  17.                 -- On my laptop(i7-9750H), it's about 14600(10 level) or 20000(1 level)
  18.                 print(time, i - prev)
  19.                 prev = i
  20.             end
  21.         end
  22.     end
  23. end

Dont' mind the __SlashCmd__, it means use command "/sct start" to call the function bigCycle, the __Async__ means the function will be processed in a coroutine, there are many ways to simple code like this.

The blz provide the debugprofilestop, so we can mesaure the cost of code in one frame(The GetTime() can't do that, since it won't change the result during one frame)

The core part in the example is the Continue API provided by the Scorpio. It'll yield the coroutine, queue it to a high priority task list. So the code is stopped, the task schedule system will check if there is still enough time in one frame, if it's has, the system will check the task list, and resume each task one by one until there is no task or not enough time.

The time limit for one frame is calcluated by the fps, it is less in 120 hz game than the 60hz(but normally the CPU is more powerful in the 120 Hz hardware platform).

The system will also try to calcuate the average cost of the codes(from resume to the yield, since many codes doesn't finish in one frame), so if there is too many tasks, the task system will try to get more time to reduce the amount of the tasks, but with a max time limit, the fps dropping could be unnoticeable, we still can change the max time limit to make sure no fps dropping.

So to dot it, we need a task schedule system to manage the time and resume the tasks, and several async APIs like the Continue, Delay and etc to queue the tasks into the schedule system, so we can manage them no matter where and how the code works.

LudiusMaximus 07-01-20 04:28 AM

Cool, it's great to know that something like that exists. Maybe some day I will try to implement a bag inventory that gets updated without FPS drop when looting something. :)

DahkCeles 07-01-20 08:58 AM

This makes sense, actually. I've considered adding a flag my addon to detect when something like UNIT_AURA has happened a bazillion times in just one frame, and waiting until the next frame to execute the code only once. The downside is that you are imposing 'latency' on the player.

In theory, they will see the information one frame later and thus have a slower reaction time. It's kind of like purposefully having tiny lag, in order to have a faster framerate... but of course we're talking about imperceptibly small fractions of a second.

After playing around, though, I found the savings on a 120Hz screen to be so marginal that it wasn't worth it. I guess if it were an expensive function then it might be helpful... but displaying buffs on a screen doesn't take much effort. A computer capable of super-duper-fast refresh rates probably has the processing power to push through it anyways.

SDPhantom 07-01-20 05:03 PM

Keep in mind, not everyone is running bleeding edge hardware nor can afford to.


All times are GMT -6. The time now is 10:10 AM.

vBulletin © 2020, Jelsoft Enterprises Ltd
© 2004 - 2020 MMOUI