Factor Studios commited on
Commit
ce4253e
·
verified ·
1 Parent(s): 3f45e4d

Upload 9 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 requirements file
17
+ COPY requirements.txt .
18
+
19
+ # Install Python dependencies
20
+ RUN pip install --no-cache-dir -r requirements.txt
21
+
22
+ # Copy the project code
23
+ COPY . .
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 port
33
+ EXPOSE 8765
34
+
35
+ # Set environment variable for storage path
36
+ ENV STORAGE_PATH=/app/storage
37
+
38
+ # Run the server
39
+ CMD ["python", "virtual_gpu_server/server.py"]
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
+ }
requirements.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
6
+ # WebSocket/HTTP Server Dependencies
7
+ aiosignal==1.3.1 # Async signals
8
+ async-timeout==4.0.3 # Timeouts for async operations
9
+ attrs==23.1.0 # Class builders
10
+ charset-normalizer==3.2.0 # Unicode normalization
11
+ frozenlist==1.4.0 # Immutable lists
12
+ multidict==6.0.4 # Dict with multiple values per key
13
+ yarl==1.9.2 # URL handling
14
+
15
+ # Performance & Utilities
16
+ ujson==5.8.0 # Fast JSON processing
17
+ psutil==5.9.5 # System and process monitoring
18
+ pathlib==1.0.1 # Path manipulation
server.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import websockets
3
+ import json
4
+ import os
5
+ from pathlib import Path
6
+ import uuid
7
+ import time
8
+ from typing import Dict, Any, Optional
9
+ import numpy as np
10
+ from aiohttp import web
11
+ import aiohttp
12
+ from datetime import datetime
13
+
14
+ class VirtualGPUServer:
15
+ def __init__(self):
16
+ self.base_path = Path(__file__).parent / "storage"
17
+ self.vram_path = self.base_path / "vram_blocks"
18
+ self.state_path = self.base_path / "gpu_state"
19
+ self.cache_path = self.base_path / "cache"
20
+
21
+ # Ensure all storage directories exist
22
+ self.vram_path.mkdir(parents=True, exist_ok=True)
23
+ self.state_path.mkdir(parents=True, exist_ok=True)
24
+ self.cache_path.mkdir(parents=True, exist_ok=True)
25
+
26
+ # In-memory caches for faster access
27
+ self.vram_cache: Dict[str, Any] = {}
28
+ self.state_cache: Dict[str, Any] = {}
29
+ self.memory_cache: Dict[str, Any] = {}
30
+
31
+ # Active connections and sessions
32
+ self.active_connections: Dict[str, websockets.WebSocketServerProtocol] = {}
33
+ self.active_sessions: Dict[str, Dict[str, Any]] = {}
34
+
35
+ # Performance monitoring
36
+ self.ops_counter = 0
37
+ self.start_time = time.time()
38
+
39
+ # HTTP app
40
+ self.app = web.Application()
41
+ self.app.router.add_get('/', self.handle_index)
42
+ self.app.router.add_get('/files', self.handle_files)
43
+
44
+ async def handle_vram_operation(self, operation: dict) -> dict:
45
+ """Handle VRAM read/write operations"""
46
+ op_type = operation.get('type')
47
+ block_id = operation.get('block_id')
48
+ data = operation.get('data')
49
+
50
+ if op_type == 'write':
51
+ # Generate unique file path for this block
52
+ file_path = self.vram_path / f"{block_id}.npy"
53
+ # Save data to file
54
+ np.save(file_path, np.array(data))
55
+ # Update cache
56
+ self.vram_cache[block_id] = np.array(data)
57
+ return {'status': 'success', 'message': f'Block {block_id} written'}
58
+
59
+ elif op_type == 'read':
60
+ # Try cache first
61
+ if block_id in self.vram_cache:
62
+ return {
63
+ 'status': 'success',
64
+ 'data': self.vram_cache[block_id] if isinstance(self.vram_cache[block_id], list) else self.vram_cache[block_id].tolist(),
65
+ 'source': 'cache'
66
+ }
67
+
68
+ # Load from file
69
+ file_path = self.vram_path / f"{block_id}.npy"
70
+ if file_path.exists():
71
+ data = np.load(file_path)
72
+ self.vram_cache[block_id] = np.array(data)
73
+ return {
74
+ 'status': 'success',
75
+ 'data': data.tolist(),
76
+ 'source': 'disk'
77
+ }
78
+
79
+ return {'status': 'error', 'message': 'Block not found'}
80
+
81
+ async def handle_state_operation(self, operation: dict) -> dict:
82
+ """Handle GPU state operations"""
83
+ op_type = operation.get('type')
84
+ component = operation.get('component')
85
+ state_id = operation.get('state_id')
86
+ state_data = operation.get('data')
87
+
88
+ file_path = self.state_path / component / f"{state_id}.json"
89
+
90
+ if op_type == 'save':
91
+ file_path.parent.mkdir(exist_ok=True)
92
+ with open(file_path, 'w') as f:
93
+ json.dump(state_data, f)
94
+ self.state_cache[f"{component}:{state_id}"] = state_data
95
+ return {'status': 'success', 'message': f'State {state_id} saved'}
96
+
97
+ elif op_type == 'load':
98
+ cache_key = f"{component}:{state_id}"
99
+ if cache_key in self.state_cache:
100
+ return {
101
+ 'status': 'success',
102
+ 'data': self.state_cache[cache_key],
103
+ 'source': 'cache'
104
+ }
105
+
106
+ if file_path.exists():
107
+ with open(file_path) as f:
108
+ state_data = json.load(f)
109
+ self.state_cache[cache_key] = state_data
110
+ return {
111
+ 'status': 'success',
112
+ 'data': state_data,
113
+ 'source': 'disk'
114
+ }
115
+
116
+ return {'status': 'error', 'message': 'State not found'}
117
+
118
+ async def handle_cache_operation(self, operation: dict) -> dict:
119
+ """Handle cache operations"""
120
+ op_type = operation.get('type')
121
+ key = operation.get('key')
122
+ data = operation.get('data')
123
+
124
+ if op_type == 'set':
125
+ self.memory_cache[key] = data
126
+ # Also persist to disk for recovery
127
+ file_path = self.cache_path / f"{key}.json"
128
+ with open(file_path, 'w') as f:
129
+ json.dump(data, f)
130
+ return {'status': 'success', 'message': f'Cache key {key} set'}
131
+
132
+ elif op_type == 'get':
133
+ if key in self.memory_cache:
134
+ return {
135
+ 'status': 'success',
136
+ 'data': self.memory_cache[key],
137
+ 'source': 'memory'
138
+ }
139
+
140
+ file_path = self.cache_path / f"{key}.json"
141
+ if file_path.exists():
142
+ with open(file_path) as f:
143
+ data = json.load(f)
144
+ self.memory_cache[key] = data
145
+ return {
146
+ 'status': 'success',
147
+ 'data': data,
148
+ 'source': 'disk'
149
+ }
150
+
151
+ return {'status': 'error', 'message': 'Cache key not found'}
152
+
153
+ async def handle_connection(self, websocket: websockets.WebSocketServerProtocol):
154
+ """Handle incoming WebSocket connections"""
155
+ # Generate unique session ID
156
+ session_id = str(uuid.uuid4())
157
+ self.active_connections[session_id] = websocket
158
+ self.active_sessions[session_id] = {
159
+ 'start_time': time.time(),
160
+ 'ops_count': 0
161
+ }
162
+
163
+ try:
164
+ async for message in websocket:
165
+ # Parse incoming message
166
+ try:
167
+ data = json.loads(message)
168
+ except json.JSONDecodeError:
169
+ await websocket.send(json.dumps({
170
+ 'status': 'error',
171
+ 'message': 'Invalid JSON'
172
+ }))
173
+ continue
174
+
175
+ # Route operation to appropriate handler
176
+ operation_type = data.get('operation')
177
+ if operation_type == 'vram':
178
+ response = await self.handle_vram_operation(data)
179
+ elif operation_type == 'state':
180
+ response = await self.handle_state_operation(data)
181
+ elif operation_type == 'cache':
182
+ response = await self.handle_cache_operation(data)
183
+ else:
184
+ response = {
185
+ 'status': 'error',
186
+ 'message': 'Unknown operation type'
187
+ }
188
+
189
+ # Update statistics
190
+ self.ops_counter += 1
191
+ self.active_sessions[session_id]['ops_count'] += 1
192
+
193
+ # Send response
194
+ await websocket.send(json.dumps(response))
195
+
196
+ except websockets.exceptions.ConnectionClosed:
197
+ pass
198
+ finally:
199
+ # Cleanup on disconnect
200
+ del self.active_connections[session_id]
201
+ del self.active_sessions[session_id]
202
+
203
+ def get_stats(self) -> dict:
204
+ """Get server statistics"""
205
+ current_time = time.time()
206
+ uptime = current_time - self.start_time
207
+ ops_per_second = self.ops_counter / uptime if uptime > 0 else 0
208
+
209
+ return {
210
+ 'uptime': uptime,
211
+ 'total_operations': self.ops_counter,
212
+ 'ops_per_second': ops_per_second,
213
+ 'active_connections': len(self.active_connections),
214
+ 'vram_cache_size': len(self.vram_cache),
215
+ 'state_cache_size': len(self.state_cache),
216
+ 'memory_cache_size': len(self.memory_cache)
217
+ }
218
+
219
+ async def handle_index(self, request):
220
+ """Handle HTTP index request"""
221
+ stats = self.get_stats()
222
+ html = f"""
223
+ <!DOCTYPE html>
224
+ <html>
225
+ <head>
226
+ <title>Virtual GPU Server</title>
227
+ <style>
228
+ body {{ font-family: Arial, sans-serif; margin: 40px; }}
229
+ table {{ border-collapse: collapse; width: 100%; margin-top: 20px; }}
230
+ th, td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }}
231
+ th {{ background-color: #f2f2f2; }}
232
+ .stats {{ background-color: #f9f9f9; padding: 20px; border-radius: 5px; }}
233
+ </style>
234
+ </head>
235
+ <body>
236
+ <h1>Virtual GPU Server Status</h1>
237
+ <div class="stats">
238
+ <h2>Server Statistics</h2>
239
+ <ul>
240
+ <li>Uptime: {stats['uptime']:.2f} seconds</li>
241
+ <li>Total Operations: {stats['total_operations']}</li>
242
+ <li>Operations per Second: {stats['ops_per_second']:.2f}</li>
243
+ <li>Active Connections: {stats['active_connections']}</li>
244
+ <li>VRAM Cache Size: {stats['vram_cache_size']}</li>
245
+ <li>State Cache Size: {stats['state_cache_size']}</li>
246
+ <li>Memory Cache Size: {stats['memory_cache_size']}</li>
247
+ </ul>
248
+ </div>
249
+ <h2>Server Files</h2>
250
+ <iframe src="/files" style="width: 100%; height: 500px; border: none;"></iframe>
251
+ </body>
252
+ </html>
253
+ """
254
+ return web.Response(text=html, content_type='text/html')
255
+
256
+ async def handle_files(self, request):
257
+ """Handle HTTP files listing request"""
258
+ def format_size(size):
259
+ for unit in ['B', 'KB', 'MB', 'GB']:
260
+ if size < 1024:
261
+ return f"{size:.2f} {unit}"
262
+ size /= 1024
263
+ return f"{size:.2f} TB"
264
+
265
+ html = ['<!DOCTYPE html><html><head>',
266
+ '<style>',
267
+ 'body { font-family: Arial, sans-serif; margin: 20px; }',
268
+ 'table { border-collapse: collapse; width: 100%; }',
269
+ 'th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }',
270
+ 'th { background-color: #f2f2f2; }',
271
+ '</style></head><body>',
272
+ '<h2>Server Files</h2>',
273
+ '<table><tr><th>Path</th><th>Size</th><th>Last Modified</th></tr>']
274
+
275
+ for root, _, files in os.walk(self.base_path):
276
+ for file in files:
277
+ full_path = Path(root) / file
278
+ rel_path = full_path.relative_to(self.base_path)
279
+ size = format_size(os.path.getsize(full_path))
280
+ mtime = datetime.fromtimestamp(os.path.getmtime(full_path))
281
+ html.append(f'<tr><td>{rel_path}</td><td>{size}</td><td>{mtime}</td></tr>')
282
+
283
+ html.extend(['</table></body></html>'])
284
+ return web.Response(text='\n'.join(html), content_type='text/html')
285
+
286
+ async def main():
287
+ server = VirtualGPUServer()
288
+
289
+ # Start WebSocket server
290
+ websocket_server = await websockets.serve(server.handle_connection, "0.0.0.0", 8765)
291
+
292
+ # Start HTTP server
293
+ runner = web.AppRunner(server.app)
294
+ await runner.setup()
295
+ site = web.TCPSite(runner, '0.0.0.0', 8080)
296
+ await site.start()
297
+
298
+ print("Virtual GPU Server running:")
299
+ print("- WebSocket: ws://localhost:8765")
300
+ print("- HTTP Interface: http://localhost:8080")
301
+
302
+ # Run forever
303
+ await asyncio.Future()
304
+
305
+ if __name__ == "__main__":
306
+ asyncio.run(main())
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_block_1.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a5f8356bd5b0ba51ac0da5009031c0f129f899f2878d7ce57d66af5ab9abc40b
3
+ size 928
storage_manager.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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"""
32
+ # Create main directories
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
42
+ for subdir in ['active', 'archived', 'temp']:
43
+ (self.vram_path / subdir).mkdir(exist_ok=True)
44
+
45
+ def store_vram_block(self, block_id: str, data: np.ndarray, temp: bool = False) -> Path:
46
+ """Store a VRAM block with metadata"""
47
+ # Determine storage location
48
+ if temp:
49
+ target_dir = self.vram_path / "temp"
50
+ else:
51
+ target_dir = self.vram_path / "active"
52
+
53
+ file_path = target_dir / f"{block_id}.npz"
54
+ metadata_path = target_dir / f"{block_id}.meta.json"
55
+
56
+ # Save data and metadata
57
+ np.savez_compressed(file_path, data=data)
58
+ metadata = {
59
+ 'created': datetime.now().isoformat(),
60
+ 'shape': data.shape,
61
+ 'dtype': str(data.dtype),
62
+ 'size_bytes': data.nbytes
63
+ }
64
+ with open(metadata_path, 'w') as f:
65
+ json.dump(metadata, f)
66
+
67
+ return file_path
68
+
69
+ def load_vram_block(self, block_id: str) -> Optional[np.ndarray]:
70
+ """Load a VRAM block with fallback to archived"""
71
+ # Check active blocks first
72
+ active_path = self.vram_path / "active" / f"{block_id}.npz"
73
+ if active_path.exists():
74
+ return np.load(active_path)['data']
75
+
76
+ # Check archived blocks
77
+ archived_path = self.vram_path / "archived" / f"{block_id}.npz"
78
+ if archived_path.exists():
79
+ data = np.load(archived_path)['data']
80
+ # Move back to active
81
+ self.store_vram_block(block_id, data)
82
+ return data
83
+
84
+ return None
85
+
86
+ def store_component_state(self, component: str, state_id: str, state: Dict) -> Path:
87
+ """Store component state with versioning"""
88
+ component_path = self.component_paths[component]
89
+ state_dir = component_path / state_id
90
+ state_dir.mkdir(exist_ok=True)
91
+
92
+ # Create versioned state file
93
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
94
+ state_file = state_dir / f"state_{timestamp}.json"
95
+
96
+ with open(state_file, 'w') as f:
97
+ json.dump(state, f)
98
+
99
+ # Update latest symlink
100
+ latest_link = state_dir / "latest.json"
101
+ if latest_link.exists():
102
+ latest_link.unlink()
103
+ latest_link.symlink_to(state_file)
104
+
105
+ return state_file
106
+
107
+ def load_component_state(self, component: str, state_id: str, version: str = "latest") -> Optional[Dict]:
108
+ """Load component state with version support"""
109
+ component_path = self.component_paths[component]
110
+ state_dir = component_path / state_id
111
+
112
+ if version == "latest":
113
+ state_file = state_dir / "latest.json"
114
+ else:
115
+ state_file = state_dir / f"state_{version}.json"
116
+
117
+ if state_file.exists():
118
+ with open(state_file) as f:
119
+ return json.load(f)
120
+
121
+ return None
122
+
123
+ def archive_vram_block(self, block_id: str):
124
+ """Move a VRAM block to archive"""
125
+ source_path = self.vram_path / "active" / f"{block_id}.npz"
126
+ target_path = self.vram_path / "archived" / f"{block_id}.npz"
127
+
128
+ if source_path.exists():
129
+ shutil.move(source_path, target_path)
130
+
131
+ # Also move metadata
132
+ source_meta = self.vram_path / "active" / f"{block_id}.meta.json"
133
+ target_meta = self.vram_path / "archived" / f"{block_id}.meta.json"
134
+ if source_meta.exists():
135
+ shutil.move(source_meta, target_meta)
136
+
137
+ def cleanup_temp_blocks(self, max_age_hours: int = 24):
138
+ """Clean up old temporary VRAM blocks"""
139
+ temp_dir = self.vram_path / "temp"
140
+ current_time = datetime.now()
141
+
142
+ for file_path in temp_dir.glob("*.npz"):
143
+ # Check corresponding metadata
144
+ meta_path = file_path.with_suffix('.meta.json')
145
+ if meta_path.exists():
146
+ with open(meta_path) as f:
147
+ metadata = json.load(f)
148
+ created = datetime.fromisoformat(metadata['created'])
149
+
150
+ # Remove if too old
151
+ if (current_time - created).total_seconds() > max_age_hours * 3600:
152
+ file_path.unlink()
153
+ meta_path.unlink()
154
+
155
+ def get_storage_stats(self) -> Dict[str, Any]:
156
+ """Get storage statistics"""
157
+ stats = {
158
+ 'vram': {
159
+ 'active_blocks': len(list(self.vram_path.glob("active/*.npz"))),
160
+ 'archived_blocks': len(list(self.vram_path.glob("archived/*.npz"))),
161
+ 'temp_blocks': len(list(self.vram_path.glob("temp/*.npz"))),
162
+ 'total_size_bytes': self._get_dir_size(self.vram_path)
163
+ },
164
+ 'state': {
165
+ 'components': {},
166
+ 'total_size_bytes': self._get_dir_size(self.state_path)
167
+ },
168
+ 'cache': {
169
+ 'size_bytes': self._get_dir_size(self.cache_path)
170
+ }
171
+ }
172
+
173
+ # Add component-specific stats
174
+ for component in self.component_paths:
175
+ stats['state']['components'][component] = {
176
+ 'states': len(list(self.component_paths[component].glob("**/state_*.json"))),
177
+ 'size_bytes': self._get_dir_size(self.component_paths[component])
178
+ }
179
+
180
+ return stats
181
+
182
+ def _get_dir_size(self, path: Path) -> int:
183
+ """Calculate total size of a directory"""
184
+ return sum(f.stat().st_size for f in path.glob('**/*') if f.is_file())
185
+
186
+ def create_snapshot(self, snapshot_id: str):
187
+ """Create a snapshot of the entire storage"""
188
+ snapshot_dir = self.base_path / "snapshots" / snapshot_id
189
+ snapshot_dir.mkdir(parents=True)
190
+
191
+ # Copy current state
192
+ shutil.copytree(self.state_path, snapshot_dir / "gpu_state")
193
+ shutil.copytree(self.vram_path / "active", snapshot_dir / "vram_blocks")
194
+
195
+ # Create snapshot metadata
196
+ metadata = {
197
+ 'created': datetime.now().isoformat(),
198
+ 'stats': self.get_storage_stats()
199
+ }
200
+ with open(snapshot_dir / "snapshot.json", 'w') as f:
201
+ json.dump(metadata, f)
202
+
203
+ def restore_snapshot(self, snapshot_id: str):
204
+ """Restore from a snapshot"""
205
+ snapshot_dir = self.base_path / "snapshots" / snapshot_id
206
+ if not snapshot_dir.exists():
207
+ raise ValueError(f"Snapshot {snapshot_id} not found")
208
+
209
+ # Clear current state
210
+ shutil.rmtree(self.state_path)
211
+ shutil.rmtree(self.vram_path / "active")
212
+
213
+ # Restore from snapshot
214
+ shutil.copytree(snapshot_dir / "gpu_state", self.state_path)
215
+ 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
+