For more info about the project, visit the project page
You can install the gem by doing
gem install shikashi
New Enhancements
The primary focus of this latest release was improve the performance of execution of ruby code in the sandbox but maintaining the purity of ruby (i.e. without implementing anything with C or similar)
Code packets
In the previous version of shikashi (0.4.0), to execute code in the sandbox, you do:
Shikashi::Sandbox.run("1+1", Shikashi::Privileges.allow_method(:+))This, internally, implies:
- Parse the code
- Process the syntax tree (evalhook)
- Emulate the transformed tree (partialruby)
- Execute the emulation code using eval...
To solve this, the concept of "code packet" was implemented; a "code packet" is the ultimate product of the above mentioned processing chain ready to be executed as many times as necessary without reprocess the code and tree. Example:
packet = Shikashi::Sandbox.packet(code)
# after that, you can run the "packet" as many times as you want without doing all
# parsing, tree processing and emulation stuff internally
packet.run(privileges)
packet.run(privileges)
packet.run(privileges)
packet.run(privileges)
The performance difference is of the order of 20X, you can check by doing the following benchmark:
require "rubygems"
require "shikashi"
require "benchmark"
code = "class X
def foo(n)
end
end
X.new.foo(1000)
"
s = Shikashi::Sandbox.new
Benchmark.bm(7) do |x|
x.report("normal") {
1000.times do
s.run(code, Shikashi::Privileges.allow_method(:new))
end
}
x.report("packet") {
packet = s.packet(code, Shikashi::Privileges.allow_method(:new))
1000.times do
packet.run
end
}
end
In my laptop, the result of this benchmark is:
user system total real
normal 5.870000 0.540000 6.410000 ( 6.436331)
packet 0.290000 0.020000 0.310000 ( 0.315351)
The repeated execution of code using packets is 20 times faster than normal
Refactor of evalhook internals
Evalhook is the support gem that provides the ability to hook events on the execution of ruby code. Evalhook implemenations initially was not desgined for performance, then it's possible to refactor the implementation to increase the performance by supressing unnecessary calls and other optimizations.
require "rubygems"
require "shikashi"
require "benchmark"
s = Shikashi::Sandbox.new
class NilClass
def foo
end
end
Benchmark.bm(7) do |x|
x.report {
code = "
500000.times {
nil.foo
}
"
s.run code, Shikashi::Privileges.allow_method(:times).allow_method(:foo)
}
end
The result without the optimizations:
user system total real
36.140000 1.420000 37.560000 ( 37.672708)
The result with the optimizations:
user system total real
27.460000 1.130000 28.590000 ( 28.658031)
The difference is not so significant because most of the time is used by privileges checking in both cases. Similar bechmarks executed against evalhook directly throws greater differences
Links