CoolFace
Datasetpublic

echodict/llama.cpp

version https://git-lfs.github.com/spec/v1 oid sha256:cfc44b7ba25614df70e6b65e3341cae0310163bd32fd31a6b928a542df433faf size 30786

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes762downloads
create_ops_docs.py202 linesDownload Raw Back to scripts
1#!/usr/bin/env python32 3"""4This script parses docs/ops/*.csv and creates the ops.md, which is a table documenting supported operations on various ggml backends.5"""6import csv7import logging8import sys9from pathlib import Path10from collections import defaultdict11 12 13class DocsGenerator:14    def __init__(self, ggml_root: str, output_filename: str = "ops.md"):15        self.ggml_root = Path(ggml_root)16        self.ops_dir = self.ggml_root / "docs" / "ops"17        self.output_filename = output_filename18        self.backend_support: dict[str, dict[str, list[bool]]] = defaultdict(19            lambda: defaultdict(list)20        )21        self.all_operations: set[str] = set()22        self.all_backends: set[str] = set()23        self.logger = logging.getLogger(__name__)24 25    def parse_support_files(self) -> None:26        if not self.ops_dir.exists():27            self.logger.warning(f"ops directory not found: {self.ops_dir}")28            return29 30        self.logger.info(f"Parsing support files from {self.ops_dir}...")31 32        for support_file in self.ops_dir.glob("*.csv"):33            self.logger.info(f"  Reading: {support_file.name}")34            self._parse_support_file(support_file)35 36    def _parse_support_file(self, file_path: Path) -> None:37        try:38            with open(file_path, "r", newline='') as f:39                reader = csv.DictReader(f)40 41                for row in reader:42                    # Skip rows that don't have support mode43                    if row.get('test_mode') != 'support':44                        continue45 46                    backend_name = row.get('backend_name', '').strip()47                    operation = row.get('op_name', '').strip()48                    supported_str = row.get('error_message', '').strip()  # "yes" or "no"49                    backend_reg_name = row.get('backend_reg_name', '').strip()50 51                    # Skip invalid or error operations52                    if not operation or not backend_name or operation in [53                        "CONTEXT_ERROR",54                        "BUILD_ERROR",55                    ]:56                        continue57 58                    is_supported = supported_str.lower() == "yes"59 60                    # Use backend_reg_name for grouping, fallback to backend_name61                    backend_key = backend_reg_name if backend_reg_name else backend_name62 63                    self.all_backends.add(backend_key)64                    self.backend_support[backend_key][operation].append(is_supported)65                    self.all_operations.add(operation)66 67        except Exception as e:68            self.logger.error(f"    Error parsing {file_path}: {e}")69 70    def get_backend_support_status(self, backend: str, operation: str) -> str:71        support_list = self.backend_support[backend].get(operation, [])72 73        if not support_list:74            return "unsupported"75 76        all_supported = all(support_list)77        any_supported = any(support_list)78 79        if all_supported:80            return "supported"81        elif any_supported:82            return "partially supported"83        else:84            return "unsupported"85 86    def get_support_status(self, operation: str) -> str:87        if operation not in self.all_operations:88            return "unsupported"89 90        support_count = 091        total_backends = len(self.all_backends)92 93        for backend in self.all_backends:94            if self.backend_support[backend].get(operation, False):95                support_count += 196 97        if support_count == 0:98            return "unsupported"99        elif support_count == total_backends:100            return "supported"101        else:102            return "partially supported"103 104    def get_support_symbol(self, status: str) -> str:105        symbols = {"supported": "โœ…", "partially supported": "๐ŸŸก", "unsupported": "โŒ"}106        return symbols.get(status, "โ“")107 108    def generate_markdown(self) -> str:109        lines = []110 111        lines.append("# GGML Operations")112        lines.append("")113        lines.append("List of GGML operations and backend support status.")114        lines.append("")115        lines.append("## How to add a backend to this table:")116        lines.append("")117        lines.append("1. Run `test-backend-ops support --output csv` with your backend name and redirect output to a csv file in `docs/ops/` (e.g., `docs/ops/CUDA.csv`)")118        lines.append("2. Regenerate `/docs/ops.md` via `./scripts/create_ops_docs.py`")119        lines.append("")120        lines.append("Legend:")121        lines.append("- โœ… Fully supported by this backend")122        lines.append("- ๐ŸŸก Partially supported by this backend")123        lines.append("- โŒ Not supported by this backend")124        lines.append("")125 126        backends = sorted(self.all_backends)127        header = "| Operation |"128        for backend in backends:129            header += f" {backend} |"130 131        separator = "|-----------|"132        for _ in backends:133            separator += "------|"134 135        lines.append(header)136        lines.append(separator)137 138        sorted_operations = sorted(self.all_operations)139 140        for operation in sorted_operations:141            row = f"| {operation:>32} |"142 143            for backend in backends:144                status = self.get_backend_support_status(backend, operation)145                if status == "supported":146                    symbol = "โœ…"147                elif status == "partially supported":148                    symbol = "๐ŸŸก"149                else:150                    symbol = "โŒ"151                row += f" {symbol} |"152 153            lines.append(row)154 155        lines.append("")156 157        return "\n".join(lines)158 159    def run(self) -> None:160        self.logger.info("Parsing GGML operation support files...")161        self.parse_support_files()162 163        if not self.all_operations:164            self.logger.error(165                "No operations found. Make sure to run test-backend-ops support --output csv > docs/ops/file.csv first."166            )167            return168 169        self.logger.info(170            f"Found {len(self.all_operations)} operations across {len(self.all_backends)} backends"171        )172 173        self.logger.info("Generating markdown...")174        markdown_content = self.generate_markdown()175 176        docs_dir = self.ggml_root / "docs"177        docs_dir.mkdir(exist_ok=True)178 179        ops_file = docs_dir / self.output_filename180        with open(ops_file, "w") as f:181            f.write(markdown_content)182 183        self.logger.info(f"Generated: {ops_file}")184        self.logger.info(f"Operations: {len(self.all_operations)}")185        self.logger.info(f"Backends: {len(self.all_backends)}")186 187 188def main():189    logging.basicConfig(level=logging.INFO)190 191    if len(sys.argv) > 1:192        output_filename = sys.argv[1]193    else:194        output_filename = "ops.md"195 196    generator = DocsGenerator(".", output_filename)197    generator.run()198 199 200if __name__ == "__main__":201    main()202