mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Add dependency-free CPU-bound workloads adapted from pyperformance 1.14.0 to cover interpreter, standard-library serialization, regex, numeric, and garbage-collection paths under the existing Criterion and CodSpeed harnesses. Keep inputs deterministic and scale expensive cases for simulation while checking that benchmark execution does not leak interpreter state. Assisted-by: Codex:gpt-5.6-sol
416 lines
9.2 KiB
Python
416 lines
9.2 KiB
Python
# Adapted from python/pyperformance 1.14.0 (richards).
|
|
"""
|
|
based on a Java version:
|
|
Based on original version written in BCPL by Dr Martin Richards
|
|
in 1981 at Cambridge University Computer Laboratory, England
|
|
and a C++ version derived from a Smalltalk version written by
|
|
L Peter Deutsch.
|
|
Java version: Copyright (C) 1995 Sun Microsystems, Inc.
|
|
Translation from C++, Mario Wolczko
|
|
Outer loop added by Alex Jacoby
|
|
"""
|
|
|
|
# Task IDs
|
|
I_IDLE = 1
|
|
I_WORK = 2
|
|
I_HANDLERA = 3
|
|
I_HANDLERB = 4
|
|
I_DEVA = 5
|
|
I_DEVB = 6
|
|
|
|
# Packet types
|
|
K_DEV = 1000
|
|
K_WORK = 1001
|
|
|
|
# Packet
|
|
|
|
BUFSIZE = 4
|
|
|
|
BUFSIZE_RANGE = range(BUFSIZE)
|
|
|
|
|
|
class Packet(object):
|
|
|
|
def __init__(self, l, i, k):
|
|
self.link = l
|
|
self.ident = i
|
|
self.kind = k
|
|
self.datum = 0
|
|
self.data = [0] * BUFSIZE
|
|
|
|
def append_to(self, lst):
|
|
self.link = None
|
|
if lst is None:
|
|
return self
|
|
else:
|
|
p = lst
|
|
next = p.link
|
|
while next is not None:
|
|
p = next
|
|
next = p.link
|
|
p.link = self
|
|
return lst
|
|
|
|
# Task Records
|
|
|
|
|
|
class TaskRec(object):
|
|
pass
|
|
|
|
|
|
class DeviceTaskRec(TaskRec):
|
|
|
|
def __init__(self):
|
|
self.pending = None
|
|
|
|
|
|
class IdleTaskRec(TaskRec):
|
|
|
|
def __init__(self):
|
|
self.control = 1
|
|
self.count = 10000
|
|
|
|
|
|
class HandlerTaskRec(TaskRec):
|
|
|
|
def __init__(self):
|
|
self.work_in = None
|
|
self.device_in = None
|
|
|
|
def workInAdd(self, p):
|
|
self.work_in = p.append_to(self.work_in)
|
|
return self.work_in
|
|
|
|
def deviceInAdd(self, p):
|
|
self.device_in = p.append_to(self.device_in)
|
|
return self.device_in
|
|
|
|
|
|
class WorkerTaskRec(TaskRec):
|
|
|
|
def __init__(self):
|
|
self.destination = I_HANDLERA
|
|
self.count = 0
|
|
# Task
|
|
|
|
|
|
class TaskState(object):
|
|
|
|
def __init__(self):
|
|
self.packet_pending = True
|
|
self.task_waiting = False
|
|
self.task_holding = False
|
|
|
|
def packetPending(self):
|
|
self.packet_pending = True
|
|
self.task_waiting = False
|
|
self.task_holding = False
|
|
return self
|
|
|
|
def waiting(self):
|
|
self.packet_pending = False
|
|
self.task_waiting = True
|
|
self.task_holding = False
|
|
return self
|
|
|
|
def running(self):
|
|
self.packet_pending = False
|
|
self.task_waiting = False
|
|
self.task_holding = False
|
|
return self
|
|
|
|
def waitingWithPacket(self):
|
|
self.packet_pending = True
|
|
self.task_waiting = True
|
|
self.task_holding = False
|
|
return self
|
|
|
|
def isPacketPending(self):
|
|
return self.packet_pending
|
|
|
|
def isTaskWaiting(self):
|
|
return self.task_waiting
|
|
|
|
def isTaskHolding(self):
|
|
return self.task_holding
|
|
|
|
def isTaskHoldingOrWaiting(self):
|
|
return self.task_holding or (not self.packet_pending and self.task_waiting)
|
|
|
|
def isWaitingWithPacket(self):
|
|
return self.packet_pending and self.task_waiting and not self.task_holding
|
|
|
|
|
|
tracing = False
|
|
layout = 0
|
|
|
|
|
|
def trace(a):
|
|
global layout
|
|
layout -= 1
|
|
if layout <= 0:
|
|
print()
|
|
layout = 50
|
|
print(a, end='')
|
|
|
|
|
|
TASKTABSIZE = 10
|
|
|
|
|
|
class TaskWorkArea(object):
|
|
|
|
def __init__(self):
|
|
self.taskTab = [None] * TASKTABSIZE
|
|
|
|
self.taskList = None
|
|
|
|
self.holdCount = 0
|
|
self.qpktCount = 0
|
|
|
|
|
|
taskWorkArea = TaskWorkArea()
|
|
|
|
|
|
class Task(TaskState):
|
|
|
|
def __init__(self, i, p, w, initialState, r):
|
|
self.link = taskWorkArea.taskList
|
|
self.ident = i
|
|
self.priority = p
|
|
self.input = w
|
|
|
|
self.packet_pending = initialState.isPacketPending()
|
|
self.task_waiting = initialState.isTaskWaiting()
|
|
self.task_holding = initialState.isTaskHolding()
|
|
|
|
self.handle = r
|
|
|
|
taskWorkArea.taskList = self
|
|
taskWorkArea.taskTab[i] = self
|
|
|
|
def fn(self, pkt, r):
|
|
raise NotImplementedError
|
|
|
|
def addPacket(self, p, old):
|
|
if self.input is None:
|
|
self.input = p
|
|
self.packet_pending = True
|
|
if self.priority > old.priority:
|
|
return self
|
|
else:
|
|
p.append_to(self.input)
|
|
return old
|
|
|
|
def runTask(self):
|
|
if self.isWaitingWithPacket():
|
|
msg = self.input
|
|
self.input = msg.link
|
|
if self.input is None:
|
|
self.running()
|
|
else:
|
|
self.packetPending()
|
|
else:
|
|
msg = None
|
|
|
|
return self.fn(msg, self.handle)
|
|
|
|
def waitTask(self):
|
|
self.task_waiting = True
|
|
return self
|
|
|
|
def hold(self):
|
|
taskWorkArea.holdCount += 1
|
|
self.task_holding = True
|
|
return self.link
|
|
|
|
def release(self, i):
|
|
t = self.findtcb(i)
|
|
t.task_holding = False
|
|
if t.priority > self.priority:
|
|
return t
|
|
else:
|
|
return self
|
|
|
|
def qpkt(self, pkt):
|
|
t = self.findtcb(pkt.ident)
|
|
taskWorkArea.qpktCount += 1
|
|
pkt.link = None
|
|
pkt.ident = self.ident
|
|
return t.addPacket(pkt, self)
|
|
|
|
def findtcb(self, id):
|
|
t = taskWorkArea.taskTab[id]
|
|
if t is None:
|
|
raise Exception("Bad task id %d" % id)
|
|
return t
|
|
|
|
|
|
# DeviceTask
|
|
|
|
|
|
class DeviceTask(Task):
|
|
|
|
def __init__(self, i, p, w, s, r):
|
|
Task.__init__(self, i, p, w, s, r)
|
|
|
|
def fn(self, pkt, r):
|
|
d = r
|
|
assert isinstance(d, DeviceTaskRec)
|
|
if pkt is None:
|
|
pkt = d.pending
|
|
if pkt is None:
|
|
return self.waitTask()
|
|
else:
|
|
d.pending = None
|
|
return self.qpkt(pkt)
|
|
else:
|
|
d.pending = pkt
|
|
if tracing:
|
|
trace(pkt.datum)
|
|
return self.hold()
|
|
|
|
|
|
class HandlerTask(Task):
|
|
|
|
def __init__(self, i, p, w, s, r):
|
|
Task.__init__(self, i, p, w, s, r)
|
|
|
|
def fn(self, pkt, r):
|
|
h = r
|
|
assert isinstance(h, HandlerTaskRec)
|
|
if pkt is not None:
|
|
if pkt.kind == K_WORK:
|
|
h.workInAdd(pkt)
|
|
else:
|
|
h.deviceInAdd(pkt)
|
|
work = h.work_in
|
|
if work is None:
|
|
return self.waitTask()
|
|
count = work.datum
|
|
if count >= BUFSIZE:
|
|
h.work_in = work.link
|
|
return self.qpkt(work)
|
|
|
|
dev = h.device_in
|
|
if dev is None:
|
|
return self.waitTask()
|
|
|
|
h.device_in = dev.link
|
|
dev.datum = work.data[count]
|
|
work.datum = count + 1
|
|
return self.qpkt(dev)
|
|
|
|
# IdleTask
|
|
|
|
|
|
class IdleTask(Task):
|
|
|
|
def __init__(self, i, p, w, s, r):
|
|
Task.__init__(self, i, 0, None, s, r)
|
|
|
|
def fn(self, pkt, r):
|
|
i = r
|
|
assert isinstance(i, IdleTaskRec)
|
|
i.count -= 1
|
|
if i.count == 0:
|
|
return self.hold()
|
|
elif i.control & 1 == 0:
|
|
i.control //= 2
|
|
return self.release(I_DEVA)
|
|
else:
|
|
i.control = i.control // 2 ^ 0xd008
|
|
return self.release(I_DEVB)
|
|
|
|
|
|
# WorkTask
|
|
|
|
|
|
A = ord('A')
|
|
|
|
|
|
class WorkTask(Task):
|
|
|
|
def __init__(self, i, p, w, s, r):
|
|
Task.__init__(self, i, p, w, s, r)
|
|
|
|
def fn(self, pkt, r):
|
|
w = r
|
|
assert isinstance(w, WorkerTaskRec)
|
|
if pkt is None:
|
|
return self.waitTask()
|
|
|
|
if w.destination == I_HANDLERA:
|
|
dest = I_HANDLERB
|
|
else:
|
|
dest = I_HANDLERA
|
|
|
|
w.destination = dest
|
|
pkt.ident = dest
|
|
pkt.datum = 0
|
|
|
|
for i in BUFSIZE_RANGE: # range(BUFSIZE)
|
|
w.count += 1
|
|
if w.count > 26:
|
|
w.count = 1
|
|
pkt.data[i] = A + w.count - 1
|
|
|
|
return self.qpkt(pkt)
|
|
|
|
|
|
def schedule():
|
|
t = taskWorkArea.taskList
|
|
while t is not None:
|
|
if tracing:
|
|
print("tcb =", t.ident)
|
|
|
|
if t.isTaskHoldingOrWaiting():
|
|
t = t.link
|
|
else:
|
|
if tracing:
|
|
trace(chr(ord("0") + t.ident))
|
|
t = t.runTask()
|
|
|
|
|
|
class Richards(object):
|
|
|
|
def run(self, iterations):
|
|
for i in range(iterations):
|
|
taskWorkArea.holdCount = 0
|
|
taskWorkArea.qpktCount = 0
|
|
|
|
IdleTask(I_IDLE, 1, 10000, TaskState().running(), IdleTaskRec())
|
|
|
|
wkq = Packet(None, 0, K_WORK)
|
|
wkq = Packet(wkq, 0, K_WORK)
|
|
WorkTask(I_WORK, 1000, wkq, TaskState(
|
|
).waitingWithPacket(), WorkerTaskRec())
|
|
|
|
wkq = Packet(None, I_DEVA, K_DEV)
|
|
wkq = Packet(wkq, I_DEVA, K_DEV)
|
|
wkq = Packet(wkq, I_DEVA, K_DEV)
|
|
HandlerTask(I_HANDLERA, 2000, wkq, TaskState(
|
|
).waitingWithPacket(), HandlerTaskRec())
|
|
|
|
wkq = Packet(None, I_DEVB, K_DEV)
|
|
wkq = Packet(wkq, I_DEVB, K_DEV)
|
|
wkq = Packet(wkq, I_DEVB, K_DEV)
|
|
HandlerTask(I_HANDLERB, 3000, wkq, TaskState(
|
|
).waitingWithPacket(), HandlerTaskRec())
|
|
|
|
wkq = None
|
|
DeviceTask(I_DEVA, 4000, wkq,
|
|
TaskState().waiting(), DeviceTaskRec())
|
|
DeviceTask(I_DEVB, 5000, wkq,
|
|
TaskState().waiting(), DeviceTaskRec())
|
|
|
|
schedule()
|
|
|
|
if taskWorkArea.holdCount == 9297 and taskWorkArea.qpktCount == 23246:
|
|
pass
|
|
else:
|
|
return False
|
|
|
|
return True
|
|
|
|
assert Richards().run(1)
|