252 lines
5.7 KiB
Plaintext
252 lines
5.7 KiB
Plaintext
// 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
|
|
}
|
|
}
|