sram-engine 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ from .core import SRAMCommandDispatcher, SRAMSession
sram_engine/core.py ADDED
@@ -0,0 +1,268 @@
1
+ import os
2
+ import mmap
3
+ import ctypes
4
+ import subprocess
5
+ import sys
6
+
7
+ # Embedded C Kernel Code (ARM NEON / Multi-threaded Worker Engine)
8
+ C_KERNEL_CODE = """
9
+ #include <stdint.h>
10
+ #include <stdatomic.h>
11
+ #include <pthread.h>
12
+ #include <unistd.h>
13
+
14
+ #define NUM_THREADS 8
15
+ #define PARTITION_SIZE 40000
16
+
17
+ typedef struct {
18
+ uint32_t d[12];
19
+ } Node11D;
20
+
21
+ typedef struct {
22
+ pthread_t thread;
23
+ volatile Node11D *target_base;
24
+ uint32_t worker_id;
25
+ uint64_t local_ops;
26
+ atomic_int running;
27
+ atomic_int paused;
28
+ } __attribute__((aligned(64))) Target5MsWorker;
29
+
30
+ static Target5MsWorker worker_pool[NUM_THREADS];
31
+
32
+ void *target_5ms_worker_routine(void *arg) {
33
+ Target5MsWorker *w = (Target5MsWorker *__restrict__)arg;
34
+ uint64_t id = (uint64_t)w->worker_id;
35
+ uint64_t bytes_per_partition = PARTITION_SIZE * sizeof(Node11D);
36
+
37
+ while (atomic_load_explicit(&w->running, memory_order_relaxed)) {
38
+ if (atomic_load_explicit(&w->paused, memory_order_acquire)) {
39
+ usleep(50);
40
+ continue;
41
+ }
42
+
43
+ volatile Node11D *base = w->target_base;
44
+ if (!base) {
45
+ usleep(100);
46
+ continue;
47
+ }
48
+ uint64_t current_base = (uint64_t)base;
49
+ uint64_t end_base = current_base + bytes_per_partition;
50
+
51
+ __asm__ __volatile__ (
52
+ "mov x9, %[base]\\n\\t"
53
+ "mov x16, %[end_limit]\\n\\t"
54
+ "mov x10, %[v]\\n\\t"
55
+ "mov x11, #123\\n\\t"
56
+ "mov x12, #456\\n\\t"
57
+ "mov x13, #789\\n\\t"
58
+ "mov x14, #999\\n\\t"
59
+ "mov x15, #111\\n\\t"
60
+
61
+ "dup v0.4s, w10\\n\\t"
62
+ "dup v1.4s, w11\\n\\t"
63
+ "dup v2.4s, w12\\n\\t"
64
+ "dup v3.4s, w13\\n\\t"
65
+ "dup v4.4s, w14\\n\\t"
66
+ "dup v5.4s, w15\\n\\t"
67
+
68
+ ".rept 500\\n\\t"
69
+ "stp q0, q1, [x9], #32\\n\\t"
70
+ "str q2, [x9], #16\\n\\t"
71
+ "stp q3, q4, [x9], #32\\n\\t"
72
+ "str q5, [x9], #16\\n\\t"
73
+ ".endr\\n\\t"
74
+
75
+ "cmp x9, x16\\n\\t"
76
+ "b.lt 1f\\n\\t"
77
+ "mov x9, %[base]\\n\\t"
78
+ "1:\\n\\t"
79
+ :
80
+ : [base] "r" (current_base), [end_limit] "r" (end_base), [v] "r" (id)
81
+ : "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "v0", "v1", "v2", "v3", "v4", "v5", "memory"
82
+ );
83
+ w->local_ops += 1000;
84
+ }
85
+ return NULL;
86
+ }
87
+
88
+ void target_5ms_init(volatile Node11D *base_ptr) {
89
+ for (int i = 0; i < NUM_THREADS; i++) {
90
+ worker_pool[i].target_base = base_ptr + (i * PARTITION_SIZE);
91
+ worker_pool[i].worker_id = i + 1;
92
+ worker_pool[i].local_ops = 0;
93
+ atomic_init(&worker_pool[i].running, 1);
94
+ atomic_init(&worker_pool[i].paused, 0);
95
+ pthread_create(&worker_pool[i].thread, NULL, target_5ms_worker_routine, &worker_pool[i]);
96
+ }
97
+ }
98
+
99
+ void target_5ms_pause_workers(int pause) {
100
+ for (int i = 0; i < NUM_THREADS; i++) {
101
+ atomic_store_explicit(&worker_pool[i].paused, pause, memory_order_release);
102
+ }
103
+ usleep(150);
104
+ }
105
+
106
+ void target_5ms_update_base(volatile Node11D *base_ptr) {
107
+ target_5ms_pause_workers(1);
108
+ for (int i = 0; i < NUM_THREADS; i++) {
109
+ worker_pool[i].target_base = base_ptr + (i * PARTITION_SIZE);
110
+ }
111
+ target_5ms_pause_workers(0);
112
+ }
113
+
114
+ uint64_t target_5ms_get_total_ops(void) {
115
+ uint64_t total = 0;
116
+ for (int i = 0; i < NUM_THREADS; i++) {
117
+ total += worker_pool[i].local_ops;
118
+ }
119
+ return total;
120
+ }
121
+
122
+ void target_5ms_destroy(void) {
123
+ for (int i = 0; i < NUM_THREADS; i++) {
124
+ atomic_store_explicit(&worker_pool[i].running, 0, memory_order_release);
125
+ atomic_store_explicit(&worker_pool[i].paused, 0, memory_order_release);
126
+ pthread_join(worker_pool[i].thread, NULL);
127
+ }
128
+ }
129
+ """
130
+
131
+ class Node11DStruct(ctypes.Structure):
132
+ _fields_ = [("d", ctypes.c_uint32 * 12)]
133
+
134
+ class SRAMSession:
135
+ def __init__(self, session_name, storage_mb):
136
+ self.session_name = session_name
137
+ self.window_size = storage_mb * 1024 * 1024
138
+
139
+ internal_dir = "/data/user/0/ru.iiec.pydroid3"
140
+ if os.access(internal_dir, os.W_OK):
141
+ work_dir = os.path.join(internal_dir, "app_sram_" + session_name)
142
+ else:
143
+ work_dir = os.path.join(os.getcwd(), "app_sram_" + session_name)
144
+
145
+ os.makedirs(work_dir, exist_ok=True)
146
+
147
+ self.kernel_c_path = os.path.join(work_dir, "sram_5ms_kernel.c")
148
+ self.kernel_so_path = os.path.join(work_dir, "sram_5ms_kernel.so")
149
+ self.pool_file_path = os.path.join(work_dir, "persistent_sram_pool.bin")
150
+
151
+ with open(self.kernel_c_path, "w") as f:
152
+ f.write(C_KERNEL_CODE)
153
+
154
+ compile_cmd = f"gcc -O3 -march=native -ffast-math -fomit-frame-pointer -shared -fPIC {self.kernel_c_path} -o {self.kernel_so_path} -lpthread"
155
+ if os.system(compile_cmd) != 0:
156
+ os.system(f"gcc -O3 -shared -fPIC {self.kernel_c_path} -o {self.kernel_so_path} -lpthread")
157
+
158
+ self._lib = ctypes.CDLL(self.kernel_so_path)
159
+ self._lib.target_5ms_init.argtypes = [ctypes.c_void_p]
160
+ self._lib.target_5ms_get_total_ops.restype = ctypes.c_uint64
161
+ self._lib.target_5ms_pause_workers.argtypes = [ctypes.c_int]
162
+
163
+ with open(self.pool_file_path, "wb") as f:
164
+ f.write(b"\x00" * self.window_size)
165
+
166
+ self.file_obj = open(self.pool_file_path, "r+b")
167
+ self.mmap_buf = mmap.mmap(self.file_obj.fileno(), length=self.window_size, access=mmap.ACCESS_WRITE)
168
+ self.storage_ptr = ctypes.cast(
169
+ ctypes.addressof(ctypes.c_char.from_buffer(self.mmap_buf)),
170
+ ctypes.POINTER(Node11DStruct)
171
+ )
172
+
173
+ self._lib.target_5ms_init(self.storage_ptr)
174
+ self.is_paused = False
175
+ self.process = None
176
+
177
+ def run_script(self, python_path, multistring):
178
+ env = os.environ.copy()
179
+ env["SRAM_SESSION"] = self.session_name
180
+ env["SRAM_POOL_PATH"] = self.pool_file_path
181
+ env["SRAM_MULTISTRING"] = str(multistring)
182
+ env["SRAM_WINDOW_SIZE"] = str(self.window_size)
183
+
184
+ print(f"[SRAM] Spawning target script '{python_path}' on session '{self.session_name}'...")
185
+ self.process = subprocess.Popen([sys.executable, python_path], env=env)
186
+
187
+ def pause(self, pause_state: int):
188
+ self.is_paused = bool(pause_state)
189
+ self._lib.target_5ms_pause_workers(int(pause_state))
190
+
191
+ def resume(self):
192
+ self.is_paused = False
193
+ self._lib.target_5ms_pause_workers(0)
194
+
195
+ def get_ops(self):
196
+ return self._lib.target_5ms_get_total_ops()
197
+
198
+ def destroy(self):
199
+ try:
200
+ if self.process and self.process.poll() is None:
201
+ self.process.terminate()
202
+ self._lib.target_5ms_destroy()
203
+ if self.mmap_buf:
204
+ self.mmap_buf.close()
205
+ if self.file_obj:
206
+ self.file_obj.close()
207
+ if os.path.exists(self.pool_file_path):
208
+ os.remove(self.pool_file_path)
209
+ print(f"[SRAM] Session '{self.session_name}' successfully destroyed.")
210
+ except Exception as e:
211
+ print(f"[ERROR] Cleanup error: {e}")
212
+
213
+
214
+ class SRAMCommandDispatcher:
215
+ def __init__(self):
216
+ self.sessions = {}
217
+
218
+ def execute(self, command_line: str):
219
+ parts = command_line.strip().split()
220
+ if not parts:
221
+ return
222
+
223
+ cmd = parts[0]
224
+
225
+ if cmd == "SRAM_Run":
226
+ py_path = parts[1]
227
+ storage_mb = int(parts[3])
228
+ multistring = parts[5].lower() == 'true'
229
+ session_name = parts[7]
230
+
231
+ session = SRAMSession(session_name, storage_mb)
232
+ self.sessions[session_name] = session
233
+ session.run_script(py_path, multistring)
234
+
235
+ elif cmd == "SRAM_monitor":
236
+ session_name = parts[1]
237
+ if session_name in self.sessions:
238
+ s = self.sessions[session_name]
239
+ ops = s.get_ops()
240
+ print(f"[MONITOR] Session '{session_name}' | Total Ops: {ops:,d} | Paused: {s.is_paused}")
241
+ else:
242
+ print(f"[ERROR] Session '{session_name}' not found.")
243
+
244
+ elif cmd == "SRAM_pause":
245
+ session_name = parts[1]
246
+ if session_name in self.sessions:
247
+ s = self.sessions[session_name]
248
+ s.pause(1)
249
+ print(f"[PAUSE] Session '{session_name}' paused.")
250
+ else:
251
+ print(f"[ERROR] Session '{session_name}' not found.")
252
+
253
+ elif cmd == "SRAM_resume":
254
+ session_name = parts[1]
255
+ if session_name in self.sessions:
256
+ s = self.sessions[session_name]
257
+ s.resume()
258
+ print(f"[RESUME] Session '{session_name}' resumed.")
259
+ else:
260
+ print(f"[ERROR] Session '{session_name}' not found.")
261
+
262
+ elif cmd == "SRAM_stop":
263
+ session_name = parts[1]
264
+ if session_name in self.sessions:
265
+ s = self.sessions.pop(session_name)
266
+ s.destroy()
267
+ else:
268
+ print(f"[ERROR] Session '{session_name}' not found.")
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.4
2
+ Name: sram_engine
3
+ Version: 1.0.0
4
+ Summary: High-speed virtual SRAM engine with C/NEON backend
5
+ Author: Developer
6
+ Requires-Python: >=3.6
7
+ Dynamic: author
8
+ Dynamic: requires-python
9
+ Dynamic: summary
@@ -0,0 +1,6 @@
1
+ sram_engine/__init__.py,sha256=LMvMn4YRKGauGVodhkwKH2_TFo5wgWLR42aVFoxl5Xs,53
2
+ sram_engine/core.py,sha256=9MzNxCjs72ayUGVSWK5DxW5L-BfxyRcU3WEEtuzdFJk,9185
3
+ sram_engine-1.0.0.dist-info/METADATA,sha256=1iJEdc9YLowv1cco49QsiMAC9fiLiPYsTZDhjpxwkUs,214
4
+ sram_engine-1.0.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
5
+ sram_engine-1.0.0.dist-info/top_level.txt,sha256=MhzH5GD1s7jO6dX6YG4YQiJ3SzSD2rNcfuSnLPVM31c,12
6
+ sram_engine-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ sram_engine