From 2e1ed817209194ee276d3fadde0533d5c1aa5f52 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Fri, 14 Apr 2023 10:33:39 -0700 Subject: [PATCH 1/3] add version of Richards that uses super() --- pyperformance/data-files/benchmarks/MANIFEST | 1 + .../bm_richards_super/pyproject.toml | 9 + .../bm_richards_super/run_benchmark.py | 430 ++++++++++++++++++ 3 files changed, 440 insertions(+) create mode 100644 pyperformance/data-files/benchmarks/bm_richards_super/pyproject.toml create mode 100644 pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py diff --git a/pyperformance/data-files/benchmarks/MANIFEST b/pyperformance/data-files/benchmarks/MANIFEST index 7d62c5a0..d472c2c1 100644 --- a/pyperformance/data-files/benchmarks/MANIFEST +++ b/pyperformance/data-files/benchmarks/MANIFEST @@ -58,6 +58,7 @@ regex_dna regex_effbot regex_v8 richards +richards_super scimark spectral_norm sqlalchemy_declarative diff --git a/pyperformance/data-files/benchmarks/bm_richards_super/pyproject.toml b/pyperformance/data-files/benchmarks/bm_richards_super/pyproject.toml new file mode 100644 index 00000000..3157a818 --- /dev/null +++ b/pyperformance/data-files/benchmarks/bm_richards_super/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "pyperformance_bm_richards_super" +requires-python = ">=3.8" +dependencies = ["pyperf"] +urls = {repository = "https://github.com/python/pyperformance"} +dynamic = ["version"] + +[tool.pyperformance] +name = "richards_super" diff --git a/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py b/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py new file mode 100644 index 00000000..7a7309b9 --- /dev/null +++ b/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py @@ -0,0 +1,430 @@ +""" +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 + super() usage added by Carl Meyer +""" + +import pyperf + + +# 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 + + self.last_packet = None + + def fn(self, pkt, r): + self.last_packet = pkt + + 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): + super().__init__(i, p, w, s, r) + + def fn(self, pkt, r): + d = r + assert isinstance(d, DeviceTaskRec) + super().fn(pkt, r) + 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): + super().__init__(i, p, w, s, r) + + def fn(self, pkt, r): + h = r + assert isinstance(h, HandlerTaskRec) + super().fn(pkt, r) + 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): + super().__init__(i, 0, None, s, r) + + def fn(self, pkt, r): + i = r + assert isinstance(i, IdleTaskRec) + super().fn(pkt, r) + 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): + super().__init__(i, p, w, s, r) + + def fn(self, pkt, r): + w = r + assert isinstance(w, WorkerTaskRec) + super().fn(pkt, r) + 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 + + +if __name__ == "__main__": + runner = pyperf.Runner() + runner.metadata['description'] = "The Richards benchmark" + + richard = Richards() + runner.bench_func('richards', richard.run, 1) From cefb41b418484c5817bf548ac5f999473d2c8d98 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Fri, 14 Apr 2023 10:57:15 -0700 Subject: [PATCH 2/3] update some metadata --- .../data-files/benchmarks/bm_richards_super/run_benchmark.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py b/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py index 7a7309b9..60245934 100644 --- a/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py +++ b/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py @@ -424,7 +424,7 @@ def run(self, iterations): if __name__ == "__main__": runner = pyperf.Runner() - runner.metadata['description'] = "The Richards benchmark" + runner.metadata['description'] = "The Richards benchmark, with super()" richard = Richards() - runner.bench_func('richards', richard.run, 1) + runner.bench_func('richards_super', richard.run, 1) From 0baf13954e0d39ab48a0b240f581aa577484fda7 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Tue, 25 Apr 2023 10:40:14 -0600 Subject: [PATCH 3/3] remove unnecessary inheriting from object --- .../benchmarks/bm_richards_super/run_benchmark.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py b/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py index 60245934..271ebfb3 100644 --- a/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py +++ b/pyperformance/data-files/benchmarks/bm_richards_super/run_benchmark.py @@ -32,7 +32,7 @@ BUFSIZE_RANGE = range(BUFSIZE) -class Packet(object): +class Packet: def __init__(self, l, i, k): self.link = l @@ -57,7 +57,7 @@ def append_to(self, lst): # Task Records -class TaskRec(object): +class TaskRec: pass @@ -97,7 +97,7 @@ def __init__(self): # Task -class TaskState(object): +class TaskState: def __init__(self): self.packet_pending = True @@ -160,7 +160,7 @@ def trace(a): TASKTABSIZE = 10 -class TaskWorkArea(object): +class TaskWorkArea: def __init__(self): self.taskTab = [None] * TASKTABSIZE @@ -380,7 +380,7 @@ def schedule(): t = t.runTask() -class Richards(object): +class Richards: def run(self, iterations): for i in range(iterations):