File size: 2,366 Bytes
63ca2a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
"""
Paged Video Latent 内存池与连续批处理引擎 (vLLM Style)
Author: XiaoZhe (Commercial Contact: janejulius119@gmail.com / WeChat: julius119)
"""

import torch
import logging
from typing import Dict, List

logger = logging.getLogger("VerseFlow.PagedLatentPool")

class LatentBlock:
    def __init__(self, block_id: int, block_size: int, num_channels: int, height: int, width: int, dtype=torch.float16):
        self.block_id = block_id
        self.ref_count = 0
        self.data = torch.empty((block_size, num_channels, height, width), dtype=dtype, device="cuda")

class PagedVideoLatentMemoryPool:
    """视频扩散模型 Paged Latent 显存池,消除显存碎片"""
    def __init__(self, total_blocks: int = 1024, block_size: int = 16, channels: int = 4, height: int = 64, width: int = 64):
        self.block_size = block_size
        self.free_blocks: List[LatentBlock] = [
            LatentBlock(i, block_size, channels, height, width) for i in range(total_blocks)
        ]
        self.allocated_blocks: Dict[int, LatentBlock] = {}
        self.block_table: Dict[str, List[int]] = {}

    def allocate(self, sequence_id: str, num_frames: int) -> List[int]:
        num_blocks_needed = (num_frames + self.block_size - 1) // self.block_size
        if len(self.free_blocks) < num_blocks_needed:
            raise RuntimeError(f"Paged 显存池开销溢出: 需要 {num_blocks_needed} 页,剩余 {len(self.free_blocks)} 页")

        allocated_ids = []
        for _ in range(num_blocks_needed):
            block = self.free_blocks.pop()
            block.ref_count = 1
            self.allocated_blocks[block.block_id] = block
            allocated_ids.append(block.block_id)

        self.block_table[sequence_id] = allocated_ids
        logger.info(f"🧠 [PagedLatent] 序列 {sequence_id} 成功分配 {num_blocks_needed} 个 Block 页")
        return allocated_ids

    def free_sequence(self, sequence_id: str):
        if sequence_id not in self.block_table:
            return

        for block_id in self.block_table[sequence_id]:
            block = self.allocated_blocks.pop(block_id, None)
            if block:
                block.ref_count = 0
                self.free_blocks.append(block)

        del self.block_table[sequence_id]
        logger.info(f"♻️ [PagedLatent] 序列 {sequence_id} 显存页成功回收")