char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
446595b9b
char/aliceai-t5-moe
1#!/usr/bin/env python3 2 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 csv 7import logging 8import sys 9from pathlib import Path 10from collections import defaultdict 11 12 13class DocsGenerator : 14def __init__ (self ,ggml_root :str ,output_filename :str = "ops.md" ): 15self .ggml_root = Path (ggml_root ) 16self .ops_dir = self .ggml_root / "docs" / "ops" 17self .output_filename = output_filename 18self .backend_support :dict [str ,dict [str ,list [bool ]]]= defaultdict ( 19lambda :defaultdict (list ) 20 ) 21self .all_operations :set [str ]= set () 22self .all_backends :set [str ]= set () 23self .logger = logging .getLogger (__name__ ) 24 25def parse_support_files (self )-> None : 26if not self .ops_dir .exists (): 27self .logger .warning (f"ops directory not found: { self . ops_dir } " ) 28return 29 30self .logger .info (f"Parsing support files from { self . ops_dir } ..." ) 31 32for support_file in self .ops_dir .glob ("*.csv" ): 33self .logger .info (f" Reading: { support_file . name } " ) 34self ._parse_support_file (support_file ) 35 36def _parse_support_file (self ,file_path :Path )-> None : 37try : 38with open (file_path ,"r" ,newline = '' )as f : 39reader = csv .DictReader (f ) 40 41for row in reader : 42# Skip rows that don't have support mode 43if row .get ('test_mode' )!= 'support' : 44continue 45 46backend_name = row .get ('backend_name' ,'' ).strip () 47operation = row .get ('op_name' ,'' ).strip () 48supported_str = row .get ('error_message' ,'' ).strip ()# "yes" or "no" 49backend_reg_name = row .get ('backend_reg_name' ,'' ).strip () 50 51# Skip invalid or error operations 52if not operation or not backend_name or operation in [ 53"CONTEXT_ERROR" , 54"BUILD_ERROR" , 55 ]: 56continue 57 58is_supported = supported_str .lower ()== "yes" 59 60# Use backend_reg_name for grouping, fallback to backend_name 61backend_key = backend_reg_name if backend_reg_name else backend_name 62 63self .all_backends .add (backend_key ) 64self .backend_support [backend_key ][operation ].append (is_supported ) 65self .all_operations .add (operation ) 66 67except Exception as e : 68self .logger .error (f" Error parsing { file_path } : { e } " ) 69 70def get_backend_support_status (self ,backend :str ,operation :str )-> str : 71support_list = self .backend_support [backend ].get (operation , []) 72 73if not support_list : 74return "unsupported" 75 76all_supported = all (support_list ) 77any_supported = any (support_list ) 78 79if all_supported : 80return "supported" 81elif any_supported : 82return "partially supported" 83else : 84return "unsupported" 85 86def get_support_status (self ,operation :str )-> str : 87if operation not in self .all_operations : 88return "unsupported" 89 90support_count = 0 91total_backends = len (self .all_backends ) 92 93for backend in self .all_backends : 94if self .backend_support [backend ].get (operation ,False ): 95support_count += 1 96 97if support_count == 0 : 98return "unsupported" 99elif support_count == total_backends : 100return "supported" 101else : 102return "partially supported" 103 104def get_support_symbol (self ,status :str )-> str : 105symbols = {"supported" :"✅" ,"partially supported" :"🟡" ,"unsupported" :"❌" } 106return symbols .get (status ,"❓" ) 107 108def generate_markdown (self )-> str : 109lines = [] 110 111lines .append ("# GGML Operations" ) 112lines .append ("" ) 113lines .append ("List of GGML operations and backend support status." ) 114lines .append ("" ) 115lines .append ("## How to add a backend to this table:" ) 116lines .append ("" ) 117lines .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`)" ) 118lines .append ("2. Regenerate `/docs/ops.md` via `./scripts/create_ops_docs.py`" ) 119lines .append ("" ) 120lines .append ("Legend:" ) 121lines .append ("- ✅ Fully supported by this backend" ) 122lines .append ("- 🟡 Partially supported by this backend" ) 123lines .append ("- ❌ Not supported by this backend" ) 124lines .append ("" ) 125 126backends = sorted (self .all_backends ) 127header = "| Operation |" 128for backend in backends : 129header += f" { backend } |" 130 131separator = "|-----------|" 132for _ in backends : 133separator += "------|" 134 135lines .append (header ) 136lines .append (separator ) 137 138sorted_operations = sorted (self .all_operations ) 139 140for operation in sorted_operations : 141row = f"| { operation :>32 } |" 142 143for backend in backends : 144status = self .get_backend_support_status (backend ,operation ) 145if status == "supported" : 146symbol = "✅" 147elif status == "partially supported" : 148symbol = "🟡" 149else : 150symbol = "❌" 151row += f" { symbol } |" 152 153lines .append (row ) 154 155lines .append ("" ) 156 157return "\n" .join (lines ) 158 159def run (self )-> None : 160self .logger .info ("Parsing GGML operation support files..." ) 161self .parse_support_files () 162 163if not self .all_operations : 164self .logger .error ( 165"No operations found. Make sure to run test-backend-ops support --output csv > docs/ops/file.csv first." 166 ) 167return 168 169self .logger .info ( 170f"Found { len ( self . all_operations ) } operations across { len ( self . all_backends ) } backends" 171 ) 172 173self .logger .info ("Generating markdown..." ) 174markdown_content = self .generate_markdown () 175 176docs_dir = self .ggml_root / "docs" 177docs_dir .mkdir (exist_ok = True ) 178 179ops_file = docs_dir / self .output_filename 180with open (ops_file ,"w" )as f : 181f .write (markdown_content ) 182 183self .logger .info (f"Generated: { ops_file } " ) 184self .logger .info (f"Operations: { len ( self . all_operations ) } " ) 185self .logger .info (f"Backends: { len ( self . all_backends ) } " ) 186 187 188def main (): 189logging .basicConfig (level = logging .INFO ) 190 191if len (sys .argv )> 1 : 192output_filename = sys .argv [1 ] 193else : 194output_filename = "ops.md" 195 196generator = DocsGenerator ("." ,output_filename ) 197generator .run () 198 199 200if __name__ == "__main__" : 201main ()