2323 e.g. qwen3.5-0.8b_bf16_seq2048_bm1684x_1dev_static/block_0/block_0.mlir
2424
2525Usage:
26- python llm_analyse.py <model_dir > -t 32 -b 64
27- python llm_analyse.py <model_dir> -t 32 -b 64 -d w4f16 -o result.xlsx
26+ python llm_analyse.py -m <model > -c bm1684x -s 2048 -t 16 -b 64 -o <out_dir>
27+ # -t: FP16 TOPS; INT8/FP8 TOPS default to 2*t
2828"""
2929
3030import os
@@ -128,6 +128,24 @@ def discover_modules(model_dir: str,
128128# Single-module analysis
129129# ---------------------------------------------------------------------------
130130
131+ COMPUTE_FP16 = "fp16"
132+ COMPUTE_INT8 = "int8"
133+ COMPUTE_FP8 = "fp8"
134+ COMPUTE_VECTOR = "vector"
135+
136+
137+ def _compute_type (base_opn : str ) -> str :
138+ """Pick compute-power bucket for roofline estimate.
139+
140+ Fp8MatMul computes in FP8; weight-only quant (w8/w4 f16/bf16) still
141+ computes in FP16, so all other key ops use FP16 TOPS.
142+ """
143+ if base_opn == "Fp8MatMul" :
144+ return COMPUTE_FP8
145+ if base_opn in KEY_OPS :
146+ return COMPUTE_FP16
147+ return COMPUTE_VECTOR
148+
131149
132150def analyse_module (filepath : str , dtype_mode : str = "f16" ):
133151 """Parse and analyse a single MLIR file.
@@ -145,6 +163,8 @@ def analyse_module(filepath: str, dtype_mode: str = "f16"):
145163 if opn == "MatMul" and ssa_op_map and len (op .operands ) > 1 :
146164 if ssa_op_map .get (op .operands [1 ], "" ) == "top.Weight" :
147165 opn = f"MatMul ({ dtype_mode } )"
166+ elif opn == "Fp8MatMul" :
167+ opn = f"Fp8MatMul ({ dtype_mode } )"
148168 flops = calc_flops (op )
149169 rb , wb = calc_data_volume (op , dtype_mode , ssa_op_map )
150170 inp_shapes = ", " .join (t .shape_str () if t else "none" for t in op .input_types )
@@ -162,6 +182,7 @@ def analyse_module(filepath: str, dtype_mode: str = "f16"):
162182 wb = wb ,
163183 total_io = rb + wb ,
164184 is_key = base_opn in KEY_OPS ,
185+ compute_type = _compute_type (base_opn ),
165186 ))
166187 total_flops += flops
167188 total_read += rb
@@ -180,11 +201,13 @@ def analyse_module(filepath: str, dtype_mode: str = "f16"):
180201
181202
182203def export_llm_excel (modules_data ,
183- chip_tops ,
204+ fp16_tops ,
184205 bw_gbps ,
185206 out_dir ,
186207 llm_path ,
187208 dtype_mode = "f16" ,
209+ int8_tops = None ,
210+ fp8_tops = None ,
188211 vector_tops = None ,
189212 uarch_rate = 0.8 ,
190213 bw_util = 0.7 ,
@@ -211,8 +234,12 @@ def export_llm_excel(modules_data,
211234 from openpyxl .formatting .rule import CellIsRule
212235 from openpyxl .utils import get_column_letter
213236
237+ if int8_tops is None :
238+ int8_tops = fp16_tops * 2.0
239+ if fp8_tops is None :
240+ fp8_tops = fp16_tops * 2.0
214241 if vector_tops is None :
215- vector_tops = chip_tops / 8.0
242+ vector_tops = fp16_tops / 8.0
216243
217244 # ---------- Color palette ----------
218245 C_TITLE = "1F4E79" # deep blue - main title
@@ -322,13 +349,15 @@ def _banner(ws, row, text, span, fill=section_fill, font=section_font, height=22
322349
323350 # params start at row 9
324351 params = [
325- ("Chip Compute Power" , chip_tops , "TOPS" , "#,##0.##" ),
352+ ("FP16 Compute Power" , fp16_tops , "TOPS" , "#,##0.##" ),
353+ ("INT8 Compute Power" , int8_tops , "TOPS" , "#,##0.##" ),
354+ ("FP8 Compute Power" , fp8_tops , "TOPS" , "#,##0.##" ),
326355 ("Vector Compute Power" , vector_tops , "TOPS" , "#,##0.##" ),
327356 ("Chip Bandwidth" , bw_gbps , "GB/s" , "#,##0.##" ),
328357 ("uArch Rate" , uarch_rate , "" , "0%" ),
329358 ("Bandwidth Utilization" , bw_util , "" , "0%" ),
330359 ("Parallelism" , parallelism , "" , "0%" ),
331- ("Serialism" , "=1-B14 " , "" , "0%" ),
360+ ("Serialism" , "=1-B16 " , "" , "0%" ),
332361 ("CPU Call" , 100 , "us" , "#,##0" ),
333362 ("Preprocess Time" , 0.1 , "s" , "#,##0.000" ),
334363 ]
@@ -351,14 +380,26 @@ def _banner(ws, row, text, span, fill=section_fill, font=section_font, height=22
351380 uc .alignment = center
352381
353382 # Formula references (must match absolute positions above)
354- TOPS_REF = "Overview!$B$9"
355- VECTOR_TOPS_REF = "Overview!$B$10"
356- BW_REF = "Overview!$B$11"
357- CU_REF = "Overview!$B$12"
358- BU_REF = "Overview!$B$13"
359- PAR_REF = "Overview!$B$14"
360- CPU_CALL_REF = "Overview!$B$16"
361- PREPROCESS_TIME_REF = "Overview!$B$17"
383+ FP16_TOPS_REF = "Overview!$B$9"
384+ INT8_TOPS_REF = "Overview!$B$10"
385+ FP8_TOPS_REF = "Overview!$B$11"
386+ VECTOR_TOPS_REF = "Overview!$B$12"
387+ BW_REF = "Overview!$B$13"
388+ CU_REF = "Overview!$B$14"
389+ BU_REF = "Overview!$B$15"
390+ PAR_REF = "Overview!$B$16"
391+ CPU_CALL_REF = "Overview!$B$18"
392+ PREPROCESS_TIME_REF = "Overview!$B$19"
393+
394+ def _tops_ref_for_op (d ):
395+ ctype = d .get ("compute_type" , COMPUTE_VECTOR )
396+ if ctype == COMPUTE_INT8 :
397+ return INT8_TOPS_REF
398+ if ctype == COMPUTE_FP8 :
399+ return FP8_TOPS_REF
400+ if ctype == COMPUTE_FP16 :
401+ return FP16_TOPS_REF
402+ return VECTOR_TOPS_REF
362403
363404 # --- Special Ratios (rows 19+) ---
364405 RATIO_BANNER = PARAM_START + len (params ) + 1 # 19
@@ -409,7 +450,7 @@ def _banner(ws, row, text, span, fill=section_fill, font=section_font, height=22
409450 cell .alignment = center
410451 cell .border = thin
411452
412- def _compute_formula (gops_cell , tops_ref = TOPS_REF ):
453+ def _compute_formula (gops_cell , tops_ref = FP16_TOPS_REF ):
413454 return f"=IF({ tops_ref } =0,0,{ gops_cell } /({ tops_ref } *{ CU_REF } )*1000)"
414455
415456 def _memory_formula (io_cell ):
@@ -473,7 +514,7 @@ def _memory_formula(io_cell):
473514 elif c in (5 , 6 , 7 ):
474515 cell .number_format = "#,##0.000"
475516
476- tops_ref = TOPS_REF if d [ "is_key" ] else VECTOR_TOPS_REF
517+ tops_ref = _tops_ref_for_op ( d )
477518 # H: Compute(us) - from GOPs column D
478519 cell_h = ws .cell (row = r , column = 8 )
479520 cell_h .value = _compute_formula (f"D{ r } " , tops_ref )
@@ -629,14 +670,16 @@ def _memory_formula(io_cell):
629670 # ============ Back-fill TTFT / Tokens/s at top (rows 4, 5) ============
630671 # TTFT row (4)
631672 ws0 .cell (row = 4 , column = 2 , value = f"=F{ phase_r } " ).number_format = "#,##0.000000"
632- ws0 .cell (row = 4 , column = 4 , value = f"=IF(F{ phase_r } =0,0,C{ phase_r } /{ TOPS_REF } /1000/F{ phase_r } )" )
673+ ws0 .cell (row = 4 ,
674+ column = 4 ,
675+ value = f"=IF(F{ phase_r } =0,0,C{ phase_r } /{ FP16_TOPS_REF } /1000/F{ phase_r } )" )
633676 ws0 .cell (row = 4 , column = 6 , value = f"=IF(F{ phase_r } =0,0,D{ phase_r } /{ BW_REF } /1000/F{ phase_r } )" )
634677 # Tokens/s row (5)
635678 ws0 .cell (row = 5 , column = 2 ,
636679 value = f"=IF(F{ phase_r + 1 } =0,0,1/F{ phase_r + 1 } )" ).number_format = "#,##0.00"
637680 ws0 .cell (row = 5 ,
638681 column = 4 ,
639- value = f"=IF(F{ phase_r + 1 } =0,0,C{ phase_r + 1 } /{ TOPS_REF } /1000/F{ phase_r + 1 } )" )
682+ value = f"=IF(F{ phase_r + 1 } =0,0,C{ phase_r + 1 } /{ FP16_TOPS_REF } /1000/F{ phase_r + 1 } )" )
640683 ws0 .cell (row = 5 ,
641684 column = 6 ,
642685 value = f"=IF(F{ phase_r + 1 } =0,0,D{ phase_r + 1 } /{ BW_REF } /1000/F{ phase_r + 1 } )" )
@@ -694,7 +737,7 @@ def _memory_formula(io_cell):
694737 "Green cells (parameters, ratios, block counts) are editable; all estimates auto-update." ,
695738 "Est.Time = max(Compute, Memory) + Serialism * min(Compute, Memory)." ,
696739 "block / block_cache use the first block as representative, multiplied by Count." ,
697- "Key operators are highlighted in yellow; use chip TOPS (else vector TOPS) for compute ." ,
740+ "Key operators: Fp8MatMul uses FP8 TOPS; others (incl. w8/w4 MatMul) use FP16 TOPS; non-key ops use vector TOPS ." ,
698741 ]
699742 for i , txt in enumerate (notes , 1 ):
700743 ws0 .merge_cells (start_row = info_banner + i ,
@@ -728,12 +771,19 @@ def main():
728771 parser .add_argument ('-s' , '--seq_length' , type = int , required = True ,
729772 help = "sequence length" )
730773 parser .add_argument ("-t" , "--tops" , type = float , required = True ,
731- help = "Chip compute power in TOPS" )
774+ help = "FP16 compute power in TOPS" )
775+ parser .add_argument ("--int8_tops" , type = float , default = None ,
776+ help = "INT8 compute power in TOPS (default: 2 * tops)" )
777+ parser .add_argument ("--fp8_tops" , type = float , default = None ,
778+ help = "FP8 compute power in TOPS (default: 2 * tops)" )
732779 parser .add_argument ("-b" , "--bandwidth" , type = float , required = True ,
733780 help = "Chip memory bandwidth in GB/s" )
734781 parser .add_argument ("-q" , "--quantize" , default = "f16" ,
735782 choices = ["f16" , "w8f16" , "w4f16" ,"bf16" , "w8bf16" , "w4bf16" ],
736783 help = "Quantization mode (default: f16)" )
784+ parser .add_argument ("-c" , "--chip" , default = "bm1684x" ,
785+ choices = ["bm1684x" , "bm1688" , "cv186x" , "bm1690" , "bm1684x2" ],
786+ help = "Chip type (default: bm1684x)" )
737787 parser .add_argument ("-v" , "--vector_tops" , type = float , default = None ,
738788 help = "Vector compute power in TOPS (default: tops/8)" )
739789 parser .add_argument ("-r" , "--uarch_rate" , type = float , default = 0.8 ,
@@ -768,7 +818,7 @@ def main():
768818 max_pixels = "768,768"
769819 cmds = [
770820 "llm_convert.py" , f"-m { args .model_path } " , f"-s { args .seq_length } " , f"-q { args .quantize } " ,
771- "-c bm1684x " , f"--out_dir { args .out_dir } " , "--only_mlir" , f"--max_pixels { max_pixels } "
821+ f "-c { args . chip } " , f"--out_dir { args .out_dir } " , "--only_mlir" , f"--max_pixels { max_pixels } "
772822 ]
773823 if args .max_input_length > 0 :
774824 cmds .append (f"--max_input_length { args .max_input_length } " )
@@ -821,15 +871,19 @@ def main():
821871 modules_data = []
822872 for name , path , count in modules :
823873 print (f" Analysing: { name } ({ os .path .basename (path )} )" )
824- dtype = args .quantize if name .startswith ("block" ) else "f16"
874+ dtype = args .quantize if name .startswith ("block" ) else args . quantize . replace ( "fp8" , "" )
825875 rows_data , totals = analyse_module (path , dtype )
826876 modules_data .append ((name , count , rows_data , totals ))
827877
828878 # Step 3: Export Excel
829879 cmdline = "python " + " " .join (sys .argv )
830- export_llm_excel (modules_data , args .tops , args .bandwidth , args .out_dir , args .model_path ,
831- args .quantize , args .vector_tops , args .uarch_rate , args .bw_util ,
832- args .parallelism , model_config , args .seq_length , max_pixels , cmdline )
880+ fp16_tops = args .tops
881+ int8_tops = args .int8_tops if args .int8_tops is not None else fp16_tops * 2.0
882+ fp8_tops = args .fp8_tops if args .fp8_tops is not None else fp16_tops * 2.0
883+ export_llm_excel (modules_data , fp16_tops , args .bandwidth , args .out_dir , args .model_path ,
884+ args .quantize , int8_tops , fp8_tops , args .vector_tops , args .uarch_rate ,
885+ args .bw_util , args .parallelism , model_config , args .seq_length , max_pixels ,
886+ cmdline )
833887
834888
835889if __name__ == "__main__" :
0 commit comments