Factor Studios commited on
Commit
06b5f7e
·
verified ·
1 Parent(s): 0d0e562

Upload 12 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.9-slim
3
+
4
+ # Set environment variables
5
+ ENV PYTHONUNBUFFERED=1
6
+
7
+ # Set working directory in container
8
+ WORKDIR /app
9
+
10
+ # Install system dependencies
11
+ RUN apt-get update && apt-get install -y \
12
+ gcc \
13
+ python3-dev \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ # Copy only the requirements file first
17
+ COPY virtual_gpu_server/requirements.txt .
18
+
19
+ # Install Python dependencies
20
+ RUN pip install --no-cache-dir -r requirements.txt
21
+
22
+ # Copy the server code
23
+ COPY virtual_gpu_server/ .
24
+
25
+ # Create storage directories
26
+ RUN mkdir -p /app/storage/vram_blocks/active \
27
+ /app/storage/vram_blocks/archived \
28
+ /app/storage/vram_blocks/temp \
29
+ /app/storage/gpu_state \
30
+ /app/storage/cache
31
+
32
+ # Expose ports
33
+ EXPOSE 7860
34
+ EXPOSE 8765
35
+
36
+ # Set environment variable for storage path
37
+ ENV STORAGE_PATH=/app/storage
38
+
39
+ # Run the server using Uvicorn
40
+ CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "7860", "--ws", "websockets"]
config.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "server": {
3
+ "host": "localhost",
4
+ "port": 8765,
5
+ "max_connections": 1000
6
+ },
7
+ "storage": {
8
+ "vram": {
9
+ "block_size": 1048576, // 1MB blocks
10
+ "max_cache_size": 8589934592, // 8GB cache
11
+ "persistence": true
12
+ },
13
+ "state": {
14
+ "cache_ttl": 3600, // 1 hour cache lifetime
15
+ "compression": true
16
+ },
17
+ "cache": {
18
+ "max_memory_size": 4294967296, // 4GB memory cache
19
+ "eviction_policy": "lru"
20
+ }
21
+ },
22
+ "performance": {
23
+ "prefetch_enabled": true,
24
+ "compression_level": 1,
25
+ "cache_warmup": true
26
+ }
27
+ }
handlers.py ADDED
File without changes
requirements.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Virtual GPU Server Core Dependencies
2
+ numpy==1.24.3 # Array operations for GPU data handling
3
+ websockets==11.0.3 # WebSocket server implementation
4
+ aiohttp==3.8.5 # HTTP server and async web framework
5
+ uvicorn==0.23.2 # ASGI server implementation
6
+
7
+ # WebSocket/HTTP Server Dependencies
8
+ aiosignal==1.3.1 # Async signals
9
+ async-timeout==4.0.3 # Timeouts for async operations
10
+ attrs==23.1.0 # Class builders
11
+ charset-normalizer==3.2.0 # Unicode normalization
12
+ frozenlist==1.4.0 # Immutable lists
13
+ multidict==6.0.4 # Dict with multiple values per key
14
+ yarl==1.9.2 # URL handling
15
+
16
+ # Performance & Utilities
17
+ ujson==5.8.0 # Fast JSON processing
18
+ psutil==5.9.5 # System and process monitoring
19
+ pathlib==1.0.1 # Path manipulation
requirements_new.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Virtual GPU Server Core Dependencies
2
+ numpy==1.24.3 # Array operations for GPU data handling
3
+ fastapi==0.103.0 # FastAPI framework
4
+ uvicorn==0.23.2 # ASGI server
5
+
6
+ # WebSocket Dependencies
7
+ websockets==11.0.3 # WebSocket support
8
+ websocket-client==1.6.1 # WebSocket client
9
+
10
+ # Performance & Utilities
11
+ ujson==5.8.0 # Fast JSON processing
12
+ psutil==5.9.5 # System and process monitoring
13
+ pathlib==1.0.1 # Path manipulation
14
+
15
+ # FastAPI Dependencies
16
+ starlette==0.27.0 # Web framework required by FastAPI
17
+ pydantic==2.3.0 # Data validation
18
+ python-multipart==0.0.6 # Form/File uploads
19
+ typing-extensions==4.7.1 # Enhanced typing support
server.py ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import json
3
+ import os
4
+ from pathlib import Path
5
+ import uuid
6
+ import time
7
+ from typing import Dict, Any, Optional
8
+ import numpy as np
9
+ from fastapi import FastAPI, WebSocket
10
+ from fastapi.responses import HTMLResponse
11
+ from datetime import datetime
12
+
13
+ # Create FastAPI instance
14
+ app = FastAPI()
15
+
16
+ class VirtualGPUServer:
17
+ def __init__(self):
18
+ self.base_path = Path(__file__).parent / "storage"
19
+ self.vram_path = self.base_path / "vram_blocks"
20
+ self.state_path = self.base_path / "gpu_state"
21
+ self.cache_path = self.base_path / "cache"
22
+
23
+ # Ensure all storage directories exist
24
+ self.vram_path.mkdir(parents=True, exist_ok=True)
25
+ self.state_path.mkdir(parents=True, exist_ok=True)
26
+ self.cache_path.mkdir(parents=True, exist_ok=True)
27
+
28
+ # In-memory caches for faster access
29
+ self.vram_cache: Dict[str, Any] = {}
30
+ self.state_cache: Dict[str, Any] = {}
31
+ self.memory_cache: Dict[str, Any] = {}
32
+
33
+ # Active connections and sessions
34
+ self.active_connections: Dict[str, WebSocket] = {}
35
+ self.active_sessions: Dict[str, Dict[str, Any]] = {}
36
+ self.heartbeat_interval = 5 # seconds
37
+ self.connection_timeout = 30 # seconds
38
+
39
+ # Performance monitoring
40
+ self.ops_counter = 0
41
+ self.start_time = time.time()
42
+
43
+ def _make_json_serializable(self, obj):
44
+ """Convert non-JSON-serializable objects to serializable format"""
45
+ if isinstance(obj, dict):
46
+ return {k: self._make_json_serializable(v) for k, v in obj.items()}
47
+ elif isinstance(obj, list):
48
+ return [self._make_json_serializable(i) for i in obj]
49
+ elif isinstance(obj, tuple):
50
+ return list(obj)
51
+ elif isinstance(obj, (np.ndarray, np.generic)):
52
+ return obj.tolist()
53
+ elif isinstance(obj, (Path, uuid.UUID)):
54
+ return str(obj)
55
+ elif hasattr(obj, '__dict__'):
56
+ # Handle custom objects by converting their __dict__ to serializable format
57
+ return self._make_json_serializable(obj.__dict__)
58
+ elif isinstance(obj, (int, float, str, bool, type(None))):
59
+ return obj
60
+ else:
61
+ # Convert any other types to string representation
62
+ return str(obj)
63
+
64
+ async def monitor_connection(self, websocket: WebSocket, session_id: str):
65
+ """Monitor connection health and handle reconnection"""
66
+ try:
67
+ while session_id in self.active_connections:
68
+ try:
69
+ await asyncio.wait_for(websocket.receive_text(), timeout=self.heartbeat_interval)
70
+ except asyncio.TimeoutError:
71
+ try:
72
+ await websocket.send_json({"type": "ping"})
73
+ except:
74
+ print(f"Connection lost for session {session_id}")
75
+ break
76
+ except Exception:
77
+ break
78
+ await asyncio.sleep(self.heartbeat_interval)
79
+ finally:
80
+ await self.handle_disconnect(session_id)
81
+
82
+ async def handle_disconnect(self, session_id: str):
83
+ """Clean up resources when a client disconnects"""
84
+ if session_id in self.active_connections:
85
+ try:
86
+ await self.active_connections[session_id].close()
87
+ except:
88
+ pass
89
+ del self.active_connections[session_id]
90
+ if session_id in self.active_sessions:
91
+ # Save any pending state before removing session
92
+ session_data = self.active_sessions[session_id]
93
+ if session_data.get('pending_state'):
94
+ await self.handle_state_operation({
95
+ 'type': 'save',
96
+ 'component': 'session',
97
+ 'state_id': session_id,
98
+ 'data': session_data['pending_state']
99
+ })
100
+ del self.active_sessions[session_id]
101
+
102
+ async def handle_vram_operation(self, operation: dict) -> dict:
103
+ """Handle VRAM read/write operations"""
104
+ try:
105
+ op_type = operation.get('type')
106
+ if not op_type:
107
+ raise ValueError("Missing operation type")
108
+
109
+ block_id = operation.get('block_id')
110
+ if not block_id:
111
+ raise ValueError("Missing block_id")
112
+
113
+ data = operation.get('data')
114
+ if data and isinstance(data, (dict, list)):
115
+ data = self._make_json_serializable(data)
116
+
117
+ if op_type == 'write':
118
+ if data is None:
119
+ raise ValueError("Missing data for write operation")
120
+ file_path = self.vram_path / f"{block_id}.npy"
121
+ np.save(file_path, np.array(data))
122
+ self.vram_cache[block_id] = np.array(data)
123
+ return {'status': 'success', 'message': f'Block {block_id} written'}
124
+
125
+ if op_type == 'read':
126
+ if block_id in self.vram_cache:
127
+ return {
128
+ 'status': 'success',
129
+ 'data': self.vram_cache[block_id] if isinstance(self.vram_cache[block_id], list) else self.vram_cache[block_id].tolist(),
130
+ 'source': 'cache'
131
+ }
132
+
133
+ file_path = self.vram_path / f"{block_id}.npy"
134
+ if file_path.exists():
135
+ data = np.load(file_path)
136
+ self.vram_cache[block_id] = np.array(data)
137
+ return {
138
+ 'status': 'success',
139
+ 'data': data.tolist(),
140
+ 'source': 'disk'
141
+ }
142
+ return {'status': 'error', 'message': 'Block not found'}
143
+
144
+ return {'status': 'error', 'message': f'Unknown operation type: {op_type}'}
145
+
146
+ except ValueError as e:
147
+ return {'status': 'error', 'message': str(e)}
148
+ except Exception as e:
149
+ return {'status': 'error', 'message': f'Operation failed: {str(e)}'}
150
+
151
+ async def handle_state_operation(self, operation: dict) -> dict:
152
+ """Handle GPU state operations"""
153
+ op_type = operation.get('type')
154
+ component = operation.get('component')
155
+ state_id = operation.get('state_id')
156
+ state_data = operation.get('data')
157
+
158
+ file_path = self.state_path / component / f"{state_id}.json"
159
+
160
+ if op_type == 'save':
161
+ file_path.parent.mkdir(exist_ok=True)
162
+ with open(file_path, 'w') as f:
163
+ json.dump(state_data, f)
164
+ self.state_cache[f"{component}:{state_id}"] = state_data
165
+ return {'status': 'success', 'message': f'State {state_id} saved'}
166
+
167
+ elif op_type == 'load':
168
+ cache_key = f"{component}:{state_id}"
169
+ if cache_key in self.state_cache:
170
+ return {
171
+ 'status': 'success',
172
+ 'data': self.state_cache[cache_key],
173
+ 'source': 'cache'
174
+ }
175
+
176
+ if file_path.exists():
177
+ with open(file_path) as f:
178
+ state_data = json.load(f)
179
+ self.state_cache[cache_key] = state_data
180
+ return {
181
+ 'status': 'success',
182
+ 'data': state_data,
183
+ 'source': 'disk'
184
+ }
185
+
186
+ return {'status': 'error', 'message': 'State not found'}
187
+
188
+ async def handle_cache_operation(self, operation: dict) -> dict:
189
+ """Handle cache operations"""
190
+ op_type = operation.get('type')
191
+ key = operation.get('key')
192
+ data = operation.get('data')
193
+
194
+ if op_type == 'set':
195
+ self.memory_cache[key] = data
196
+ # Also persist to disk for recovery
197
+ file_path = self.cache_path / f"{key}.json"
198
+ with open(file_path, 'w') as f:
199
+ json.dump(data, f)
200
+ return {'status': 'success', 'message': f'Cache key {key} set'}
201
+
202
+ elif op_type == 'get':
203
+ if key in self.memory_cache:
204
+ return {
205
+ 'status': 'success',
206
+ 'data': self.memory_cache[key],
207
+ 'source': 'memory'
208
+ }
209
+
210
+ file_path = self.cache_path / f"{key}.json"
211
+ if file_path.exists():
212
+ with open(file_path) as f:
213
+ data = json.load(f)
214
+ self.memory_cache[key] = data
215
+ return {
216
+ 'status': 'success',
217
+ 'data': data,
218
+ 'source': 'disk'
219
+ }
220
+
221
+ return {'status': 'error', 'message': 'Cache key not found'}
222
+
223
+
224
+ async def handle_connection(self, websocket: WebSocket, connection_type: str):
225
+ """Handle incoming WebSocket connections"""
226
+ # Generate unique session ID
227
+ session_id = str(uuid.uuid4())
228
+ self.active_connections[session_id] = websocket
229
+ self.active_sessions[session_id] = {
230
+ 'start_time': time.time(),
231
+ 'ops_count': 0,
232
+ 'connection_type': connection_type
233
+ }
234
+
235
+ try:
236
+ while True:
237
+ message = await websocket.receive_json()
238
+
239
+ # Route operation to appropriate handler
240
+ operation_type = message.get('operation')
241
+ if operation_type == 'vram':
242
+ response = await self.handle_vram_operation(message)
243
+ elif operation_type == 'state':
244
+ response = await self.handle_state_operation(message)
245
+ elif operation_type == 'cache':
246
+ response = await self.handle_cache_operation(message)
247
+ else:
248
+ response = {
249
+ 'status': 'error',
250
+ 'message': 'Unknown operation type'
251
+ }
252
+
253
+ # Update statistics
254
+ self.ops_counter += 1
255
+ self.active_sessions[session_id]['ops_count'] += 1
256
+
257
+ # Send response
258
+ await websocket.send_json(response)
259
+
260
+ except Exception as e:
261
+ print(f"WebSocket error: {e}")
262
+ finally:
263
+ # Cleanup on disconnect
264
+ if session_id in self.active_connections:
265
+ del self.active_connections[session_id]
266
+ if session_id in self.active_sessions:
267
+ del self.active_sessions[session_id]
268
+
269
+ def get_stats(self) -> dict:
270
+ uptime = current_time - self.start_time
271
+ ops_per_second = self.ops_counter / uptime if uptime > 0 else 0
272
+
273
+ return {
274
+ 'uptime': uptime,
275
+ 'total_operations': self.ops_counter,
276
+ 'ops_per_second': ops_per_second,
277
+ 'active_connections': len(self.active_connections),
278
+ 'vram_cache_size': len(self.vram_cache),
279
+ 'state_cache_size': len(self.state_cache),
280
+ 'memory_cache_size': len(self.memory_cache)
281
+ }
282
+
283
+ server = VirtualGPUServer()
284
+
285
+ @app.get("/", response_class=HTMLResponse)
286
+ async def handle_index():
287
+ """Handle HTTP index request"""
288
+ stats = server.get_stats()
289
+ html = f"""
290
+ <!DOCTYPE html>
291
+ <html>
292
+ <head>
293
+ <title>Virtual GPU Server</title>
294
+ <style>
295
+ body {{ font-family: Arial, sans-serif; margin: 40px; }}
296
+ table {{ border-collapse: collapse; width: 100%; margin-top: 20px; }}
297
+ th, td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }}
298
+ th {{ background-color: #f2f2f2; }}
299
+ .stats {{ background-color: #f9f9f9; padding: 20px; border-radius: 5px; }}
300
+ </style>
301
+ </head>
302
+ <body>
303
+ <h1>Virtual GPU Server Status</h1>
304
+ <div class="stats">
305
+ <h2>Server Statistics</h2>
306
+ <ul>
307
+ <li>Uptime: {stats['uptime']:.2f} seconds</li>
308
+ <li>Total Operations: {stats['total_operations']}</li>
309
+ <li>Operations per Second: {stats['ops_per_second']:.2f}</li>
310
+ <li>Active Connections: {stats['active_connections']}</li>
311
+ <li>VRAM Cache Size: {stats['vram_cache_size']}</li>
312
+ <li>State Cache Size: {stats['state_cache_size']}</li>
313
+ <li>Memory Cache Size: {stats['memory_cache_size']}</li>
314
+ </ul>
315
+ </div>
316
+ <h2>Server Files</h2>
317
+ <iframe src="/files" style="width: 100%; height: 500px; border: none;"></iframe>
318
+ </body>
319
+ </html>
320
+ """
321
+ return HTMLResponse(content=html)
322
+
323
+ @app.get("/files", response_class=HTMLResponse)
324
+ async def handle_files():
325
+ """Handle HTTP files listing request"""
326
+ def format_size(size):
327
+ for unit in ['B', 'KB', 'MB', 'GB']:
328
+ if size < 1024:
329
+ return f"{size:.2f} {unit}"
330
+ size /= 1024
331
+ return f"{size:.2f} TB"
332
+
333
+ html = ['<!DOCTYPE html><html><head>',
334
+ '<style>',
335
+ 'body { font-family: Arial, sans-serif; margin: 20px; }',
336
+ 'table { border-collapse: collapse; width: 100%; }',
337
+ 'th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }',
338
+ 'th { background-color: #f2f2f2; }',
339
+ '</style></head><body>',
340
+ '<h2>Server Files</h2>',
341
+ '<table><tr><th>Path</th><th>Size</th><th>Last Modified</th></tr>']
342
+
343
+ for root, _, files in os.walk(server.base_path):
344
+ for file in files:
345
+ full_path = Path(root) / file
346
+ rel_path = full_path.relative_to(server.base_path)
347
+ size = format_size(os.path.getsize(full_path))
348
+ mtime = datetime.fromtimestamp(os.path.getmtime(full_path))
349
+ html.append(f'<tr><td>{rel_path}</td><td>{size}</td><td>{mtime}</td></tr>')
350
+
351
+ html.extend(['</table></body></html>'])
352
+ return HTMLResponse(content='\n'.join(html))
353
+
354
+ # WebSocket endpoint
355
+ @app.websocket("/ws")
356
+ async def websocket_endpoint(websocket: WebSocket):
357
+ await websocket.accept()
358
+ await server.handle_connection(websocket, "gpu")
359
+
360
+ @app.websocket("/ws/model")
361
+ async def websocket_model_endpoint(websocket: WebSocket):
362
+ await websocket.accept()
363
+ await server.handle_connection(websocket, "model")
364
+
365
+
storage/cache/model_info.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"model_version": "v1.2", "accuracy": 0.98}
storage/gpu_state/gpu_core/current_state.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"gpu_temp": 65, "fan_speed": 2000}
storage/vram_blocks/test_model_123_11.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6b77c2d6a8693eece477e2ac5cd425c1a2e1bc2d8bb1fbb684d3a6804588e01e
3
+ size 8388736
storage/vram_blocks/test_model_123_14.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:39c2d4f10e76b70763505974c095aba40a2127a7153ad741390ad8e6f796c7b1
3
+ size 8388736
storage_manager.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import json
3
+ import shutil
4
+ import os
5
+ from typing import Dict, Any, Optional
6
+ import numpy as np
7
+ from datetime import datetime
8
+
9
+ class StorageManager:
10
+ def __init__(self, base_path: Path):
11
+ self.base_path = base_path
12
+
13
+ # Storage paths
14
+ self.vram_path = base_path / "vram_blocks"
15
+ self.state_path = base_path / "gpu_state"
16
+ self.cache_path = base_path / "cache"
17
+
18
+ # Create directory structure
19
+ self._init_storage()
20
+
21
+ # Component paths
22
+ self.component_paths = {
23
+ 'cores': self.state_path / "cores",
24
+ 'tensor_cores': self.state_path / "tensor_cores",
25
+ 'warps': self.state_path / "warps",
26
+ 'threads': self.state_path / "threads",
27
+ 'memory': self.state_path / "memory"
28
+ }
29
+
30
+ def _init_storage(self):
31
+ """Initialize storage directory structure with unlimited capacity support"""
32
+ # Create main directories with unlimited storage capacity
33
+ self.vram_path.mkdir(parents=True, exist_ok=True)
34
+ self.state_path.mkdir(parents=True, exist_ok=True)
35
+ self.cache_path.mkdir(parents=True, exist_ok=True)
36
+
37
+ # Create subdirectories for different types of state
38
+ for component in ['cores', 'tensor_cores', 'warps', 'threads', 'memory']:
39
+ (self.state_path / component).mkdir(exist_ok=True)
40
+
41
+ # Create VRAM block subdirectories with unlimited capacity
42
+ for subdir in ['active', 'archived', 'temp']:
43
+ (self.vram_path / subdir).mkdir(exist_ok=True)
44
+
45
+ # Initialize storage configuration for unlimited capacity
46
+ self.storage_config = {
47
+ "unlimited_storage": True,
48
+ "dynamic_scaling": True,
49
+ "auto_compress": False # Disabled for maximum performance
50
+ }
51
+
52
+ def store_vram_block(self, block_id: str, data: np.ndarray, temp: bool = False) -> Path:
53
+ """Store a VRAM block with metadata"""
54
+ # Determine storage location
55
+ if temp:
56
+ target_dir = self.vram_path / "temp"
57
+ else:
58
+ target_dir = self.vram_path / "active"
59
+
60
+ file_path = target_dir / f"{block_id}.npz"
61
+ metadata_path = target_dir / f"{block_id}.meta.json"
62
+
63
+ # Save data and metadata
64
+ np.savez_compressed(file_path, data=data)
65
+ metadata = {
66
+ 'created': datetime.now().isoformat(),
67
+ 'shape': data.shape,
68
+ 'dtype': str(data.dtype),
69
+ 'size_bytes': data.nbytes
70
+ }
71
+ with open(metadata_path, 'w') as f:
72
+ json.dump(metadata, f)
73
+
74
+ return file_path
75
+
76
+ def load_vram_block(self, block_id: str) -> Optional[np.ndarray]:
77
+ """Load a VRAM block with fallback to archived"""
78
+ # Check active blocks first
79
+ active_path = self.vram_path / "active" / f"{block_id}.npz"
80
+ if active_path.exists():
81
+ return np.load(active_path)['data']
82
+
83
+ # Check archived blocks
84
+ archived_path = self.vram_path / "archived" / f"{block_id}.npz"
85
+ if archived_path.exists():
86
+ data = np.load(archived_path)['data']
87
+ # Move back to active
88
+ self.store_vram_block(block_id, data)
89
+ return data
90
+
91
+ return None
92
+
93
+ def store_component_state(self, component: str, state_id: str, state: Dict) -> Path:
94
+ """Store component state with versioning"""
95
+ component_path = self.component_paths[component]
96
+ state_dir = component_path / state_id
97
+ state_dir.mkdir(exist_ok=True)
98
+
99
+ # Create versioned state file
100
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
101
+ state_file = state_dir / f"state_{timestamp}.json"
102
+
103
+ with open(state_file, 'w') as f:
104
+ json.dump(state, f)
105
+
106
+ # Update latest symlink
107
+ latest_link = state_dir / "latest.json"
108
+ if latest_link.exists():
109
+ latest_link.unlink()
110
+ latest_link.symlink_to(state_file)
111
+
112
+ return state_file
113
+
114
+ def load_component_state(self, component: str, state_id: str, version: str = "latest") -> Optional[Dict]:
115
+ """Load component state with version support"""
116
+ component_path = self.component_paths[component]
117
+ state_dir = component_path / state_id
118
+
119
+ if version == "latest":
120
+ state_file = state_dir / "latest.json"
121
+ else:
122
+ state_file = state_dir / f"state_{version}.json"
123
+
124
+ if state_file.exists():
125
+ with open(state_file) as f:
126
+ return json.load(f)
127
+
128
+ return None
129
+
130
+ def archive_vram_block(self, block_id: str):
131
+ """Move a VRAM block to archive"""
132
+ source_path = self.vram_path / "active" / f"{block_id}.npz"
133
+ target_path = self.vram_path / "archived" / f"{block_id}.npz"
134
+
135
+ if source_path.exists():
136
+ shutil.move(source_path, target_path)
137
+
138
+ # Also move metadata
139
+ source_meta = self.vram_path / "active" / f"{block_id}.meta.json"
140
+ target_meta = self.vram_path / "archived" / f"{block_id}.meta.json"
141
+ if source_meta.exists():
142
+ shutil.move(source_meta, target_meta)
143
+
144
+ def cleanup_temp_blocks(self, max_age_hours: int = 24):
145
+ """Clean up old temporary VRAM blocks"""
146
+ temp_dir = self.vram_path / "temp"
147
+ current_time = datetime.now()
148
+
149
+ for file_path in temp_dir.glob("*.npz"):
150
+ # Check corresponding metadata
151
+ meta_path = file_path.with_suffix('.meta.json')
152
+ if meta_path.exists():
153
+ with open(meta_path) as f:
154
+ metadata = json.load(f)
155
+ created = datetime.fromisoformat(metadata['created'])
156
+
157
+ # Remove if too old
158
+ if (current_time - created).total_seconds() > max_age_hours * 3600:
159
+ file_path.unlink()
160
+ meta_path.unlink()
161
+
162
+ def get_storage_stats(self) -> Dict[str, Any]:
163
+ """Get storage statistics"""
164
+ stats = {
165
+ 'vram': {
166
+ 'active_blocks': len(list(self.vram_path.glob("active/*.npz"))),
167
+ 'archived_blocks': len(list(self.vram_path.glob("archived/*.npz"))),
168
+ 'temp_blocks': len(list(self.vram_path.glob("temp/*.npz"))),
169
+ 'total_size_bytes': self._get_dir_size(self.vram_path)
170
+ },
171
+ 'state': {
172
+ 'components': {},
173
+ 'total_size_bytes': self._get_dir_size(self.state_path)
174
+ },
175
+ 'cache': {
176
+ 'size_bytes': self._get_dir_size(self.cache_path)
177
+ }
178
+ }
179
+
180
+ # Add component-specific stats
181
+ for component in self.component_paths:
182
+ stats['state']['components'][component] = {
183
+ 'states': len(list(self.component_paths[component].glob("**/state_*.json"))),
184
+ 'size_bytes': self._get_dir_size(self.component_paths[component])
185
+ }
186
+
187
+ return stats
188
+
189
+ def _get_dir_size(self, path: Path) -> int:
190
+ """Calculate total size of a directory"""
191
+ return sum(f.stat().st_size for f in path.glob('**/*') if f.is_file())
192
+
193
+ def create_snapshot(self, snapshot_id: str):
194
+ """Create a snapshot of the entire storage"""
195
+ snapshot_dir = self.base_path / "snapshots" / snapshot_id
196
+ snapshot_dir.mkdir(parents=True)
197
+
198
+ # Copy current state
199
+ shutil.copytree(self.state_path, snapshot_dir / "gpu_state")
200
+ shutil.copytree(self.vram_path / "active", snapshot_dir / "vram_blocks")
201
+
202
+ # Create snapshot metadata
203
+ metadata = {
204
+ 'created': datetime.now().isoformat(),
205
+ 'stats': self.get_storage_stats()
206
+ }
207
+ with open(snapshot_dir / "snapshot.json", 'w') as f:
208
+ json.dump(metadata, f)
209
+
210
+ def restore_snapshot(self, snapshot_id: str):
211
+ """Restore from a snapshot"""
212
+ snapshot_dir = self.base_path / "snapshots" / snapshot_id
213
+ if not snapshot_dir.exists():
214
+ raise ValueError(f"Snapshot {snapshot_id} not found")
215
+
216
+ # Clear current state
217
+ shutil.rmtree(self.state_path)
218
+ shutil.rmtree(self.vram_path / "active")
219
+
220
+ # Restore from snapshot
221
+ shutil.copytree(snapshot_dir / "gpu_state", self.state_path)
222
+ shutil.copytree(snapshot_dir / "vram_blocks", self.vram_path / "active")
websocket_test.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import websockets
3
+ import json
4
+ import numpy as np
5
+
6
+ async def test_websocket():
7
+ uri = "wss://8765-int35aifjdyxr46oxipjg-cf14c883.manusvm.computer"
8
+ async with websockets.connect(uri) as websocket:
9
+ print("Connected to websocket.")
10
+
11
+ # Test VRAM write operation
12
+ vram_data = np.random.rand(10, 10).tolist()
13
+ vram_write_message = {
14
+ "operation": "vram",
15
+ "type": "write",
16
+ "block_id": "test_block_1",
17
+ "data": vram_data
18
+ }
19
+ await websocket.send(json.dumps(vram_write_message))
20
+ response = await websocket.recv()
21
+ print(f"VRAM write response: {response}")
22
+
23
+ # Test VRAM read operation
24
+ vram_read_message = {
25
+ "operation": "vram",
26
+ "type": "read",
27
+ "block_id": "test_block_1"
28
+ }
29
+ await websocket.send(json.dumps(vram_read_message))
30
+ response = await websocket.recv()
31
+ print(f"VRAM read response: {response}")
32
+
33
+ # Test state save operation
34
+ state_data = {"gpu_temp": 65, "fan_speed": 2000}
35
+ state_save_message = {
36
+ "operation": "state",
37
+ "type": "save",
38
+ "component": "gpu_core",
39
+ "state_id": "current_state",
40
+ "data": state_data
41
+ }
42
+ await websocket.send(json.dumps(state_save_message))
43
+ response = await websocket.recv()
44
+ print(f"State save response: {response}")
45
+
46
+ # Test state load operation
47
+ state_load_message = {
48
+ "operation": "state",
49
+ "type": "load",
50
+ "component": "gpu_core",
51
+ "state_id": "current_state"
52
+ }
53
+ await websocket.send(json.dumps(state_load_message))
54
+ response = await websocket.recv()
55
+ print(f"State load response: {response}")
56
+
57
+ # Test cache set operation
58
+ cache_data = {"model_version": "v1.2", "accuracy": 0.98}
59
+ cache_set_message = {
60
+ "operation": "cache",
61
+ "type": "set",
62
+ "key": "model_info",
63
+ "data": cache_data
64
+ }
65
+ await websocket.send(json.dumps(cache_set_message))
66
+ response = await websocket.recv()
67
+ print(f"Cache set response: {response}")
68
+
69
+ # Test cache get operation
70
+ cache_get_message = {
71
+ "operation": "cache",
72
+ "type": "get",
73
+ "key": "model_info"
74
+ }
75
+ await websocket.send(json.dumps(cache_get_message))
76
+ response = await websocket.recv()
77
+ print(f"Cache get response: {response}")
78
+
79
+ asyncio.run(test_websocket())
80
+