Benchmark - put every function inside a object or inside a helper object

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
gcmartijn
Party member
Posts: 136
Joined: Sat Dec 28, 2019 6:35 pm

Benchmark - put every function inside a object or inside a helper object

Post by gcmartijn »

H!

Today I was wondering if there are performance differents between the following situations.

Situation 1

Code: Select all

object {
  function a
  function b
  function c
  function d
}
object = new object()
object:b()
Situation 2

Code: Select all

object {
  function a
}
helper {
  function b(object)
  function c(object)
  function d(object)
}
helper = new helper()
object = new object()
helper:b(object)
Well, I don't see a different when using 1000 'small' objects.
So for performance only you don't have to create a helper function to get more speed.

situation 1 Apple M1: CPU +/- 55%, Mem +/- 53M, Max garbage count 1297.1787109375 FPS 30
situation 2 Apple M1: CPU +/- 53%, Mem +/- 51M, Max garbage count 1299.2373046875 FPS 30

situation 1 Apple Intel 2014: CPU +/- 77%, Mem +/- 40M, Max garbage count 1477.265625 FPS 17
situation 2 Apple Intel 2014: CPU +/- 76%, Mem +/- 40M, Max garbage count 1499.13671875 FPS 17

Code: Select all

maxObjects = 1000
testcase = 2 -- use 1 for SuperObject use 2 for NotSoSuperObject
maxTime = 60 -- seconds

Object = require "lib.classic.classic" -- https://github.com/rxi/classic

function generateRandomData(length)
    local charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    math.randomseed(os.time())
    local randomData = ""
    for i = 1, length do
        local randomIndex = math.random(1, #charset)
        randomData = randomData .. string.sub(charset, randomIndex, randomIndex)
    end
    return randomData
end

local SuperObject = Object:extend("SuperObject")
function SuperObject:new(data)
    self.x1 = data.x1
    self.moredata1 = generateRandomData(1000)
    self.moredata2 = generateRandomData(1000)
    self.moredata3 = generateRandomData(1000)
end
function SuperObject:getX()
    return self.x1
end
function SuperObject:anotherFuction1()
    -- random lines of code to fill this function
    local x = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local y = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local z = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local g = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local d = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    return self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
end
function SuperObject:anotherFuction2()
    -- random lines of code to fill this function
    local x = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local y = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local z = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local g = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local d = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    return self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
end
function SuperObject:anotherFuction3()
    -- random lines of code to fill this function
    local x = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local y = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local z = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local g = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local d = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    return self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
end
function SuperObject:anotherFuction4()
    -- random lines of code to fill this function
    local x = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local y = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local z = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local g = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local d = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    return self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
end
function SuperObject:anotherFuction5()
    -- random lines of code to fill this function
    local x = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local y = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local z = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local g = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local d = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    return self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
end
function SuperObject:anotherFuction6()
    -- random lines of code to fill this function
    local x = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local y = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local z = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local g = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    local d = self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
    return self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1 + self.x1
end

local NotSoSuperObject = Object:extend("NotSoSuperObject")
function NotSoSuperObject:new(data)
    self.x1 = data.x1
    self.moredata1 = generateRandomData(1000)
    self.moredata2 = generateRandomData(1000)
    self.moredata3 = generateRandomData(1000)
end
function NotSoSuperObject:getX()
    return self.x1
end
local HelperObjectForNotSoSuperObject = Object:extend("HelperObjectForNotSoSuperObject")
function HelperObjectForNotSoSuperObject:anotherFuction1(obj)
    -- random lines of code to fill this function
    local x = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local y = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local z = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local g = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local d = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    return obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
end
function HelperObjectForNotSoSuperObject:anotherFuction2(obj)
    -- random lines of code to fill this function
    local x = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local y = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local z = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local g = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local d = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    return obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
end
function HelperObjectForNotSoSuperObject:anotherFuction3(obj)
    -- random lines of code to fill this function
    local x = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local y = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local z = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local g = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local d = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    return obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
end
function HelperObjectForNotSoSuperObject:anotherFuction4(obj)
    -- random lines of code to fill this function
    local x = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local y = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local z = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local g = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local d = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    return obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
end
function HelperObjectForNotSoSuperObject:anotherFuction5(obj)
    -- random lines of code to fill this function
    local x = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local y = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local z = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local g = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local d = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    return obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
end
function HelperObjectForNotSoSuperObject:anotherFuction6(obj)
    -- random lines of code to fill this function
    local x = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local y = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local z = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local g = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    local d = obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
    return obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1 + obj.x1
end

ProFi = require("lib-dev.profi.ProFi")
ProFi:start()

helper = HelperObjectForNotSoSuperObject()
objects = {}
startTime = love.timer.getTime()
maxGarbage = 0

function love.load()
    for i = 1, maxObjects do
        if testcase == 1 then
            table.insert(objects, SuperObject({x1 = 23423432432432433}))
        else
            table.insert(objects, NotSoSuperObject({x1 = 23423432432432433}))
        end
    end
end

function love.update(dt)
    for _, object in pairs(objects) do
        if testcase == 1 then
            object:getX()
            object:anotherFuction1()
            object:anotherFuction2()
            object:anotherFuction3()
            object:anotherFuction4()
            object:anotherFuction5()
            object:anotherFuction6()
        else
            object:getX()
            helper:anotherFuction1(object)
            helper:anotherFuction2(object)
            helper:anotherFuction3(object)
            helper:anotherFuction4(object)
            helper:anotherFuction5(object)
            helper:anotherFuction6(object)
        end
    end
    local garbage = collectgarbage("count")
    if maxGarbage < garbage then
        maxGarbage = garbage
    end
    print(maxGarbage)
    if love.timer.getTime() - startTime > maxTime then
        love.event.quit()
    end
end

function love.draw()
    love.graphics.print("Memory actually used (in kB): " .. collectgarbage("count"), 10, 10)
    love.graphics.print("Max Memory (in kB): " .. maxGarbage, 10, 30)
    love.graphics.print("Current FPS: " .. tostring(love.timer.getFPS()), 10, 40)
end

function love.quit()
    ProFi:stop()
    ProFi:writeReport("./temp/MyProfilingReport" .. tostring(testcase) .. ".txt")
    return false
end
User avatar
dusoft
Party member
Posts: 510
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

Re: Benchmark - put every function inside a object or inside a helper object

Post by dusoft »

Looks like a microoptimization to me.

It's rather a programming style question.
gcmartijn
Party member
Posts: 136
Joined: Sat Dec 28, 2019 6:35 pm

Re: Benchmark - put every function inside a object or inside a helper object

Post by gcmartijn »

Yea but I only want to know if there was a huge differents in speed.
Now I know ;)
User avatar
dusoft
Party member
Posts: 510
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

Re: Benchmark - put every function inside a object or inside a helper object

Post by dusoft »

Alright, I misunderstood that as an open question.
RNavega
Party member
Posts: 254
Joined: Sun Aug 16, 2020 1:28 pm

Re: Benchmark - put every function inside a object or inside a helper object

Post by RNavega »

Code: Select all

object:anotherFuction1()

helper:anotherFuction1(object)
As I understand it, the second case is right in being more expensive, as it handles more parameters.
In both cases you have a table key query ("anotherFuction1"), but the parameters in the first case are (self,), and in the second case (self, object,).
Maybe that's the only source of difference. I'd test the helper call with dot syntax ( helper.anotherFuction1(object) ) to see if it brings them back to the same speeds.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 10 guests