1*5e3eaea3SApple OSS Distributions#!/usr/local/bin/recon 2*5e3eaea3SApple OSS Distributions 3*5e3eaea3SApple OSS Distributionslocal benchrun = require 'benchrun' 4*5e3eaea3SApple OSS Distributionslocal csv = require 'csv' 5*5e3eaea3SApple OSS Distributionslocal os = require 'os' 6*5e3eaea3SApple OSS Distributionslocal perfdata = require 'perfdata' 7*5e3eaea3SApple OSS Distributionslocal sysctl = require 'sysctl' 8*5e3eaea3SApple OSS Distributions 9*5e3eaea3SApple OSS Distributionsrequire 'strict' 10*5e3eaea3SApple OSS Distributions 11*5e3eaea3SApple OSS Distributionslocal benchmark = benchrun.new({ 12*5e3eaea3SApple OSS Distributions name = 'xnu.zero_fill_fault_throughput', 13*5e3eaea3SApple OSS Distributions version = 1, 14*5e3eaea3SApple OSS Distributions arg = arg, 15*5e3eaea3SApple OSS Distributions modify_argparser = function(parser) 16*5e3eaea3SApple OSS Distributions parser:option{ 17*5e3eaea3SApple OSS Distributions name = '--cpu-workers', 18*5e3eaea3SApple OSS Distributions description = 'Number of threads to bring up to do faulting work', 19*5e3eaea3SApple OSS Distributions convert = tonumber, 20*5e3eaea3SApple OSS Distributions argname = 'count', 21*5e3eaea3SApple OSS Distributions } 22*5e3eaea3SApple OSS Distributions parser:flag{ 23*5e3eaea3SApple OSS Distributions name = '--through-max-workers', 24*5e3eaea3SApple OSS Distributions description = 'Run with [1..n] CPU workers', 25*5e3eaea3SApple OSS Distributions } 26*5e3eaea3SApple OSS Distributions parser:flag{ 27*5e3eaea3SApple OSS Distributions name = '--through-max-workers-fast', 28*5e3eaea3SApple OSS Distributions description = 'Run with 1, 2, and each power of four value in [4..n] CPU workers', 29*5e3eaea3SApple OSS Distributions } 30*5e3eaea3SApple OSS Distributions parser:option{ 31*5e3eaea3SApple OSS Distributions name = '--path', 32*5e3eaea3SApple OSS Distributions description = 'Path to fault throughput binary', 33*5e3eaea3SApple OSS Distributions count = 1, -- This is a required option. 34*5e3eaea3SApple OSS Distributions } 35*5e3eaea3SApple OSS Distributions parser:option{ 36*5e3eaea3SApple OSS Distributions name = '--duration', 37*5e3eaea3SApple OSS Distributions description = 'How long, in seconds, to run each iteration', 38*5e3eaea3SApple OSS Distributions default = 30, 39*5e3eaea3SApple OSS Distributions convert = tonumber, 40*5e3eaea3SApple OSS Distributions argname = 'seconds', 41*5e3eaea3SApple OSS Distributions } 42*5e3eaea3SApple OSS Distributions parser:option{ 43*5e3eaea3SApple OSS Distributions name = '--variant', 44*5e3eaea3SApple OSS Distributions description = 'Which benchmark variant to run', 45*5e3eaea3SApple OSS Distributions choices = { 'separate-objects', 'share-objects' }, 46*5e3eaea3SApple OSS Distributions default = 'separate-objects', 47*5e3eaea3SApple OSS Distributions argname = 'name', 48*5e3eaea3SApple OSS Distributions } 49*5e3eaea3SApple OSS Distributions parser:option{ 50*5e3eaea3SApple OSS Distributions name = '--first-cpu', 51*5e3eaea3SApple OSS Distributions description = 'Pin threads to CPUs, starting with this CPU ID; requires enable_skstb=1 boot-arg', 52*5e3eaea3SApple OSS Distributions default = -1, 53*5e3eaea3SApple OSS Distributions convert = tonumber, 54*5e3eaea3SApple OSS Distributions argname = 'cpu-id' 55*5e3eaea3SApple OSS Distributions } 56*5e3eaea3SApple OSS Distributions parser:flag{ 57*5e3eaea3SApple OSS Distributions name = '--verbose', 58*5e3eaea3SApple OSS Distributions description = 'Enable verbose logging at a performance cost', 59*5e3eaea3SApple OSS Distributions } 60*5e3eaea3SApple OSS Distributions end, 61*5e3eaea3SApple OSS Distributions}) 62*5e3eaea3SApple OSS Distributions 63*5e3eaea3SApple OSS Distributionslocal ncpus, _ = sysctl('hw.logicalcpu_max') 64*5e3eaea3SApple OSS Distributionsbenchmark:assert(ncpus > 0, 'invalid number of logical CPUs') 65*5e3eaea3SApple OSS Distributionslocal cpu_workers = benchmark.opt.cpu_workers or ncpus 66*5e3eaea3SApple OSS Distributionsbenchmark:assert(cpu_workers > 0, 'invalid number of CPU workers') 67*5e3eaea3SApple OSS Distributions 68*5e3eaea3SApple OSS Distributionsbenchmark:assert(benchmark.opt.first_cpu > -2, 'negative first CPU') 69*5e3eaea3SApple OSS Distributionsbenchmark:assert(benchmark.opt.first_cpu < ncpus, 'invalid first CPU') 70*5e3eaea3SApple OSS Distributions 71*5e3eaea3SApple OSS Distributionslocal page_throughput_unit = perfdata.unit.custom('pages/sec') 72*5e3eaea3SApple OSS Distributions 73*5e3eaea3SApple OSS Distributionslocal test_threads = {} 74*5e3eaea3SApple OSS Distributions 75*5e3eaea3SApple OSS Distributionsif benchmark.opt.through_max_workers then 76*5e3eaea3SApple OSS Distributions for i = 1, cpu_workers do 77*5e3eaea3SApple OSS Distributions table.insert(test_threads, i) 78*5e3eaea3SApple OSS Distributions end 79*5e3eaea3SApple OSS Distributionselseif benchmark.opt.through_max_workers_fast then 80*5e3eaea3SApple OSS Distributions local i = 1 81*5e3eaea3SApple OSS Distributions while i <= cpu_workers do 82*5e3eaea3SApple OSS Distributions table.insert(test_threads, i) 83*5e3eaea3SApple OSS Distributions -- Always do a run with two threads to see what the first part of the 84*5e3eaea3SApple OSS Distributions -- scaling curve looks like (and to measure perf on dual core systems). 85*5e3eaea3SApple OSS Distributions if i == 1 and cpu_workers >= 2 then 86*5e3eaea3SApple OSS Distributions table.insert(test_threads, i + 1) 87*5e3eaea3SApple OSS Distributions end 88*5e3eaea3SApple OSS Distributions i = i * 4 89*5e3eaea3SApple OSS Distributions end 90*5e3eaea3SApple OSS Distributionselse 91*5e3eaea3SApple OSS Distributions table.insert(test_threads, cpu_workers) 92*5e3eaea3SApple OSS Distributionsend 93*5e3eaea3SApple OSS Distributions 94*5e3eaea3SApple OSS Distributionsfor _, thread_count in ipairs(test_threads) do 95*5e3eaea3SApple OSS Distributions local cmd = { 96*5e3eaea3SApple OSS Distributions benchmark.opt.path; 97*5e3eaea3SApple OSS Distributions echo = true, 98*5e3eaea3SApple OSS Distributions name = ('with %d CPU workers%s'):format(thread_count, 99*5e3eaea3SApple OSS Distributions thread_count == 1 and '' or 's'), 100*5e3eaea3SApple OSS Distributions } 101*5e3eaea3SApple OSS Distributions if benchmark.opt.verbose then 102*5e3eaea3SApple OSS Distributions cmd[#cmd + 1] = '-v' 103*5e3eaea3SApple OSS Distributions end 104*5e3eaea3SApple OSS Distributions cmd[#cmd + 1] = benchmark.opt.variant 105*5e3eaea3SApple OSS Distributions cmd[#cmd + 1] = benchmark.opt.duration 106*5e3eaea3SApple OSS Distributions cmd[#cmd + 1] = thread_count 107*5e3eaea3SApple OSS Distributions if benchmark.opt.first_cpu ~= -1 then 108*5e3eaea3SApple OSS Distributions cmd[#cmd + 1] = benchmark.opt.first_cpu 109*5e3eaea3SApple OSS Distributions end 110*5e3eaea3SApple OSS Distributions 111*5e3eaea3SApple OSS Distributions for out in benchmark:run(cmd) do 112*5e3eaea3SApple OSS Distributions local result = out:match('-----Results-----\n(.*)') 113*5e3eaea3SApple OSS Distributions benchmark:assert(result, 'unable to find result data in output') 114*5e3eaea3SApple OSS Distributions local data = csv.openstring(result, { header = true }) 115*5e3eaea3SApple OSS Distributions for field in data:lines() do 116*5e3eaea3SApple OSS Distributions for k, v in pairs(field) do 117*5e3eaea3SApple OSS Distributions benchmark.writer:add_value(k, page_throughput_unit, tonumber(v), { 118*5e3eaea3SApple OSS Distributions [perfdata.larger_better] = true, 119*5e3eaea3SApple OSS Distributions threads = thread_count, 120*5e3eaea3SApple OSS Distributions variant = benchmark.opt.variant 121*5e3eaea3SApple OSS Distributions }) 122*5e3eaea3SApple OSS Distributions end 123*5e3eaea3SApple OSS Distributions end 124*5e3eaea3SApple OSS Distributions end 125*5e3eaea3SApple OSS Distributionsend 126*5e3eaea3SApple OSS Distributions 127*5e3eaea3SApple OSS Distributionsbenchmark:finish() 128