tds-core 0.2.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.
tds/__init__.py ADDED
@@ -0,0 +1,34 @@
1
+ """太极调度层 TDS —— 大模型权重-显存动态调度中间层。
2
+
3
+ SDK 入口
4
+ --------
5
+ from tds import TDSRuntime
6
+
7
+ runtime = TDSRuntime()
8
+ runtime.register_adapter(MyAdapter())
9
+ runtime.attach() # 挂载
10
+ result = runtime.run_task("用户输入")
11
+ runtime.detach() # 卸载
12
+ """
13
+ __version__ = "0.1.0"
14
+ __author__ = "BY LAOMENG 网络工作室"
15
+
16
+ from .config import TDSConfig, BAGUA_DOMAINS
17
+ from .api import (
18
+ TDSRuntime,
19
+ RuntimeState,
20
+ AttachResult,
21
+ DetachResult,
22
+ BenchmarkResult,
23
+ )
24
+
25
+ __all__ = [
26
+ "TDSConfig",
27
+ "BAGUA_DOMAINS",
28
+ "__version__",
29
+ "TDSRuntime",
30
+ "RuntimeState",
31
+ "AttachResult",
32
+ "DetachResult",
33
+ "BenchmarkResult",
34
+ ]
tds/api.py ADDED
@@ -0,0 +1,548 @@
1
+ """SDK 挂载/卸载入口层 —— 宿主无关的调度中间层 API。
2
+
3
+ 定位
4
+ ----
5
+ 本模块是 TDS SDK 面向宿主的唯一入口。宿主通过 TDSRuntime 完成三件事:
6
+
7
+ 1. 注册适配器(扫描/加载/卸载/显存快照);
8
+ 2. 挂载(attach)—— 将宿主当前上下文(模型、显存状态等)接入调度链路;
9
+ 3. 卸载(detach)—— 断开调度链路,释放 TDS 占用的资源,宿主继续独立运行。
10
+
11
+ 挂载/卸载的设计要点:
12
+ - **唯一入口**:所有操作通过 TDSRuntime 一个对象完成,无全局 state。
13
+ - **幂等安全**:attach/detach 可多次调用,内部做状态保护。
14
+ - **宿主解耦**:SDK 不依赖任何宿主类名硬编码,宿主只需实现 BaseAdapter 接口。
15
+ - **热插拔**:挂载/卸载不重启宿主,调度状态(分类器、计划器、存储层)保留,
16
+ 仅断开外部适配器的调度驱动。
17
+
18
+ 设计哲学
19
+ --------
20
+ 挂载(attach)= 让 TDS 接管调度决策,adapter 的 load/unload/prefetch 被调度器驱动;
21
+ 卸载(detach)= 让宿主恢复自主调度,adapter 直接服务于宿主自身框架,不再受 TDS 驱动。
22
+
23
+ 宿主对接收敛:宿主把自身的适配器实现注册到 TDSRuntime,SDK 内部不引用
24
+ 宿主任何类名、模块名或版本信息,仅通过 BaseAdapter 抽象层交互。
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import threading
29
+ import time
30
+ from dataclasses import dataclass, field
31
+ from typing import Any, Dict, List, Optional, Sequence
32
+
33
+ from .core.scheduler import Scheduler
34
+ from .core.memory import VramState
35
+ from .config import TDSConfig, BAGUA_DOMAINS
36
+ from .core.classifier import BaguaClassifier
37
+
38
+
39
+ # --------------------------------------------------------------------------
40
+ # 运行时状态
41
+ # --------------------------------------------------------------------------
42
+
43
+ class RuntimeState:
44
+ """SDK 运行时状态机。"""
45
+ INIT = "init" # 初始化,未挂载
46
+ ATTACHED = "attached" # 已挂载,调度器接管
47
+ DETACHED = "detached" # 已卸载,适配器独立
48
+
49
+ ALL = [INIT, ATTACHED, DETACHED]
50
+
51
+
52
+ @dataclass
53
+ class AttachResult:
54
+ """attach() 返回结果。"""
55
+ success: bool = True
56
+ adapter_name: str = ""
57
+ vram_before: Optional[Dict[str, Any]] = None
58
+ vram_after: Optional[Dict[str, Any]] = None
59
+ message: str = ""
60
+
61
+
62
+ @dataclass
63
+ class DetachResult:
64
+ """detach() 返回结果。"""
65
+ success: bool = True
66
+ adapters_detached: int = 0
67
+ message: str = ""
68
+
69
+
70
+ @dataclass
71
+ class BenchmarkResult:
72
+ """基准测试返回结果。"""
73
+ name: str = ""
74
+ mode: str = "" # single | concurrent
75
+ duration_ms: float = 0.0
76
+ tasks_completed: int = 0
77
+ tasks_failed: int = 0
78
+ avg_latency_ms: float = 0.0
79
+ avg_tps: float = 0.0
80
+ peak_vram_mb: float = 0.0
81
+ min_vram_mb: float = 0.0
82
+ details: List[Dict[str, Any]] = field(default_factory=list)
83
+
84
+
85
+ # --------------------------------------------------------------------------
86
+ # TDSRuntime — 唯一入口
87
+ # --------------------------------------------------------------------------
88
+
89
+ class TDSRuntime:
90
+ """SDK 挂载/卸载运行时。
91
+
92
+ 使用方式
93
+ --------
94
+ 1. 创建:runtime = TDSRuntime()
95
+ 2. 注册适配器:runtime.register_adapter(MyAdapter())
96
+ 3. 挂载:runtime.attach()
97
+ 4. 执行调度:result = runtime.run_task("用户输入文本")
98
+ 5. 卸载:runtime.detach()
99
+
100
+ 参数
101
+ ----
102
+ config: TDSConfig, 可选,SDK 配置,默认 TDSConfig 实例
103
+ """
104
+
105
+ def __init__(self, config: Optional[TDSConfig] = None):
106
+ self.cfg = config or TDSConfig()
107
+ self.scheduler: Optional[Scheduler] = None
108
+ self._adapters: Dict[str, Any] = {}
109
+ self._state = RuntimeState.INIT
110
+ self._lock = threading.RLock()
111
+ # 显存账本:最近一次调度后的 vram 快照(成功/异常路径均回填,问题6)
112
+ self.last_vram: Optional[Dict[str, Any]] = None
113
+
114
+ @property
115
+ def state(self) -> str:
116
+ return self._state
117
+
118
+ def is_attached(self) -> bool:
119
+ return self._state == RuntimeState.ATTACHED
120
+
121
+ def is_detached(self) -> bool:
122
+ return self._state == RuntimeState.DETACHED
123
+
124
+ # ---- 适配器管理 ----
125
+
126
+ def register_adapter(self, adapter: Any, name: str = "default") -> bool:
127
+ """注册宿主适配器。
128
+
129
+ 参数
130
+ ----
131
+ adapter: 实现 BaseAdapter 接口的适配器实例
132
+ name: 适配器名称(支持多适配器注册)
133
+
134
+ 返回
135
+ ----
136
+ bool: 注册成功为 True
137
+
138
+ 注意
139
+ ----
140
+ - 适配器是宿主的实现,SDK 内部不引用宿主类名
141
+ - 同一 name 注册会被覆盖
142
+ """
143
+ if not hasattr(adapter, "scan_usage"):
144
+ raise ValueError("适配器必须实现 scan_usage 方法")
145
+ if not hasattr(adapter, "load"):
146
+ raise ValueError("适配器必须实现 load 方法")
147
+ if not hasattr(adapter, "unload"):
148
+ raise ValueError("适配器必须实现 unload 方法")
149
+ if not hasattr(adapter, "prefetch"):
150
+ raise ValueError("适配器必须实现 prefetch 方法")
151
+ if not hasattr(adapter, "vram_state"):
152
+ raise ValueError("适配器必须实现 vram_state 方法")
153
+
154
+ with self._lock:
155
+ self._adapters[name] = adapter
156
+
157
+ return True
158
+
159
+ def get_adapter(self, name: str = "default") -> Optional[Any]:
160
+ """获取已注册的适配器。"""
161
+ return self._adapters.get(name)
162
+
163
+ def list_adapters(self) -> List[str]:
164
+ """列出所有已注册的适配器名称。"""
165
+ return list(self._adapters.keys())
166
+
167
+ # ---- 挂载 / 卸载 ----
168
+
169
+ def attach(self, adapter_name: str = "default") -> AttachResult:
170
+ """挂载 SDK —— 将适配器接入调度链路。
171
+
172
+ 挂载后,调度器会接管 adapter 的 load/unload/prefetch 调用,
173
+ 宿主无需直接调用适配器方法。
174
+
175
+ 参数
176
+ ----
177
+ adapter_name: 要挂载的适配器名称
178
+
179
+ 返回
180
+ ----
181
+ AttachResult: 挂载结果
182
+
183
+ 异常
184
+ ----
185
+ RuntimeError: 适配器未注册或 SDK 已挂载
186
+ """
187
+ with self._lock:
188
+ if adapter_name not in self._adapters:
189
+ raise RuntimeError(f"适配器未注册: {adapter_name}")
190
+
191
+ if self._state == RuntimeState.ATTACHED:
192
+ return AttachResult(
193
+ success=False,
194
+ message=f"SDK 已挂载,无需重复挂载"
195
+ )
196
+
197
+ adapter = self._adapters[adapter_name]
198
+ vram_before = self._capture_vram(adapter)
199
+
200
+ # 初始化调度器并绑定适配器
201
+ self.scheduler = Scheduler(config=self.cfg, adapter=adapter)
202
+
203
+ # 标记挂载完成
204
+ self._state = RuntimeState.ATTACHED
205
+
206
+ vram_after = self._capture_vram(adapter)
207
+
208
+ return AttachResult(
209
+ success=True,
210
+ adapter_name=adapter_name,
211
+ vram_before=vram_before,
212
+ vram_after=vram_after,
213
+ message=f"SDK 挂载成功,adapter={adapter_name}"
214
+ )
215
+
216
+ def detach(self) -> DetachResult:
217
+ """卸载 SDK —— 断开调度链路,释放 TDS 资源。
218
+
219
+ 卸载后,适配器恢复到独立运行状态,宿主框架直接管理调度。
220
+ TDS 内部状态(分类器、计划器)保留,可随时重新挂载。
221
+
222
+ 返回
223
+ ----
224
+ DetachResult: 卸载结果
225
+
226
+ 异常
227
+ ----
228
+ RuntimeError: SDK 未挂载
229
+ """
230
+ with self._lock:
231
+ if self._state == RuntimeState.DETACHED:
232
+ return DetachResult(
233
+ success=False,
234
+ message="SDK 已卸载,无需重复卸载"
235
+ )
236
+
237
+ if self._state != RuntimeState.ATTACHED or self.scheduler is None:
238
+ raise RuntimeError("SDK 未挂载,无法卸载")
239
+
240
+ # 获取调度器关联的适配器
241
+ scheduler_adapter = self.scheduler.adapter
242
+ scheduler_adapter_name = None
243
+ for name, adapter in self._adapters.items():
244
+ if adapter is scheduler_adapter:
245
+ scheduler_adapter_name = name
246
+ break
247
+
248
+ # 断开调度器(adapter 仍保留在 _adapters 中供后续重新挂载)
249
+ self.scheduler.adapter = None
250
+ self.scheduler = None
251
+ self._state = RuntimeState.DETACHED
252
+
253
+ return DetachResult(
254
+ success=True,
255
+ adapters_detached=1,
256
+ message=f"SDK 卸载成功"
257
+ )
258
+
259
+ # ---- 调度入口 ----
260
+
261
+ def run_task(self, task_desc: str, graph=None, blocks=None) -> Dict[str, Any]:
262
+ """执行调度任务。
263
+
264
+ 挂载后调用,由调度器自动驱动适配器完成 load/unload/prefetch。
265
+
266
+ 参数
267
+ ----
268
+ task_desc: 任务描述(文本,用于语义分类)
269
+ graph: 执行图(可选)。传入时调度器先经 adapter.scan_usage(graph)
270
+ 扫描出块序列并登记,再据此生成调度计划 —— 这是 scan 结果
271
+ 真实驱动 adapter.load/unload 的闭环接线。
272
+ blocks: 可选,已构造的 Block 列表(与 graph 二选一,优先级更高)
273
+
274
+ 返回
275
+ ----
276
+ dict: 调度结果,包含 step、primary、scores、pressure、plan、metrics 等
277
+
278
+ 异常
279
+ ----
280
+ RuntimeError: SDK 未挂载
281
+ """
282
+ with self._lock:
283
+ if self._state != RuntimeState.ATTACHED or self.scheduler is None:
284
+ raise RuntimeError("SDK 未挂载,请先调用 attach()")
285
+
286
+ try:
287
+ result = self.scheduler.run_task(task_desc, blocks=blocks, graph=graph)
288
+ except Exception:
289
+ # 问题6:异常路径同样回填显存账本快照,避免账本停留在
290
+ # 上一次成功值(外部 catch 后据 last_vram 判断水位会失真)。
291
+ self.last_vram = self._capture_vram(self.scheduler.adapter)
292
+ raise
293
+ self.last_vram = self._capture_vram(self.scheduler.adapter)
294
+ return result
295
+
296
+ # ---- 性能基准测试 ----
297
+
298
+ def run_benchmark(self, test_name: str = "default", repeat: int = 3,
299
+ concurrent_tasks: int = 1) -> BenchmarkResult:
300
+ """运行性能基准测试。
301
+
302
+ 测试类型:
303
+ - single: 单流测试,逐个任务串行执行
304
+ - concurrent: 并发测试,同时执行 N 个任务
305
+
306
+ 参数
307
+ ----
308
+ test_name: 测试名称
309
+ repeat: 测试重复次数
310
+ concurrent_tasks: 并发任务数(concurrent 模式下)
311
+
312
+ 返回
313
+ ----
314
+ BenchmarkResult: 测试结果
315
+
316
+ 异常
317
+ ----
318
+ RuntimeError: SDK 未挂载
319
+ """
320
+ with self._lock:
321
+ if self._state != RuntimeState.ATTACHED or self.scheduler is None:
322
+ raise RuntimeError("SDK 未挂载,请先调用 attach()")
323
+
324
+ adapter = self.scheduler.adapter
325
+ results: List[Dict[str, Any]] = []
326
+ durations = []
327
+ completed = 0
328
+ failed = 0
329
+ peak_vram = 0.0
330
+ min_vram = float('inf')
331
+
332
+ if concurrent_tasks > 1:
333
+ # 并发模式
334
+ for i in range(repeat):
335
+ start_time = time.perf_counter()
336
+ concurrent_results = []
337
+
338
+ for j in range(concurrent_tasks):
339
+ try:
340
+ # 每个并发任务使用不同的描述以模拟真实负载
341
+ task_desc = f"并发任务 {j+1}/{concurrent_tasks} 在测试 {i+1}/{repeat}"
342
+ result = self.scheduler.run_task(task_desc)
343
+ concurrent_results.append(result)
344
+ except Exception as e:
345
+ concurrent_results.append({"error": str(e)})
346
+ failed += 1
347
+
348
+ # 记录显存
349
+ try:
350
+ vram = adapter.vram_state()
351
+ if vram:
352
+ usage = vram.used_mb
353
+ peak_vram = max(peak_vram, usage)
354
+ min_vram = min(min_vram, usage)
355
+ except:
356
+ pass
357
+
358
+ end_time = time.perf_counter()
359
+ duration = (end_time - start_time) * 1000.0
360
+ durations.append(duration)
361
+ completed += len(concurrent_results)
362
+
363
+ results.append({
364
+ "repeat": i + 1,
365
+ "concurrent_tasks": concurrent_tasks,
366
+ "duration_ms": duration,
367
+ "completed": len(concurrent_results),
368
+ "failed": sum(1 for r in concurrent_results if "error" in r)
369
+ })
370
+ else:
371
+ # 单流模式
372
+ for i in range(repeat):
373
+ start_time = time.perf_counter()
374
+ try:
375
+ result = self.scheduler.run_task(f"基准测试单流任务 {i+1}/{repeat}")
376
+ completed += 1
377
+ except Exception as e:
378
+ failed += 1
379
+ results.append({"error": str(e)})
380
+
381
+ end_time = time.perf_counter()
382
+ duration = (end_time - start_time) * 1000.0
383
+ durations.append(duration)
384
+
385
+ # 记录显存
386
+ try:
387
+ vram = adapter.vram_state()
388
+ if vram:
389
+ usage = vram.used_mb
390
+ peak_vram = max(peak_vram, usage)
391
+ min_vram = min(min_vram, usage)
392
+ except:
393
+ pass
394
+
395
+ results.append({
396
+ "repeat": i + 1,
397
+ "duration_ms": duration,
398
+ "completed": 1,
399
+ "failed": 0 if "error" not in str(result) else 1
400
+ })
401
+
402
+ avg_duration = sum(durations) / len(durations) if durations else 0.0
403
+ avg_tps = completed / (sum(durations) / 1000.0) if durations and sum(durations) > 0 else 0.0
404
+
405
+ if min_vram == float('inf'):
406
+ min_vram = 0.0
407
+
408
+ return BenchmarkResult(
409
+ name=test_name,
410
+ mode="concurrent" if concurrent_tasks > 1 else "single",
411
+ duration_ms=sum(durations),
412
+ tasks_completed=completed,
413
+ tasks_failed=failed,
414
+ avg_latency_ms=avg_duration,
415
+ avg_tps=avg_tps,
416
+ peak_vram_mb=peak_vram,
417
+ min_vram_mb=min_vram,
418
+ details=results
419
+ )
420
+
421
+ def attach_detach_benchmark(self, test_name: str = "attach_detach",
422
+ iterations: int = 5) -> BenchmarkResult:
423
+ """挂载/卸载性能基准测试。
424
+
425
+ 测试挂载/卸载操作的开销,验证热插拔性能。
426
+
427
+ 参数
428
+ ----
429
+ test_name: 测试名称
430
+ iterations: 测试迭代次数
431
+
432
+ 返回
433
+ ----
434
+ BenchmarkResult: 测试结果
435
+ """
436
+ if self._state != RuntimeState.INIT:
437
+ raise RuntimeError("SDK 必须处于 INIT 状态才能运行挂载/卸载测试")
438
+
439
+ if not self._adapters:
440
+ raise RuntimeError("没有注册适配器,无法运行挂载/卸载测试")
441
+
442
+ adapter_name = list(self._adapters.keys())[0]
443
+ results: List[Dict[str, Any]] = []
444
+ attach_durations = []
445
+ detach_durations = []
446
+
447
+ for i in range(iterations):
448
+ # 挂载
449
+ start_attach = time.perf_counter()
450
+ try:
451
+ attach_result = self.attach(adapter_name)
452
+ attach_duration = (time.perf_counter() - start_attach) * 1000.0
453
+ attach_durations.append(attach_duration)
454
+ except Exception as e:
455
+ attach_duration = (time.perf_counter() - start_attach) * 1000.0
456
+ attach_durations.append(attach_duration)
457
+ results.append({
458
+ "iteration": i + 1,
459
+ "phase": "attach",
460
+ "duration_ms": attach_duration,
461
+ "success": False,
462
+ "error": str(e)
463
+ })
464
+ continue
465
+
466
+ # 卸载
467
+ start_detach = time.perf_counter()
468
+ try:
469
+ detach_result = self.detach()
470
+ detach_duration = (time.perf_counter() - start_detach) * 1000.0
471
+ detach_durations.append(detach_duration)
472
+ except Exception as e:
473
+ detach_duration = (time.perf_counter() - start_detach) * 1000.0
474
+ detach_durations.append(detach_duration)
475
+ results.append({
476
+ "iteration": i + 1,
477
+ "phase": "detach",
478
+ "duration_ms": detach_duration,
479
+ "success": False,
480
+ "error": str(e)
481
+ })
482
+
483
+ results.append({
484
+ "iteration": i + 1,
485
+ "phase": "complete",
486
+ "attach_duration_ms": attach_durations[-1],
487
+ "detach_duration_ms": detach_durations[-1] if detach_durations else 0,
488
+ "success": True
489
+ })
490
+
491
+ avg_attach = sum(attach_durations) / len(attach_durations) if attach_durations else 0.0
492
+ avg_detach = sum(detach_durations) / len(detach_durations) if detach_durations else 0.0
493
+ total_duration = sum(attach_durations) + sum(detach_durations)
494
+
495
+ return BenchmarkResult(
496
+ name=test_name,
497
+ mode="attach_detach",
498
+ duration_ms=total_duration,
499
+ tasks_completed=iterations,
500
+ tasks_failed=0,
501
+ avg_latency_ms=(avg_attach + avg_detach),
502
+ avg_tps=iterations / (total_duration / 1000.0) if total_duration > 0 else 0.0,
503
+ peak_vram_mb=0.0,
504
+ min_vram_mb=0.0,
505
+ details=results,
506
+ # 挂载/卸载测试额外字段
507
+ avg_attach_ms=avg_attach,
508
+ avg_detach_ms=avg_detach
509
+ )
510
+
511
+ # ---- 内部方法 ----
512
+
513
+ def _capture_vram(self, adapter: Any) -> Optional[Dict[str, Any]]:
514
+ """捕获当前显存状态。"""
515
+ try:
516
+ state = adapter.vram_state()
517
+ if state:
518
+ return {
519
+ "total_mb": state.total_mb,
520
+ "used_mb": state.used_mb,
521
+ "free_mb": state.free_mb,
522
+ "usage_mb": state.used_mb,
523
+ "usage_ratio": state.usage_ratio
524
+ }
525
+ except Exception:
526
+ pass
527
+ return None
528
+
529
+ def reset(self):
530
+ """重置 SDK 运行时到初始状态。"""
531
+ with self._lock:
532
+ self.scheduler = None
533
+ self._adapters.clear()
534
+ self._state = RuntimeState.INIT
535
+
536
+ def __repr__(self):
537
+ return (
538
+ f"TDSRuntime(state={self._state}, "
539
+ f"adapters={len(self._adapters)}, "
540
+ f"version={__version__})"
541
+ )
542
+
543
+
544
+ # ---- 版本信息 ----
545
+ __version__ = "0.1.0"
546
+ __author__ = "BY LAOMENG 网络工作室"
547
+ __all__ = ["TDSRuntime", "RuntimeState", "AttachResult", "DetachResult",
548
+ "BenchmarkResult"]