• 0

    posted a message on Combatlog Parser for 2.4 ~ Lib or Best methods?
    Yup that's what is lacking in your test: function call (scope changes probably meaning some heap manipulations ?) passing arguments (probably PUSH/POP not the registries fastcall way*) doing stuff then restoring previous environnement... That's what make up to the 4th event check still being faster.

    And for readability it's a matter of taste IMO. I like having events in one place, but like i said im used to old WM_* message loops :P.

    Quote from Jerry »

    Do you think you will get the same results for a fight with, say, Al'ar and a fight with Void Reaver ? For which fight are you going to "optimize" your code ? What about performance in the other fight ?

    Wanna go crazy and construct your OnEvent using loadstring to always have the best order (given the loadstring is made outside of combat or the compile time is paid back) ? That's getting funny but out of proportion :)

    Oh and sorry for being off-topic :P

    EDIT: One thing is clear: not separating COMBAT_LOG_EVENT_UNFILTERED (CLEU) from other events AND using table lookup / function call is a guaranteed loser against if/then/else with CLEU as first, or prove me false :P
    Posted in: Lua Code Discussion
  • 0

    posted a message on Combatlog Parser for 2.4 ~ Lib or Best methods?
    Quote from "Jerry" »
    Do you have any proof of this assertion ? Not in theory, but actual code.

    Can you measure how much better such a "proper" ordering would be ?


    test() is my benchmark base function, i added some stuff for current testings. Copy paste the following in tinypad or whatever you use and execute.

    local loops = {}
    
    local function print(msg,...)
    	DEFAULT_CHAT_FRAME:AddMessage( select("#",...)>0 and format(msg,...) or msg )
    end
    
    local function test(func,addon)
    	addon = addon or ""
    	collectgarbage("stop")
    	UpdateAddOnMemoryUsage()
    	UpdateAddOnCPUUsage()
    	local mem = GetAddOnMemoryUsage(addon)
    	local cpu = GetAddOnCPUUsage(addon)
    	local i = 0
    	local time = GetTime()
    	repeat
    		func()
    		i = i + 1
    	until GetTime()-time > .2
    	UpdateAddOnMemoryUsage()
    	UpdateAddOnCPUUsage()
    	print(
    		"[|cffa0a0ffCPU|r |cffff8000%d|r ?s] [|cffa0a0ffMem+|r |cffff8000%i|r bytes] [|cffff8000%i|r |cffa0a0ffloops|r]",
    		(GetAddOnCPUUsage(addon)-cpu)*1000/i,
    		(GetAddOnMemoryUsage(addon)-mem)*1024/i, i )
    	loops[#loops+1] = i
    	collectgarbage("restart")
    end
    
    
    local lookup = {}
    local f = function() return end
    for i = 1, 20 do lookup["blah"..i] = f end
    
    local value = "blah3"
    
    test( function() end )
    
    test( function()
    	lookup[value]()
    end )
    
    test( function()
    	if( value == "blah1" )then
    		return
    	elseif( value == "blah2" )then
    		return
    	elseif( value == "blah3" )then
    		return
    	elseif( value == "blah4" )then
    		return
    	elseif( value == "blah5" )then
    		return
    	elseif( value == "blah6" )then
    		return
    	elseif( value == "blah7" )then
    		return
    	elseif( value == "blah8" )then
    		return
    	elseif( value == "blah9" )then
    		return
    	end
    end )
    
    if( loops[2] < loops[3] )then
    	print( "function 2 is %.2f%% faster", ((loops[1]-loops[2]) / (loops[1]-loops[3])-1)*100 )
    else
    	print( "function 1 is %.2f%% faster", ((loops[1]-loops[3]) / (loops[1]-loops[2])-1)*100 )
    end

    Change the "value", increase/decrease/shuffle lookup entries. I get something like that:

    blah1: function 2 is 220% faster
    blah2: function 2 is 50% faster
    blah3: function 2 is 25% faster
    blah4: function 2 is 5% faster
    ---------------------------------
    blah5: function 1 is 7% faster
    blah6: function 1 is 14% faster
    blah7: function 1 is 25% faster
    blah8: function 1 is 31% faster
    and so on...

    Elsia said most about good sense event profiling (sorry for crappy english :p) anyway, if someone is not sure about best event orders, simply add an "eventCount" table and the following code in the OnEvent handler:
    if( not eventCount[event] )then
    	eventCount[event] = 1
    else
    	eventCount[event] = eventCount[event] + 1
    end

    Test in raid encounters and print sorted results, then you are ready to cross these informations with previous benchmarks to determine the overall gain.
    Posted in: Lua Code Discussion
  • 0

    posted a message on Combatlog Parser for 2.4 ~ Lib or Best methods?
    @dafire: OrionShock already use it in a modded form to fit combat events. My point was that "if then else chain" can globally performs better with proper event ordering and analysis.
    Posted in: Lua Code Discussion
  • 0

    posted a message on Combatlog Parser for 2.4 ~ Lib or Best methods?
    Your first exemple make me wonder about the goodness of using an extra frame that only register "COMBAT_LOG_EVENT_UNFILTERED" so there's no extra function call, type check and all that "branching" overhead.

    trackedCombatEvents = {
    	["SPELL_AURA_APPLIED"]=true,
    	["SPELL_AURA_DISPELLED"]=true,
    	-- add combat events to listen/watch
    }
    
    addon:OnCombatEvent( event, timestamp, combatEvent, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ... )
    	if( not trackedCombatEvents[combatEvent] )then return end
    	-- stuff
    end
    
    extraFrame = CreateFrame( "Frame" )
    extraFrame:SetScript( "OnEvent", addon.OnCombatEvent )
    extraFrame:RegisterEvent( "COMBAT_LOG_EVENT_UNFILTERED" )



    I wasnt able to raid in the last 2 weeks on EU PTR, but i think in raid fights (where efficiency is critical) there's like 200+ CLEPS (combat log events per sec) so 99% of the events are combat events. Using the extra frame method or putting "COMBAT_LOG_EVENT_UNFILTERED" on top of the "if then else chain" sounds better to me.

    Pros: vast majority of events are processed faster
    Cons: not so called events take longer (deeper in the chain), may appear inelegant to the MFC generation and later (but shouldnt scare those living in an old C world :P)

    My actual implementation looks like:
    trackedCombatEvents = {
    	["SPELL_AURA_APPLIED"]=true,
    	["SPELL_AURA_DISPELLED"]=true,
    	-- add combat events to listen/watch
    }
    
    function addon:OnEvent( event, arg1, combatEvent, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ... )
    	if( event == "COMBAT_LOG_EVENT_UNFILTERED" )then
    		if( dstGUID ~= playerGUID or not trackedCombatEvents[combatEvent] )then return end
    		if( combatEvent == "SPELL_AURA_APPLIED" )then
    			local auraID, auraName, auraSchool, auraType = ...
    			if( auraType == "BUFF" and trackedBuffIDs[auraID] )then
    				-- value used in "PLAYER_AURAS_CHANGED"
    				updateNeeded = true
    			end
    		elseif( combatEvent == "SPELL_AURA_REMOVED" )then
    			-- TODO
    		end
    	elseif( event == "PLAYER_AURAS_CHANGED" )then
    		-- TODO

    Posted in: Lua Code Discussion
  • 0

    posted a message on Noob question about event fired when entering an instance
    If you dont need the zone name, IsInInstance() is better.
    I use it in PLAYER_ENTERING_WORLD because ZONE_CHANGED_NEW_AREA fires unnecessarily when all you're checking is instance zoning, not zone changing.
    Posted in: Lua Code Discussion
  • 0

    posted a message on [Optimizations] GC, ellipsis, COMBAT_LOG_*, tinsert...
    @Shadowed: sure the "no more horrid (localized) string parsing" is a huge improvement overall. Anyway we lack local filters and we receive absolutly everything that happens in the visual range. That's a load lot ! If a tiny addon just want to check for, let's say, player weapon buff beeing applied or removed, it has to check every single combat event +_+ !

    Currently we're better off with onUpdate (yuck! >_<) for small checks than relying on events, that's sad ;_;

    I wish for a CombatLogAddLocalFilter to solve these :P (with the event param working: the current one in CombatLogAddFilter seems not implemented yet).


    @tekkub: that "hash table filter" seems a good idea to return unwanted events faster :)
    Posted in: Lua Code Discussion
  • 0

    posted a message on [Optimizations] GC, ellipsis, COMBAT_LOG_*, tinsert...
    Thank you. I missed the talk page which was pretty interesting :)

    EDIT: i get 0.42 vs 0.25 from your benchmark (ratio 1.68)
    Posted in: Lua Code Discussion
  • 0

    posted a message on [Optimizations] GC, ellipsis, COMBAT_LOG_*, tinsert...
    Hello and sorry in advance for poor english and clarity, and/or stupid questions :P

    if ( combatEvent == "SPELL_AURA_APPLIED" ) then ...

    As i understand how lua works, instead of doing a char by char comparison (very fast with the ASM CMPS instructions), it compares addresses as it behaves like hashes since strings are unique.

    But for that, is the (basic) compiler able to substitute "SPELL_AURA_APPLIED" to the underlying address at compile time, or does it have to do a table lookup at run time ? Thus, having to declare a local copy of that address beforehand (local SPELL_AURA_APPLIED = "SPELL_AURA_APPLIED") to save us from horrid time waste ?


    Is CPU profiling able to give us informations about GC hits ? Because i cant see at which point/frequency/array size and complexity (CPU-wise) i should reuse table or create new ones.


    tinsert and tremove seem very inefficient. A basic "table[#table+1] = entry" sounds like a better option. Can someone confirm that tinsert is better unemployed due to it's crappy job quality ? Or does it hold some magic somewhere ?


    the new COMBAT_LOG_EVENT_UNFILTERED seems more CPU intensive as packing together many CHAT_MSG* (as if we registered all of them!) requires us to filter too much. Wouldn't it be nice to have combat filters local to addons so most of the filtering work is done in fast C rather than in slow lua ? (Stupid EU forums have no Slouken ;_;).


    I read in http://lua-users.org/wiki/OptimisingGarbageCollection that "Vararg functions create a table for the ellipsis (stored in 'arg') each time the function is called.". onEvent may use these so widely and so often ! Is it better to do:
    MyAddon:OnEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)

    (to cover the need of "COMBAT_LOG_EVENT*" for up to 15 args :p) or is creation of arg tables unavoidable ?


    Thank you in advance :)
    Posted in: Lua Code Discussion
  • To post a comment, please or register a new account.