Last active
May 11, 2019 14:40
-
-
Save haizaar/efcc083eb048d915a774ca901b0047ac to your computer and use it in GitHub Desktop.
Lua "class" performance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Plain function for baseline | |
local func = function(x) | |
return x | |
end | |
-- Closure | |
local IClass = function(id) | |
local foo = function() | |
return id | |
end | |
local bar = function() | |
local v, err = foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end | |
return { | |
id = id, | |
foo = foo, | |
bar = bar, | |
} | |
end | |
-- Metatables (similar to JS prototype) | |
local MTClass_mt = { | |
__index = { | |
foo = function(self) | |
return self.id | |
end, | |
bar = function(self) | |
local v, err = self:foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end, | |
} | |
} | |
local MTClass = function(id) | |
local obj = { | |
id = id, | |
} | |
setmetatable(obj, MTClass_mt) | |
return obj | |
end | |
-- penlight.Class - first variation | |
local PLClass1 = class() | |
function PLClass1:_init(id) | |
self.id = id | |
end | |
function PLClass1:foo() | |
return self.id | |
end | |
function PLClass1:bar() | |
local v, err = self:foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end | |
-- penlight.Class - second variation | |
class.PLClass2({ | |
_init = function(self, id) | |
self.id = id | |
end, | |
foo = function(self) | |
return self.id | |
end, | |
bar = function(self) | |
local v, err = self:foo() | |
if err then | |
error("Failure") | |
return nil, err | |
end | |
if not v then return false end | |
return true | |
end, | |
}) | |
local timeit = function(call, multiplier) | |
local million = 1000000 | |
multiplier = multiplier or 10 | |
local timeone = function(amount, name, Class) | |
local sts = os.clock() | |
for i = 1, amount do Class() end | |
print(string.format("%s: %d calls/sec", name, amount/(os.clock() - sts))) | |
end | |
local timeone_with_call = function(amount, name, Class, callback) | |
local sts = os.clock() | |
for i = 1, amount do callback(Class(42)) end | |
print(string.format("%s: %d calls/sec", name, amount/(os.clock() - sts))) | |
end | |
if call then timeone = timeone_with_call end | |
local msg = "Benchmarking initialization ..." | |
if call then | |
msg = "Benchmarking initialization + invocation ..." | |
end | |
print(msg) | |
local dot = function(c) | |
local id = c.id; c.foo(); c.bar() | |
end | |
local colon = function(c) | |
local id = c.id, c:foo(), c:bar() | |
end | |
-- Additional multiplier since these two are fast | |
local amount = multiplier * 1000 * million | |
timeone(amount, "Func", func, function() end) | |
timeone(amount, "Metatable", MTClass, colon) | |
local amount = multiplier * million | |
timeone(amount, "Closure", IClass, dot) | |
timeone(amount, "PLClass1", PLClass1, colon) | |
timeone(amount, "PLClass2", PLClass2, colon) | |
end | |
return { | |
timeit = timeit, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
def func(x): | |
return x | |
class Klass: | |
def __init__(self, id): | |
self.id = id | |
def foo(self): | |
return self.id | |
def bar(self): | |
id = self.foo() | |
if not id: | |
raise Exception() | |
return True | |
def closure(id): | |
def foo(): | |
return id | |
def bar(): | |
id = foo() | |
if not id: | |
raise Exception() | |
return True | |
return { | |
"id": id, | |
"foo": foo, | |
"bar": bar, | |
} | |
def time_init(amount, klass, name): | |
sts = time.monotonic() | |
for i in range(amount): | |
klass(42) | |
print("{}: {} ops/sec".format(name, int(amount / (time.monotonic() - sts)))) | |
def time_init_access(amount, klass, name, accessor): | |
sts = time.monotonic() | |
for i in range(amount): | |
accessor(klass(42)) | |
print("{}: {} ops/sec".format(name, int(amount / (time.monotonic() - sts)))) | |
amount = 10_000_000 | |
print("Benchmarking init") | |
time_init(10 * amount, func, "Func") | |
time_init(amount, Klass, "Class") | |
time_init(amount, closure, "Closure") | |
print("Benchmarking init+invoke") | |
time_init_access(amount, Klass, "Class", lambda o: (o.id, o.foo(), o.bar())) | |
time_init_access(amount, closure, "Closure", lambda o: (o["id"], o["foo"](), o["bar"]())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Fast-forward memory consumption checker | |
math = require("math") | |
local amount = 10 * 1000* 1000 | |
stingz = {} | |
for i = 1, amount do | |
stingz[i] = string.format("%010d", math.random(amount)) | |
end | |
print(io.open("/proc/self/status"):read("*a")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Fast-forward memory consumption checker | |
from random import randint | |
strings = [] | |
amount = 10_000_000 | |
for i in range(amount): | |
strings.append(str(randint(0, amount)).rjust(10, "0")) | |
print(open("/proc/self/status").read()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment