• Surface Library Optimisation
    6 replies, posted
Would it be better/more efficient to define every different HUD element that could be displayed with a different function, and then remove those, like [code] hook.Add("HUDHook", "DrawLicenseToThrill", function() do whatever end) hook.Remove("DrawLicenseToThrill") [/code] Or just have a single hook, and then if statements on variables to choose what is drawn? (Using surface library, forgot to specify)
Removing the hook should be faster, but who cares, it's just additional unnecessary code.
I do it for my custom notification class which is a full rewrite of the existing one. Basically it removes the Think hook that constantly runs; when a message is added it adds the think hook; when the last one is removed it removes the hook. It honestly depends, are you going for massive amounts of nit-picky optimization, or are you going for regular optimizations? Regular would be like HUDShouldDraw hook optimization, and applying the same technique to other tables: [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/benchmarking_tips/benchmarking_hud_stuff.lua.html[/url] ( Showing benchmarks of the cost effectiveness of direct-access tables vs searching ) [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/_systems/anti_teamkill_system.lua.html[/url] ( Same thing, direct-access example given because others were suggesting using tables and HasValue, etc. Shooting it laggy enough, no need to add searches to the mix ) [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/_gamemode_logic/give_weapons_based_on_group.lua[/url] ( Another example for starting a round and giving weapons - reduced it from x number of tables to one table for all players instead of many nested loops for best case, worst case ( weapons are more than 1 ) it loops through weapons that it gives out ) And caching NWVars so they're not accessed constantly by the client: [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/benchmarking_tips/benchmarking_nw_vars.lua.html[/url] Working example of caching: [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/making_players_invisible_and_caching_variables.lua.html[/url] etc etc...
[QUOTE=Acecool;44599765]I do it for my custom notification class which is a full rewrite of the existing one. Basically it removes the Think hook that constantly runs; when a message is added it adds the think hook; when the last one is removed it removes the hook. It honestly depends, are you going for massive amounts of nit-picky optimization, or are you going for regular optimizations? Regular would be like HUDShouldDraw hook optimization, and applying the same technique to other tables: [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/benchmarking_tips/benchmarking_hud_stuff.lua.html[/url] ( Showing benchmarks of the cost effectiveness of direct-access tables vs searching ) [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/_systems/anti_teamkill_system.lua.html[/url] ( Same thing, direct-access example given because others were suggesting using tables and HasValue, etc. Shooting it laggy enough, no need to add searches to the mix ) [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/_gamemode_logic/give_weapons_based_on_group.lua[/url] ( Another example for starting a round and giving weapons - reduced it from x number of tables to one table for all players instead of many nested loops for best case, worst case ( weapons are more than 1 ) it loops through weapons that it gives out ) And caching NWVars so they're not accessed constantly by the client: [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/benchmarking_tips/benchmarking_nw_vars.lua.html[/url] Working example of caching: [url]https://dl.dropboxusercontent.com/u/26074909/tutoring/making_players_invisible_and_caching_variables.lua.html[/url] etc etc...[/QUOTE] I was talking either general optimization, or just when starting from scratch. So, just do it with the if thens?
It depends on what you're trying to do. If you can come up with a solution that doesn't require a lot of processing power, it's typically desired to have a solution like that. When starting out, you don't need to worry about a whole lot except understanding the scope of variables, understanding realms in a way that you understand where code is executed and when it is executed. Just because something may be "shared" doesn't mean it will always execute on both the server and client at the same time. If a client function calls shared code then shared code will only run on the client. Likewise with the server calling shared code... There are hooks, and other things that will run simultaneously. General optimization, if you need a table: instead of using table.HadValue to search for something, see if you can redesign the data structure you're creating in a way that'll accommodate quicker results. Direct access is always quicker than searching. So the HUDShouldDraw example, notice how it takes a very long time compared to direct access when using table.HasValue? With a minor edit to the table we were able to shave over 15 seconds of run time out of I think 100,000 times. HUDShouldDraw is called many times per frame, so it is important that it runs quickly. For networking, such as with the NWVars example; caching isn't automatically built in, and each time you request that var it may try to resend it and re-network it. In the benchmark it took a long time compared to a standard variable; and with the real-world example of only updating that nwvar every x seconds it will improve run-time greatly if it's done everywhere compared to if you take the quick route and just set up nwvars without caching. You can gain up to 33% speed back by localizing globals in a script. If you call math.sin in a function a lot of times every frame, you can gain back a little bit of speed by setting something like local sin = math.sin; at the top of the file. If you read this: [url]https://github.com/Facepunch/garrysmod-issues/issues/631[/url] It shows how very little time can be gained back; looking at it from the perspective of: You only have 0.03030303030303030303030303030303 seconds for logic to execute per frame with a server running at 33 ticks / second; the time saved is massive because that one snippet won't be the only piece of code running each frame. The best thing now is to check out this thread: [url]http://facepunch.com/showthread.php?t=1337945[/url] and dive right in. Feel free to ask questions as they come up; we'll be more than happy to point you in the right direction whether it concerns optimizations, helping you fix code you're writing, etc..
[QUOTE=Acecool;44601424]It depends on what you're trying to do. If you can come up with a solution that doesn't require a lot of processing power, it's typically desired to have a solution like that. When starting out, you don't need to worry about a whole lot except understanding the scope of variables, understanding realms in a way that you understand where code is executed and when it is executed. Just because something may be "shared" doesn't mean it will always execute on both the server and client at the same time. If a client function calls shared code then shared code will only run on the client. Likewise with the server calling shared code... There are hooks, and other things that will run simultaneously. General optimization, if you need a table: instead of using table.HadValue to search for something, see if you can redesign the data structure you're creating in a way that'll accommodate quicker results. Direct access is always quicker than searching. So the HUDShouldDraw example, notice how it takes a very long time compared to direct access when using table.HasValue? With a minor edit to the table we were able to shave over 15 seconds of run time out of I think 100,000 times. HUDShouldDraw is called many times per frame, so it is important that it runs quickly. For networking, such as with the NWVars example; caching isn't automatically built in, and each time you request that var it may try to resend it and re-network it. In the benchmark it took a long time compared to a standard variable; and with the real-world example of only updating that nwvar every x seconds it will improve run-time greatly if it's done everywhere compared to if you take the quick route and just set up nwvars without caching. You can gain up to 33% speed back by localizing globals in a script. If you call math.sin in a function a lot of times every frame, you can gain back a little bit of speed by setting something like local sin = math.sin; at the top of the file. If you read this: [url]https://github.com/Facepunch/garrysmod-issues/issues/631[/url] It shows how very little time can be gained back; looking at it from the perspective of: You only have 0.03030303030303030303030303030303 seconds for logic to execute per frame with a server running at 33 ticks / second; the time saved is massive because that one snippet won't be the only piece of code running each frame. The best thing now is to check out this thread: [url]http://facepunch.com/showthread.php?t=1337945[/url] and dive right in. Feel free to ask questions as they come up; we'll be more than happy to point you in the right direction whether it concerns optimizations, helping you fix code you're writing, etc..[/QUOTE] I think you misunderstood a little bit. I know Lua, I'm just new to optimization to this level. Thanks for the links, though. I'll check that out.
[QUOTE=Ghost_Sailor;44603210]I think you misunderstood a little bit. I know Lua, I'm just new to optimization to this level. Thanks for the links, though. I'll check that out.[/QUOTE] You'll get way more optimization in most cases by just using better logic than actually doing minor optimizations, because you won't be running the code at all that way, this is at least when trying to optimize existing code. The hook method can be good and bad, because if you have to go into each of those functions and do the same math again it can be a lot slower. You can use "function" subsets to help with code structure and optimization, because it's easier to optimize smaller chunks of code than looking at something large and trying to find the bottleneck. For example, you can have your general HUDPaint function which does some hud painting and call other functions like DrawMyThing and pass already calcuated local variabled to it: [lua] function GM:HUDPaint() local ply, width, height = LocalPlayer(), ScrW(), ScrH() if mything then DrawMyThing(ply, width, height) end -- do other stuff end local function DrawMyThing(ply, width, height) -- do stuff end[/lua] You can also cut down on the amount of times some of those variables are called, by using either a Tick hook for entity logic, or a timer for things like checking if Screen width and height have changed, and caching the values in a table. For example, LocalPlayer() shouldn't ever change, so once it's valid you should no longer be calling that function. And if you're drawing health or armor, you only need to check that number once per Tick as it can't change outside of the game logic code. You can also use this function to recalculate any math you might need for your hud, too. Here is actual code I have written and used: [lua]local CacheTable = {} local function CacheInfo() local ply = LocalPlayer() if IsValid(ply) then CacheTable.Team = ply:Team() CacheTable.Arrested = ply:getDarkRPVar("Arrested") CacheTable.Health = ply:Health() CacheTable.Armor = ply:Armor() CacheTable.Money = ply:getDarkRPVar("money") CacheTable.Job = ply:getDarkRPVar("job") CacheTable.Player = ply end CacheTable.ScrW = ScrW() CacheTable.ScrH = ScrH() end hook.Add("Tick", "TickCacheHudInfo", CacheInfo)[/lua] Because drawing functions are completely dependant on what FPS you are using, you can save hundreds of function calls by just caching this info and refrencing it as a local value. I did this for someone else's hud (not all code pictured) and it ended up taking somewhere around 1/5th of the original time to draw the hud info.
Sorry, you need to Log In to post a reply to this thread.