// richards.cm — Richards benchmark (scheduler simulation) // Object-ish workload: dynamic dispatch, state machines, queuing. def IDLE = 0 def WORKER = 1 def HANDLER_A = 2 def HANDLER_B = 3 def DEVICE_A = 4 def DEVICE_B = 5 def NUM_TASKS = 6 def TASK_RUNNING = 0 def TASK_WAITING = 1 def TASK_HELD = 2 def TASK_SUSPENDED = 3 function make_packet(link, id, kind) { return {link: link, id: id, kind: kind, datum: 0, data: array(4, 0)} } function scheduler() { var tasks = array(NUM_TASKS, null) var current = null var queue_count = 0 var hold_count = 0 var v1 = 0 var v2 = 0 var w_id = HANDLER_A var w_datum = 0 var h_a_queue = null var h_a_count = 0 var h_b_queue = null var h_b_count = 0 var dev_a_pkt = null var dev_b_pkt = null var find_next = function() { var best = null var i = 0 for (i = 0; i < NUM_TASKS; i++) { if (tasks[i] && tasks[i].state == TASK_RUNNING) { if (!best || tasks[i].priority > best.priority) { best = tasks[i] } } } return best } var hold_self = function() { hold_count++ if (current) current.state = TASK_HELD return find_next() } var release = function(id) { var t = tasks[id] if (!t) return find_next() if (t.state == TASK_HELD) t.state = TASK_RUNNING if (t.priority > (current ? current.priority : -1)) return t return current } var queue_packet = function(pkt) { var t = tasks[pkt.id] var p = null if (!t) return find_next() queue_count++ pkt.link = null pkt.id = current ? current.id : 0 if (!t.queue) { t.queue = pkt t.state = TASK_RUNNING if (t.priority > (current ? current.priority : -1)) return t } else { p = t.queue while (p.link) p = p.link p.link = pkt } return current } // Idle task tasks[IDLE] = {id: IDLE, priority: 0, queue: null, state: TASK_RUNNING, hold_count: 0, queue_count: 0, fn: function(pkt) { v1-- if (v1 == 0) return hold_self() if ((v2 & 1) == 0) { v2 = v2 >> 1 return release(DEVICE_A) } v2 = (v2 >> 1) ^ 0xD008 return release(DEVICE_B) } } // Worker task tasks[WORKER] = {id: WORKER, priority: 1000, queue: null, state: TASK_SUSPENDED, hold_count: 0, queue_count: 0, fn: function(pkt) { var i = 0 if (!pkt) return hold_self() w_id = (w_id == HANDLER_A) ? HANDLER_B : HANDLER_A pkt.id = w_id pkt.datum = 0 for (i = 0; i < 4; i++) { w_datum++ if (w_datum > 26) w_datum = 1 pkt.data[i] = 65 + w_datum } return queue_packet(pkt) } } // Handler A tasks[HANDLER_A] = {id: HANDLER_A, priority: 2000, queue: null, state: TASK_SUSPENDED, hold_count: 0, queue_count: 0, fn: function(pkt) { var p = null if (pkt) { h_a_queue = pkt; h_a_count++ } if (h_a_queue) { p = h_a_queue h_a_queue = p.link if (h_a_count < 3) return queue_packet(p) return release(DEVICE_A) } return hold_self() } } // Handler B tasks[HANDLER_B] = {id: HANDLER_B, priority: 3000, queue: null, state: TASK_SUSPENDED, hold_count: 0, queue_count: 0, fn: function(pkt) { var p = null if (pkt) { h_b_queue = pkt; h_b_count++ } if (h_b_queue) { p = h_b_queue h_b_queue = p.link if (h_b_count < 3) return queue_packet(p) return release(DEVICE_B) } return hold_self() } } // Device A tasks[DEVICE_A] = {id: DEVICE_A, priority: 4000, queue: null, state: TASK_SUSPENDED, hold_count: 0, queue_count: 0, fn: function(pkt) { var p = null if (pkt) { dev_a_pkt = pkt; return hold_self() } if (dev_a_pkt) { p = dev_a_pkt dev_a_pkt = null return queue_packet(p) } return hold_self() } } // Device B tasks[DEVICE_B] = {id: DEVICE_B, priority: 5000, queue: null, state: TASK_SUSPENDED, hold_count: 0, queue_count: 0, fn: function(pkt) { var p = null if (pkt) { dev_b_pkt = pkt; return hold_self() } if (dev_b_pkt) { p = dev_b_pkt dev_b_pkt = null return queue_packet(p) } return hold_self() } } var run = function(iterations) { var i = 0 var pkt1 = null var pkt2 = null var steps = 0 var pkt = null var next = null v1 = iterations v2 = 0xBEEF queue_count = 0 hold_count = 0 w_id = HANDLER_A w_datum = 0 h_a_queue = null h_a_count = 0 h_b_queue = null h_b_count = 0 dev_a_pkt = null dev_b_pkt = null for (i = 0; i < NUM_TASKS; i++) { if (tasks[i]) { tasks[i].state = (i == IDLE) ? TASK_RUNNING : TASK_SUSPENDED tasks[i].queue = null } } pkt1 = make_packet(null, WORKER, 1) pkt2 = make_packet(pkt1, WORKER, 1) tasks[WORKER].queue = pkt2 tasks[WORKER].state = TASK_RUNNING current = find_next() while (current && steps < iterations * 10) { pkt = current.queue if (pkt) { current.queue = pkt.link current.queue_count++ } next = current.fn(pkt) if (next) current = next else current = find_next() steps++ } return {queue_count: queue_count, hold_count: hold_count, steps: steps} } return {run: run} } return { richards_100: function(n) { var i = 0 var s = null var result = null for (i = 0; i < n; i++) { s = scheduler() result = s.run(100) } return result }, richards_1k: function(n) { var i = 0 var s = null var result = null for (i = 0; i < n; i++) { s = scheduler() result = s.run(1000) } return result } }