Skip to content

Commit

Permalink
Add flag to run scripts with generational GC disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffcharles committed Jan 24, 2025
1 parent 1e2738c commit 64b5dea
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 46 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
Gemfile.lock
tmp
bin/enterprise_script_service
bin/enterprise_script_service_no_gen_gc
bin/enterprise_script_service_tests
bin/enterprise_script_service_no_gen_gc_tests
bin/enterprise_script_service.dSYM
bin/enterprise_script_service_no_gen_gc.dSYM
bin/enterprise_script_service_tests.dSYM
bin/enterprise_script_service_no_gen_gc_tests.dSYM
spec/examples.txt
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.3.1
23 changes: 23 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ expect(result.stdout).to eq("hello")
<2> two "scripts" to be executed, one sets the `@stdout_buffer` to a value, the second puts the value associated to the key `:result` of the map used passed in in <1>
<3> give the ESS a 1000 second time quota to spawn, init, inject, eval and finally output the result back.

=== Turning off generational garbage collection

In some cases, you may want to run a script in an mruby environment with the generational garbage collector turned off. To do that, you can run:

[source, ruby]
----
result = EnterpriseScriptService.run(
input: {result: [26803196617, 0.475]},
sources: [
["stdout", "@stdout_buffer = 'hello'"],
["foo", "@output = @input[:result]"],
],
instructions: nil,
timeout: 10.0,
instruction_quota: 100000,
instruction_quota_start: 1,
memory_quota: 8 << 20,
generational_gc: false
)
----

Take note of the last argument of `generational_gc: false`.

== Where are things?

=== C++ sources
Expand Down
76 changes: 72 additions & 4 deletions ext/enterprise_script_service/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@ MESSAGE
ROOT = Pathname.new(__dir__).join("../..")
SERVICE_EXECUTABLE_DIR = ROOT.join("bin")
SERVICE_EXECUTABLE = SERVICE_EXECUTABLE_DIR.join("enterprise_script_service").to_s
SERVICE_EXECUTABLE_NO_GENERATIONAL_GC = SERVICE_EXECUTABLE_DIR.join("enterprise_script_service_no_gen_gc").to_s
SERVICE_SOURCES = Dir.glob("*.cpp").map(&:to_s)
Dir.chdir("#{ROOT}/tests") do
SERVICE_TESTS = Dir.glob("*_test.cpp").map { |f| "#{Dir.pwd}/#{f.to_s}"}
GOOGLE_TEST_DIR = "#{Dir.pwd}/googletest/googletest"
SERVICE_TESTS << "#{GOOGLE_TEST_DIR}/src/gtest-all.cc"
SERVICE_TESTS << "#{GOOGLE_TEST_DIR}/src/gtest_main.cc"
SERVICE_TESTS_EXECUTABLE = SERVICE_EXECUTABLE_DIR.join("enterprise_script_service_tests").to_s
SERVICE_NO_GENERATIONAL_GC_TESTS_EXECUTABLE = SERVICE_EXECUTABLE_DIR.join("enterprise_script_service_no_gen_gc_tests").to_s
end

MRUBY_LIB_DIR = MRUBY_DIR.join("build/sandbox/lib")
MRUBY_NO_GENERATIONAL_GC_LIB_DIR = MRUBY_DIR.join("build/sandbox_no_gen_gc/lib")
MRUBY_LIB = MRUBY_LIB_DIR.join("libmruby.a")
MRUBY_NO_GENERATIONAL_GC_LIB = MRUBY_NO_GENERATIONAL_GC_LIB_DIR.join("libmruby.a")

LIBSECCOMP_DIR = Pathname.new(__dir__).join("libseccomp")
LIBSECCOMP_LIB_DIR = LIBSECCOMP_DIR.join("src/.libs")
Expand Down Expand Up @@ -67,6 +71,29 @@ file(SERVICE_EXECUTABLE => [
)
end

file(SERVICE_EXECUTABLE_NO_GENERATIONAL_GC => [
SERVICE_EXECUTABLE_DIR,
*SERVICE_SOURCES,
__FILE__,
MRUBY_NO_GENERATIONAL_GC_LIB,
]) do
sh(
CXX,
"--std=c++11",
"-Wall",
"-Wextra",
"-Imsgpack/include",
"-Imruby/include",
"-L#{MRUBY_NO_GENERATIONAL_GC_LIB_DIR}",
*Flags.cflags,
*Flags.defines_with_no_gc.map { |define| "-D#{define}" },
"-o", SERVICE_EXECUTABLE_NO_GENERATIONAL_GC,
*SERVICE_SOURCES,
"-lmruby",
*LIBSECCOMP_CFLAGS,
)
end

SERVICE_SOURCES_NO_MAIN = SERVICE_SOURCES.select { |f| f != "ext.cpp"}

file(SERVICE_TESTS_EXECUTABLE => [
Expand Down Expand Up @@ -98,26 +125,58 @@ file(SERVICE_TESTS_EXECUTABLE => [
)
end

file(SERVICE_NO_GENERATIONAL_GC_TESTS_EXECUTABLE => [
SERVICE_EXECUTABLE_DIR,
*SERVICE_SOURCES_NO_MAIN,
*SERVICE_TESTS,
__FILE__,
MRUBY_NO_GENERATIONAL_GC_LIB,
]) do
sh(
CXX,
"--std=c++11",
"-Wall",
"-Wextra",
"-Imsgpack/include",
"-Imruby/include",
"-I#{GOOGLE_TEST_DIR}/include",
"-I#{GOOGLE_TEST_DIR}",
"-I.",
"-L#{MRUBY_NO_GENERATIONAL_GC_LIB_DIR}",
*Flags.cflags,
*Flags.defines_with_no_gc.map { |define| "-D#{define}" },
"-o", SERVICE_NO_GENERATIONAL_GC_TESTS_EXECUTABLE,
*SERVICE_SOURCES_NO_MAIN,
*SERVICE_TESTS,
"-lmruby",
"-lpthread",
*LIBSECCOMP_CFLAGS,
)
end

file(MRUBY_LIB => [:"mruby:compile", :"libseccomp:compile"])
file(MRUBY_NO_GENERATIONAL_GC_LIB => [:"mruby:compile_no_gen_gc", :"libseccomp:compile"])

task(clean: [:"mruby:mrproper", :"libseccomp:mrproper"]) do
sh("rm", SERVICE_EXECUTABLE)
sh("rm", SERVICE_EXECUTABLE_NO_GENERATIONAL_GC)
end

task(mrproper: [:clean, :"mruby:mrproper", :"libseccomp:mrproper"])

task(default: [SERVICE_EXECUTABLE, :test])
task(default: [SERVICE_EXECUTABLE, SERVICE_EXECUTABLE_NO_GENERATIONAL_GC, :test])

task(test: [SERVICE_TESTS_EXECUTABLE]) do
task(test: [SERVICE_TESTS_EXECUTABLE, SERVICE_NO_GENERATIONAL_GC_TESTS_EXECUTABLE]) do
sh(SERVICE_TESTS_EXECUTABLE)
sh(SERVICE_NO_GENERATIONAL_GC_TESTS_EXECUTABLE)
end

namespace(:mruby) do
def within_mruby
def within_mruby(config: '../mruby_config.rb')
Dir.chdir(MRUBY_DIR) do
original_mruby_config = ENV['MRUBY_CONFIG']
begin
ENV['MRUBY_CONFIG'] = '../mruby_config.rb'
ENV['MRUBY_CONFIG'] = config
yield
ensure
ENV['MRUBY_CONFIG'] = original_mruby_config
Expand All @@ -131,6 +190,15 @@ namespace(:mruby) do
end
end

task(:compile_no_gen_gc) do
within_mruby(config: '../mruby_no_gen_gc_config.rb') do
extra_args = []
extra_args << '' if RUBY_PLATFORM.match?(/darwin/i)
sh('sed', '-i', *extra_args, 's/{ :verbose => $verbose }/verbose: $verbose/', 'Rakefile')
sh("ruby", "./minirake")
end
end

task(:clean) do
within_mruby do
sh("ruby", "./minirake", "clean")
Expand Down
8 changes: 8 additions & 0 deletions ext/enterprise_script_service/flags.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,16 @@ def io_safe_defines
)
end

def io_safe_defines_with_no_gc
io_safe_defines + %w(MRB_GC_TURN_OFF_GENERATIONAL)
end

def defines
io_safe_defines + %w(MRB_DISABLE_STDIO)
end

def defines_with_no_gc
defines + %w(MRB_GC_TURN_OFF_GENERATIONAL)
end
end
end
38 changes: 3 additions & 35 deletions ext/enterprise_script_service/mruby_config.rb
Original file line number Diff line number Diff line change
@@ -1,37 +1,5 @@
require_relative("./flags")
require_relative("./mruby_shared_config")

mruby_engine_gembox_path = Pathname.new(__FILE__).dirname.join("mruby_engine")

MRuby::Build.new do |conf|
toolchain(:gcc)

enable_debug

conf.gembox(mruby_engine_gembox_path)
conf.gem(core: "mruby-bin-mirb")
conf.gem(core: 'mruby-bin-mruby')

conf.bins = ["mrbc", "mruby"]

conf.cc do |cc|
cc.flags += %w(-fPIC)
cc.flags += Flags.cflags
cc.defines += Flags.io_safe_defines
end
end

MRuby::CrossBuild.new("sandbox") do |conf|
toolchain(:gcc)

enable_debug

conf.gembox(mruby_engine_gembox_path)

conf.bins = []

conf.cc do |cc|
cc.flags += %w(-fPIC)
cc.flags += Flags.cflags
cc.defines += Flags.defines
end
end
build(Flags.io_safe_defines)
crossbuild("sandbox", Flags.defines)
5 changes: 5 additions & 0 deletions ext/enterprise_script_service/mruby_no_gen_gc_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require_relative("./flags")
require_relative("./mruby_shared_config")

build(Flags.io_safe_defines_with_no_gc)
crossbuild("sandbox_no_gen_gc", Flags.defines_with_no_gc)
41 changes: 41 additions & 0 deletions ext/enterprise_script_service/mruby_shared_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require_relative("./flags")

MRUBY_ENGINE_GEMBOX_PATH = Pathname.new(__FILE__).dirname.join("mruby_engine")

def build(defines)
MRuby::Build.new do |conf|
toolchain(:gcc)

enable_debug

conf.gembox(MRUBY_ENGINE_GEMBOX_PATH)
conf.gem(core: "mruby-bin-mirb")
conf.gem(core: 'mruby-bin-mruby')

conf.bins = ["mrbc", "mruby"]

conf.cc do |cc|
cc.flags += %w(-fPIC)
cc.flags += Flags.cflags
cc.defines += defines
end
end
end

def crossbuild(directory, defines)
MRuby::CrossBuild.new(directory) do |conf|
toolchain(:gcc)

enable_debug

conf.gembox(MRUBY_ENGINE_GEMBOX_PATH)

conf.bins = []

conf.cc do |cc|
cc.flags += %w(-fPIC)
cc.flags += Flags.cflags
cc.defines += defines
end
end
end
11 changes: 9 additions & 2 deletions lib/enterprise_script_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

module EnterpriseScriptService
class << self
def run(input:, sources:, instructions: nil, timeout: 1, instruction_quota: 100000, instruction_quota_start: 0)
def run(input:, sources:, instructions: nil, timeout: 1, instruction_quota: 100000, instruction_quota_start: 0, generational_gc: true)
packer = EnterpriseScriptService::Protocol.packer_factory.packer

payload = {input: input, sources: sources}
Expand All @@ -26,7 +26,7 @@ def run(input:, sources:, instructions: nil, timeout: 1, instruction_quota: 1000

spawner = EnterpriseScriptService::Spawner.new
service_process = EnterpriseScriptService::ServiceProcess.new(
service_path,
generational_gc ? service_path : service_path_no_generational_gc,
spawner,
instruction_quota,
instruction_quota_start,
Expand All @@ -47,5 +47,12 @@ def service_path
base_path.join("bin/enterprise_script_service".freeze).to_s
end
end

def service_path_no_generational_gc
@service_path_no_generational_gc ||= begin
base_path = Pathname.new(__dir__).parent
base_path.join("bin/enterprise_script_service_no_gen_gc".freeze).to_s
end
end
end
end
6 changes: 1 addition & 5 deletions script/mkmruby
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ def within_mruby
end

case ARGV[0]
when "compile"
within_mruby do
sh("ruby", "./minirake")
end
when "clean"
within_mruby do
sh("ruby", "./minirake", "clean")
Expand All @@ -41,5 +37,5 @@ when "clobber"
sh("ruby", "./minirake", "deep_clean")
end
else
puts("#{__FILE__} compile|clean|clobber")
puts("#{__FILE__} clean|clobber")
end
15 changes: 15 additions & 0 deletions spec/script_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,21 @@ def foo
assert_roundtrip_input("😅")
end

it "handles generational_gc being false" do
result = EnterpriseScriptService.run(
input: {result: [26803196617, 0.475]},
sources: [
["stdout", "@stdout_buffer = 'hello'"],
["foo", "@output = @input[:result]"],
],
timeout: 1000,
generational_gc: false
)
expect(result.success?).to be(true)
expect(result.output).to eq([26803196617, 0.475])
expect(result.stdout).to eq("hello")
end

private

def assert_roundtrip_input(input)
Expand Down

0 comments on commit 64b5dea

Please sign in to comment.