py-alaska 0.1.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.
py_alaska/SmBlock.py ADDED
@@ -0,0 +1,263 @@
1
+ """
2
+ ╔══════════════════════════════════════════════════════════════════════════════╗
3
+ ║ ALASK v2.0 Project ║
4
+ ║ SmBlock - Shared Memory Block Allocator ║
5
+ ╠══════════════════════════════════════════════════════════════════════════════╣
6
+ ║ Version : 1.0.0 ║
7
+ ║ Date : 2026-02-01 ║
8
+ ╠══════════════════════════════════════════════════════════════════════════════╣
9
+ ║ Description: ║
10
+ ║ 프로세스 간 공유 메모리를 사용한 이미지 블록 풀 관리자. ║
11
+ ║ Free List 알고리즘으로 효율적인 O(1) 블록 할당/해제 수행. ║
12
+ ║ ║
13
+ ║ Memory Layout: ║
14
+ ║ [Index Buffer: int16[N]] + [Data Buffer: uint8[N][H][W][C]] + [Free Head] ║
15
+ ╚══════════════════════════════════════════════════════════════════════════════╝
16
+ """
17
+
18
+ from multiprocessing.shared_memory import SharedMemory
19
+ from typing import Tuple, Optional
20
+ import numpy as np
21
+
22
+
23
+ class SmBlock:
24
+ """프로세스 간 공유 메모리 이미지 블록 풀 관리자."""
25
+
26
+ __slots__ = ('_name', '_shape', '_maxsize', '_item_size', '_index_size',
27
+ '_is_new', '_shm', '_index_buffer', '_data_buffer', '_free_head',
28
+ '_lock', '_last_alloc')
29
+
30
+ def __init__(self, name: str, shape: Tuple[int, ...], maxsize: int,
31
+ create: bool = False, lock=None):
32
+ """SmBlock 초기화.
33
+
34
+ Args:
35
+ name: 공유 메모리 이름 (시스템 전역 고유)
36
+ shape: 이미지 형태 (height, width, channels)
37
+ maxsize: 최대 블록 수 (풀 크기)
38
+ create: True=새 공유 메모리 생성, False=기존에 연결
39
+ lock: multiprocessing.Lock 동시성 제어용
40
+
41
+ Raises:
42
+ FileExistsError: create=True인데 이미 존재할 때
43
+ FileNotFoundError: create=False인데 존재하지 않을 때
44
+ """
45
+ self._name = name
46
+ self._shape = shape
47
+ self._maxsize = maxsize
48
+ self._lock = lock
49
+ self._is_new = create
50
+ self._last_alloc = -1
51
+
52
+ # 크기 계산
53
+ self._item_size = int(np.prod(shape)) # H * W * C
54
+ self._index_size = 2 * maxsize # sizeof(int16) * N
55
+
56
+ # 총 공유 메모리 크기
57
+ total_size = self._index_size + (self._item_size * maxsize) + 2
58
+
59
+ # 공유 메모리 생성 또는 연결
60
+ if create:
61
+ self._shm = SharedMemory(name=name, create=True, size=total_size)
62
+ self._setup_buffers()
63
+ self._initialize_free_list()
64
+ else:
65
+ self._shm = SharedMemory(name=name, create=False)
66
+ self._setup_buffers()
67
+
68
+ def _setup_buffers(self):
69
+ """numpy 배열로 공유 메모리 영역 매핑."""
70
+ buf = self._shm.buf
71
+ n = self._maxsize
72
+
73
+ # Index Buffer: offset 0, size 2*N
74
+ self._index_buffer = np.ndarray(
75
+ (n,), dtype=np.int16,
76
+ buffer=buf[0:self._index_size]
77
+ )
78
+
79
+ # Data Buffer: offset 2*N, size N*H*W*C
80
+ data_offset = self._index_size
81
+ data_size = self._item_size * n
82
+ self._data_buffer = np.ndarray(
83
+ (n,) + self._shape, dtype=np.uint8,
84
+ buffer=buf[data_offset:data_offset + data_size]
85
+ )
86
+
87
+ # Free Head: offset 2*N + N*H*W*C, size 2
88
+ free_head_offset = data_offset + data_size
89
+ self._free_head = np.ndarray(
90
+ (1,), dtype=np.int16,
91
+ buffer=buf[free_head_offset:free_head_offset + 2]
92
+ )
93
+
94
+ def _initialize_free_list(self):
95
+ """Free List 초기화 (생성 시에만 호출)."""
96
+ n = self._maxsize
97
+ # 각 블록이 다음 블록을 가리키도록 설정
98
+ for i in range(n - 1):
99
+ self._index_buffer[i] = i + 1
100
+ self._index_buffer[n - 1] = -1 # 마지막 블록은 끝 표시
101
+ self._free_head[0] = 0 # 첫 번째 free 블록
102
+
103
+ def malloc(self, image: np.ndarray) -> int:
104
+ """이미지를 풀에 할당하고 인덱스 반환. O(1) 시간복잡도.
105
+
106
+ Args:
107
+ image: 저장할 이미지 (dtype=uint8, shape=생성자의 shape과 동일)
108
+
109
+ Returns:
110
+ 할당된 블록 인덱스 (0 ~ maxsize-1), 풀이 가득 차면 -1
111
+
112
+ Raises:
113
+ ValueError: 이미지 shape이 맞지 않을 때
114
+ """
115
+ if image.shape != self._shape:
116
+ raise ValueError(f"Shape mismatch: expected {self._shape}, got {image.shape}")
117
+
118
+ with self._lock:
119
+ head = self._free_head[0]
120
+ if head == -1:
121
+ return -1 # 풀이 가득 참
122
+
123
+ # Free list에서 블록 분리
124
+ next_free = self._index_buffer[head]
125
+ self._free_head[0] = next_free
126
+ self._index_buffer[head] = -1 # 사용 중 표시
127
+
128
+ # 데이터 복사
129
+ self._data_buffer[head][:] = image
130
+ self._last_alloc = head
131
+ return int(head)
132
+
133
+ def malloc2(self, image: np.ndarray) -> int:
134
+ """마지막 할당 위치 다음부터 순차 탐색하여 빈 공간 할당.
135
+
136
+ Args:
137
+ image: 저장할 이미지
138
+
139
+ Returns:
140
+ 할당된 블록 인덱스 또는 -1
141
+ """
142
+ if image.shape != self._shape:
143
+ raise ValueError(f"Shape mismatch: expected {self._shape}, got {image.shape}")
144
+
145
+ with self._lock:
146
+ n = self._maxsize
147
+ start = (self._last_alloc + 1) % n
148
+
149
+ # 순차 탐색으로 빈 블록 찾기
150
+ for offset in range(n):
151
+ idx = (start + offset) % n
152
+ if self._index_buffer[idx] != -1 or idx == self._free_head[0]:
153
+ # 빈 블록 발견 - Free list에서 제거
154
+ if idx == self._free_head[0]:
155
+ # head인 경우
156
+ self._free_head[0] = self._index_buffer[idx]
157
+ else:
158
+ # 중간 노드인 경우 - 이전 노드 찾아서 연결
159
+ prev = self._free_head[0]
160
+ while prev != -1 and self._index_buffer[prev] != idx:
161
+ prev = self._index_buffer[prev]
162
+ if prev != -1:
163
+ self._index_buffer[prev] = self._index_buffer[idx]
164
+
165
+ self._index_buffer[idx] = -1 # 사용 중 표시
166
+ self._data_buffer[idx][:] = image
167
+ self._last_alloc = idx
168
+ return idx
169
+
170
+ return -1 # 풀이 가득 참
171
+
172
+ def mfree(self, index: int):
173
+ """할당된 블록을 해제하고 Free List에 반환.
174
+
175
+ Args:
176
+ index: 해제할 블록 인덱스
177
+
178
+ Raises:
179
+ ValueError: 이미 비어있는 블록을 해제할 때
180
+ IndexError: 유효하지 않은 인덱스
181
+ """
182
+ if index < 0 or index >= self._maxsize:
183
+ raise IndexError(f"Index {index} out of range [0, {self._maxsize})")
184
+
185
+ with self._lock:
186
+ if self._index_buffer[index] != -1:
187
+ raise ValueError(f"Block {index} is already free")
188
+
189
+ # Free list의 head로 추가 (스택 방식)
190
+ self._index_buffer[index] = self._free_head[0]
191
+ self._free_head[0] = index
192
+
193
+ def get(self, index: int) -> np.ndarray:
194
+ """할당된 블록의 이미지 데이터 반환.
195
+
196
+ Args:
197
+ index: 읽을 블록 인덱스
198
+
199
+ Returns:
200
+ 이미지 데이터 (shape=생성자의 shape)
201
+
202
+ Raises:
203
+ ValueError: 비어있는 블록에 접근할 때
204
+ IndexError: 유효하지 않은 인덱스
205
+ """
206
+ if index < 0 or index >= self._maxsize:
207
+ raise IndexError(f"Index {index} out of range [0, {self._maxsize})")
208
+
209
+ with self._lock:
210
+ if self._index_buffer[index] != -1:
211
+ raise ValueError(f"Block {index} is free (not allocated)")
212
+
213
+ return self._data_buffer[index].copy()
214
+
215
+ def size(self) -> int:
216
+ """풀의 최대 크기(블록 수) 반환."""
217
+ return self._maxsize
218
+
219
+ def count(self) -> int:
220
+ """현재 사용 가능한(비어있는) 블록 수 반환."""
221
+ with self._lock:
222
+ cnt = 0
223
+ idx = self._free_head[0]
224
+ while idx != -1:
225
+ cnt += 1
226
+ idx = self._index_buffer[idx]
227
+ return cnt
228
+
229
+ def close(self):
230
+ """공유 메모리 연결 해제 및 정리."""
231
+ self._shm.close()
232
+ if self._is_new:
233
+ self._shm.unlink()
234
+
235
+ @property
236
+ def name(self) -> str:
237
+ return self._name
238
+
239
+ @property
240
+ def shape(self) -> Tuple[int, ...]:
241
+ return self._shape
242
+
243
+ @property
244
+ def maxsize(self) -> int:
245
+ return self._maxsize
246
+
247
+ @property
248
+ def item_size(self) -> int:
249
+ return self._item_size
250
+
251
+ @property
252
+ def index_size(self) -> int:
253
+ return self._index_size
254
+
255
+ @property
256
+ def is_new(self) -> bool:
257
+ return self._is_new
258
+
259
+ def __str__(self) -> str:
260
+ return f"SmBlock[ {self._name}, {self._shape}, {self._maxsize} ]"
261
+
262
+ def __repr__(self) -> str:
263
+ return self.__str__()
py_alaska/__init__.py ADDED
@@ -0,0 +1,63 @@
1
+ """
2
+ ╔══════════════════════════════════════════════════════════════════════════════╗
3
+ ║ ALASKA v2.0 로봇 얼라인 비전 시스템 ║
4
+ ║ Advanced Lightweight Asynchronous Service Kernel ║
5
+ ╠══════════════════════════════════════════════════════════════════════════════╣
6
+ ║ Project : ALASKA v2.0 ║
7
+ ║ Company : 동일비전소유 ║
8
+ ║ Version : 2.0.0 ║
9
+ ║ Date : 2026-01-31 ║
10
+ ╠══════════════════════════════════════════════════════════════════════════════╣
11
+ ║ Modules: ║
12
+ ║ - task_manager : TaskManager, TaskClass, TaskInfo, TaskWorker, RmiClient║
13
+ ║ - task_monitor : TaskMonitor (HTTP-based monitoring) ║
14
+ ║ - task_signal : Signal, SignalBroker, SignalClient ║
15
+ ║ - task_performance: MethodPerformance, TaskPerformance, SystemPerformance ║
16
+ ║ - gconfig : Global configuration management ║
17
+ ╚══════════════════════════════════════════════════════════════════════════════╝
18
+ """
19
+
20
+ from .task_manager import TaskManager, TaskClass, TaskInfo, TaskWorker, RmiClient
21
+ from .task_monitor import TaskMonitor
22
+ from .task_signal import Signal, SignalBroker, SignalClient
23
+ from .task_performance import (
24
+ MethodPerformance,
25
+ TaskPerformance,
26
+ SystemPerformance,
27
+ TimingRecorder,
28
+ PerformanceCollector,
29
+ )
30
+ from .gconfig import (
31
+ gconfig,
32
+ GConfig,
33
+ ConfigError,
34
+ ConfigFileNotFoundError,
35
+ ConfigPathNotFoundError,
36
+ ConfigLockTimeoutError,
37
+ ConfigValidationError,
38
+ ConfigParseError,
39
+ ConfigIntegrityError,
40
+ ConfigSecurityError,
41
+ ConfigStaleLockError,
42
+ ConfigMandatoryFieldError,
43
+ ConfigRecoveryError,
44
+ )
45
+
46
+ __version__ = "0.1.0"
47
+ __all__ = [
48
+ # Task Manager
49
+ "TaskManager", "TaskClass", "TaskInfo", "TaskWorker", "RmiClient",
50
+ # Task Monitor
51
+ "TaskMonitor",
52
+ # Task Signal
53
+ "Signal", "SignalBroker", "SignalClient",
54
+ # Task Performance
55
+ "MethodPerformance", "TaskPerformance", "SystemPerformance",
56
+ "TimingRecorder", "PerformanceCollector",
57
+ # GConfig
58
+ "gconfig", "GConfig",
59
+ "ConfigError", "ConfigFileNotFoundError", "ConfigPathNotFoundError",
60
+ "ConfigLockTimeoutError", "ConfigValidationError", "ConfigParseError",
61
+ "ConfigIntegrityError", "ConfigSecurityError", "ConfigStaleLockError",
62
+ "ConfigMandatoryFieldError", "ConfigRecoveryError",
63
+ ]
py_alaska/div_logo.png ADDED
Binary file