1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
require 'erb'
require 'ostruct'
require 'fileutils'
require 'json'
class Benchmarker
include FileUtils
def initialize(target, size)
@target = target
@size = size
@micro_benchmarks = {}
@parsecount = 100
@evalcount = 100
end
def setup
require 'puppet'
require 'puppet/pops'
config = File.join(@target, 'puppet.conf')
Puppet.initialize_settings(['--config', config])
manifests = File.join('benchmarks', 'evaluations', 'manifests')
Dir.foreach(manifests) do |f|
if f =~ /^(.*)\.pp$/
@micro_benchmarks[$1] = File.read(File.join(manifests, f))
end
end
# Run / Evaluate the common puppet logic
@env = Puppet.lookup(:environments).get('benchmarking')
@node = Puppet::Node.new("testing", :environment => @env)
@parser = Puppet::Pops::Parser::EvaluatingParser.new
@compiler = Puppet::Parser::Compiler.new(@node)
@scope = @compiler.topscope
# Perform a portion of what a compile does (just enough to evaluate the site.pp logic)
@compiler.catalog.environment_instance = @compiler.environment
@compiler.send(:evaluate_main)
# Then pretend we are running as part of a compilation
Puppet.push_context(@compiler.context_overrides, "Benchmark masquerading as compiler configured context")
end
def run(args = {})
details = args[:detail] || 'all'
measurements = []
@micro_benchmarks.each do |name, source|
# skip if all but the wanted if a single benchmark is wanted
match = details.match(/#{name}(?:[\._\s](parse|eval))?$/)
next unless details == 'all' || match
# if name ends with .parse or .eval only do that part, else do both parts
ending = match ? match[1] : nil # parse, eval or nil ending
unless ending == 'eval'
measurements << Benchmark.measure("#{name} parse") do
1..@parsecount.times { @parser.parse_string(source, name) }
end
end
unless ending == 'parse'
model = @parser.parse_string(source, name)
measurements << Benchmark.measure("#{name} eval") do
1..@evalcount.times do
begin
# Run each in a local scope
scope_memo = @scope.ephemeral_level
@scope.new_ephemeral(true)
@parser.evaluate(@scope, model)
ensure
# Toss the created local scope
@scope.pop_ephemerals(scope_memo)
end
end
end
end
end
measurements
end
def generate
environment = File.join(@target, 'environments', 'benchmarking')
templates = File.join('benchmarks', 'evaluations')
mkdir_p(File.join(environment, 'modules'))
mkdir_p(File.join(environment, 'manifests'))
render(File.join(templates, 'site.pp.erb'),
File.join(environment, 'manifests', 'site.pp'),{})
render(File.join(templates, 'puppet.conf.erb'),
File.join(@target, 'puppet.conf'),
:location => @target)
# Generate one module with a 3x function and a 4x function (namespaces)
module_name = "module1"
module_base = File.join(environment, 'modules', module_name)
manifests = File.join(module_base, 'manifests')
mkdir_p(manifests)
functions_3x = File.join(module_base, 'lib', 'puppet', 'parser', 'functions')
functions_4x = File.join(module_base, 'lib', 'puppet', 'functions')
mkdir_p(functions_3x)
mkdir_p(functions_4x)
File.open(File.join(module_base, 'metadata.json'), 'w') do |f|
JSON.dump({
"types" => [],
"source" => "",
"author" => "Evaluations Benchmark",
"license" => "Apache 2.0",
"version" => "1.0.0",
"description" => "Evaluations Benchmark module 1",
"summary" => "Module with supporting logic for evaluations benchmark",
"dependencies" => [],
}, f)
end
render(File.join(templates, 'module', 'init.pp.erb'),
File.join(manifests, 'init.pp'),
:name => module_name)
render(File.join(templates, 'module', 'func3.rb.erb'),
File.join(functions_3x, 'func3.rb'),
:name => module_name)
# namespaced function
mkdir_p(File.join(functions_4x, module_name))
render(File.join(templates, 'module', 'module1_func4.rb.erb'),
File.join(functions_4x, module_name, 'func4.rb'),
:name => module_name)
# non namespaced
render(File.join(templates, 'module', 'func4.rb.erb'),
File.join(functions_4x, 'func4.rb'),
:name => module_name)
end
def render(erb_file, output_file, bindings)
site = ERB.new(File.read(erb_file))
File.open(output_file, 'w') do |fh|
fh.write(site.result(OpenStruct.new(bindings).instance_eval { binding }))
end
end
end
|