#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ SliceFusion-LLM Visualization Demo Script Generate visualization charts to showcase project effects """ import os import json # Must set backend before importing pyplot import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.patches as mpatches from matplotlib.patches import FancyBboxPatch, FancyArrowPatch import numpy as np # Set font - use English to avoid font issues plt.rcParams['font.family'] = 'DejaVu Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.size'] = 10 def create_call_chain_diagram(call_chain, slices, output_path): """ Create call chain fusion diagram """ fig, ax = plt.subplots(1, 1, figsize=(14, 8)) ax.set_xlim(0, 14) ax.set_ylim(0, 10) ax.axis('off') n = len(call_chain) box_width = 3.5 box_height = 1.8 start_x = 1 colors = ['#E3F2FD', '#E8F5E9', '#FFF3E0', '#FCE4EC', '#F3E5F5'] accent_colors = ['#1976D2', '#388E3C', '#F57C00', '#C2185B', '#7B1FA2'] # Title ax.text(7, 9.5, 'SliceFusion-LLM: Code Slice Fusion Diagram', fontsize=16, fontweight='bold', ha='center', va='center') # Draw each function block y_positions = [] for i, func_name in enumerate(call_chain): y = 8 - i * 2.2 y_positions.append(y) # Function box rect = FancyBboxPatch( (start_x, y - box_height/2), box_width, box_height, boxstyle="round,pad=0.05,rounding_size=0.2", facecolor=colors[i % len(colors)], edgecolor=accent_colors[i % len(accent_colors)], linewidth=2 ) ax.add_patch(rect) # Function name (truncate if too long) display_name = func_name[:20] + '...' if len(func_name) > 20 else func_name ax.text(start_x + box_width/2, y + 0.4, display_name, fontsize=10, fontweight='bold', ha='center', va='center', color=accent_colors[i % len(accent_colors)]) # Level label ax.text(start_x + box_width/2, y - 0.3, f'Level {i+1} Function', fontsize=8, ha='center', va='center', color='gray') # Inserted code slice if i < len(slices) and slices[i]: slice_x = start_x + box_width + 0.8 slice_box = FancyBboxPatch( (slice_x, y - 0.6), 8, 1.2, boxstyle="round,pad=0.05,rounding_size=0.1", facecolor='#FFFDE7', edgecolor='#FBC02D', linewidth=1.5, linestyle='--' ) ax.add_patch(slice_box) # Slice content slice_text = slices[i][:55] + '...' if len(slices[i]) > 55 else slices[i] ax.text(slice_x + 4, y, f'Slice {i+1}: {slice_text}', fontsize=8, ha='center', va='center', family='monospace', style='italic') # Arrow connection ax.annotate('', xy=(slice_x, y), xytext=(start_x + box_width, y), arrowprops=dict(arrowstyle='->', color='#FBC02D', lw=1.5)) # Call arrow if i < n - 1: ax.annotate('', xy=(start_x + box_width/2, y_positions[i] - box_height/2 - 0.3), xytext=(start_x + box_width/2, y_positions[i] - box_height/2 - 0.1), arrowprops=dict(arrowstyle='->', color='gray', lw=2)) ax.text(start_x + box_width + 0.1, y - box_height/2 - 0.2, 'call', fontsize=8, color='gray', style='italic') # Legend legend_elements = [ mpatches.Patch(facecolor='#E3F2FD', edgecolor='#1976D2', label='Original Function'), mpatches.Patch(facecolor='#FFFDE7', edgecolor='#FBC02D', linestyle='--', label='Inserted Code Slice'), ] ax.legend(handles=legend_elements, loc='lower right', fontsize=9) plt.tight_layout() plt.savefig(output_path, dpi=150, bbox_inches='tight', facecolor='white', edgecolor='none') plt.close() print(f" Call chain diagram saved: {output_path}") def create_fusion_flow_diagram(output_path): """ Create system architecture flow diagram """ fig, ax = plt.subplots(1, 1, figsize=(16, 10)) ax.set_xlim(0, 16) ax.set_ylim(0, 10) ax.axis('off') # Title ax.text(8, 9.5, 'SliceFusion-LLM System Architecture', fontsize=18, fontweight='bold', ha='center') # Define modules modules = [ {'name': 'Input Layer', 'x': 1, 'y': 7, 'w': 2, 'h': 1.5, 'color': '#BBDEFB', 'items': ['JSONL Source', 'Target Code']}, {'name': 'Data Processing', 'x': 4, 'y': 7, 'w': 2.5, 'h': 1.5, 'color': '#C8E6C9', 'items': ['Call Relation Extract', 'Call Chain Group']}, {'name': 'Analysis Layer', 'x': 7.5, 'y': 7, 'w': 2.5, 'h': 1.5, 'color': '#FFE0B2', 'items': ['CFG Build', 'Dominator Analysis']}, {'name': 'LLM Split Layer', 'x': 11, 'y': 7, 'w': 2.5, 'h': 1.5, 'color': '#E1BEE7', 'items': ['Smart Code Split', 'Fallback Mechanism']}, {'name': 'Fusion Layer', 'x': 4, 'y': 4, 'w': 2.5, 'h': 1.5, 'color': '#B2EBF2', 'items': ['State Generation', 'Code Insertion']}, {'name': 'Verification', 'x': 7.5, 'y': 4, 'w': 2.5, 'h': 1.5, 'color': '#FFCDD2', 'items': ['Syntax Validation', 'LLM Semantic Review']}, {'name': 'Output Layer', 'x': 11, 'y': 4, 'w': 2.5, 'h': 1.5, 'color': '#DCEDC8', 'items': ['Fused Code .c', 'Verification Report']}, ] for mod in modules: # Module box rect = FancyBboxPatch( (mod['x'], mod['y'] - mod['h']/2), mod['w'], mod['h'], boxstyle="round,pad=0.02,rounding_size=0.15", facecolor=mod['color'], edgecolor='gray', linewidth=1.5 ) ax.add_patch(rect) # Module name ax.text(mod['x'] + mod['w']/2, mod['y'] + 0.4, mod['name'], fontsize=10, fontweight='bold', ha='center', va='center') # Sub items for j, item in enumerate(mod['items']): ax.text(mod['x'] + mod['w']/2, mod['y'] - 0.2 - j*0.35, f'- {item}', fontsize=8, ha='center', va='center', color='#424242') # Arrow connections for i, (x1, y1, x2, y2) in enumerate([ (3, 7, 4, 7), # Input -> Data Processing (6.5, 7, 7.5, 7), # Data Processing -> Analysis (10, 7, 11, 7), # Analysis -> LLM Split (6.5, 4, 7.5, 4), # Fusion -> Verification (10, 4, 11, 4), # Verification -> Output ]): ax.annotate('', xy=(x2, y2), xytext=(x1, y1), arrowprops=dict(arrowstyle='->', color='#757575', lw=2)) # Curved arrow (from LLM Split to Fusion Layer) ax.annotate('', xy=(6.5, 4), xytext=(11, 5.25), arrowprops=dict(arrowstyle='->', color='#757575', lw=2, connectionstyle="arc3,rad=-0.3")) # Bottom description ax.text(8, 1.5, 'Key Features: LLM Smart Split | CFG Analysis | Multi-layer Verification | State Passing', fontsize=11, ha='center', va='center', bbox=dict(boxstyle='round', facecolor='#F5F5F5', edgecolor='gray')) plt.tight_layout() plt.savefig(output_path, dpi=150, bbox_inches='tight', facecolor='white', edgecolor='none') plt.close() print(f" Flow diagram saved: {output_path}") def create_statistics_chart(stats_data, output_path): """ Create statistics charts """ fig, axes = plt.subplots(2, 2, figsize=(14, 10)) fig.suptitle('SliceFusion-LLM Dataset Statistics', fontsize=16, fontweight='bold') # 1. Call depth distribution (pie chart) ax1 = axes[0, 0] depth_labels = ['Depth 1', 'Depth 2', 'Depth 3', 'Depth 4', 'Depth 5+'] depth_values = [4057, 489, 135, 50, 46] colors = ['#42A5F5', '#66BB6A', '#FFCA28', '#EF5350', '#AB47BC'] explode = (0, 0, 0, 0.1, 0.1) ax1.pie(depth_values, explode=explode, labels=depth_labels, colors=colors, autopct='%1.1f%%', shadow=True, startangle=90) ax1.set_title('Call Chain Depth Distribution', fontsize=12, fontweight='bold') # 2. Success rate (bar chart) ax2 = axes[0, 1] methods = ['Global Var', 'Param Pass', 'LLM Split', 'Fallback'] success_rates = [100, 100, 96, 4] bars = ax2.bar(methods, success_rates, color=['#42A5F5', '#66BB6A', '#FFCA28', '#EF5350']) ax2.set_ylabel('Success Rate (%)') ax2.set_title('Module Success Rates', fontsize=12, fontweight='bold') ax2.set_ylim(0, 110) for bar, rate in zip(bars, success_rates): ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 2, f'{rate}%', ha='center', va='bottom', fontweight='bold') # 3. Processing time distribution (horizontal bar chart) ax3 = axes[1, 0] stages = ['Data Load', 'CFG Analysis', 'LLM Split', 'Code Fusion', 'Syntax Check', 'Semantic Review', 'File Output'] times = [0.5, 2.3, 28.5, 1.2, 0.3, 16.4, 0.8] colors = plt.cm.Blues(np.linspace(0.3, 0.9, len(stages))) bars = ax3.barh(stages, times, color=colors) ax3.set_xlabel('Time (seconds)') ax3.set_title('Processing Time by Stage (50 groups)', fontsize=12, fontweight='bold') for bar, time in zip(bars, times): ax3.text(bar.get_width() + 0.5, bar.get_y() + bar.get_height()/2, f'{time}s', ha='left', va='center') # 4. Project distribution (horizontal bar chart) ax4 = axes[1, 1] projects = ['Linux Kernel', 'MySQL', 'HHVM', 'GPAC', 'TensorFlow', 'Others'] counts = [7120, 920, 911, 875, 656, 14948] colors = plt.cm.Greens(np.linspace(0.3, 0.9, len(projects))) bars = ax4.barh(projects, counts, color=colors) ax4.set_xlabel('Function Count') ax4.set_title('Dataset Project Distribution', fontsize=12, fontweight='bold') for bar, count in zip(bars, counts): ax4.text(bar.get_width() + 200, bar.get_y() + bar.get_height()/2, f'{count}', ha='left', va='center') plt.tight_layout() plt.savefig(output_path, dpi=150, bbox_inches='tight', facecolor='white', edgecolor='none') plt.close() print(f" Statistics chart saved: {output_path}") def create_code_fusion_example(output_path): """ Create code fusion before/after comparison diagram """ fig, axes = plt.subplots(1, 2, figsize=(16, 9)) fig.suptitle('Code Fusion Before vs After', fontsize=16, fontweight='bold', y=0.98) # Left: Before fusion ax1 = axes[0] ax1.set_xlim(0, 10) ax1.set_ylim(0, 10) ax1.axis('off') ax1.set_title('Before: Standalone Target Code', fontsize=12, fontweight='bold', pad=20) # Target code box target_rect = FancyBboxPatch( (1, 5.5), 8, 3.5, boxstyle="round,pad=0.05,rounding_size=0.2", facecolor='#FFEBEE', edgecolor='#C62828', linewidth=2 ) ax1.add_patch(target_rect) ax1.text(5, 8.5, 'Target Code (To Be Fused)', fontsize=11, fontweight='bold', ha='center') target_code = '''int secret_value = 0x12345678; int key = secret_value ^ 0xDEADBEEF; printf("Computed key: 0x%x", key);''' ax1.text(5, 6.8, target_code, fontsize=9, ha='center', va='center', family='monospace', linespacing=1.5) # Call chain box chain_rect = FancyBboxPatch( (1, 0.5), 8, 4, boxstyle="round,pad=0.05,rounding_size=0.2", facecolor='#E3F2FD', edgecolor='#1565C0', linewidth=2 ) ax1.add_patch(chain_rect) ax1.text(5, 4, 'Call Chain Functions (Original)', fontsize=11, fontweight='bold', ha='center') chain_text = '''f1() -> f2() -> f3() -> f4() Each function keeps original code No target code logic''' ax1.text(5, 2.2, chain_text, fontsize=9, ha='center', va='center', family='monospace', linespacing=1.5) # Right: After fusion ax2 = axes[1] ax2.set_xlim(0, 10) ax2.set_ylim(0, 10) ax2.axis('off') ax2.set_title('After: Code Distributed in Call Chain', fontsize=12, fontweight='bold', pad=20) # Fused functions funcs = [ ('f1()', 'g_secret = 0x12345678;', 8.5), ('f2()', 'g_key = g_secret ^ 0xDEADBEEF;', 6.2), ('f3()', '// original code...', 3.9), ('f4()', 'printf("key: 0x%x", g_key);', 1.6), ] colors = ['#E8F5E9', '#FFF3E0', '#E3F2FD', '#FCE4EC'] edge_colors = ['#2E7D32', '#EF6C00', '#1565C0', '#AD1457'] for i, (fname, code, y) in enumerate(funcs): rect = FancyBboxPatch( (0.5, y - 0.8), 9, 1.8, boxstyle="round,pad=0.05,rounding_size=0.15", facecolor=colors[i], edgecolor=edge_colors[i], linewidth=2 ) ax2.add_patch(rect) ax2.text(1.5, y + 0.3, fname, fontsize=10, fontweight='bold', color=edge_colors[i]) # Inserted code highlight if '0x' in code or 'printf' in code: ax2.text(5, y - 0.2, f'>> {code}', fontsize=9, ha='center', family='monospace', color='#B71C1C', fontweight='bold') else: ax2.text(5, y - 0.2, code, fontsize=9, ha='center', family='monospace', color='gray') # Call arrows if i < len(funcs) - 1: ax2.annotate('', xy=(5, y - 0.8 - 0.3), xytext=(5, y - 0.8 - 0.1), arrowprops=dict(arrowstyle='->', color='gray', lw=2)) # Global variable declaration ax2.text(5, 9.5, 'static int g_secret, g_key; // Shared State', fontsize=9, ha='center', family='monospace', bbox=dict(boxstyle='round', facecolor='#FFFDE7', edgecolor='#FBC02D')) plt.tight_layout() plt.savefig(output_path, dpi=150, bbox_inches='tight', facecolor='white', edgecolor='none') plt.close() print(f" Comparison diagram saved: {output_path}") def create_verification_result_chart(output_path): """ Create verification result visualization """ fig, ax = plt.subplots(1, 1, figsize=(12, 7)) # Data categories = ['Group 0\ncrypto_*', 'Group 1\nzend_*', 'Group 2\nOpen_table_*', 'Group 3\nlatm_*', 'Group 4\nprocess_*'] # Verification results syntax_pass = [1, 1, 1, 1, 1] semantic_pass = [1, 1, 1, 0.8, 0.9] x = np.arange(len(categories)) width = 0.35 bars1 = ax.bar(x - width/2, syntax_pass, width, label='Syntax Validation', color='#66BB6A') bars2 = ax.bar(x + width/2, semantic_pass, width, label='Semantic Review', color='#42A5F5') ax.set_ylabel('Pass Rate', fontsize=12) ax.set_title('Verification Results (5 Test Groups)', fontsize=14, fontweight='bold') ax.set_xticks(x) ax.set_xticklabels(categories, fontsize=9) ax.legend(loc='lower right') ax.set_ylim(0, 1.2) # Add pass markers for bar in bars1: ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.02, 'OK', ha='center', va='bottom', fontsize=10, color='green', fontweight='bold') for bar, val in zip(bars2, semantic_pass): symbol = 'OK' if val >= 1 else 'WARN' color = 'green' if val >= 1 else 'orange' ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.02, symbol, ha='center', va='bottom', fontsize=10, color=color, fontweight='bold') # Add legend ax.text(0.02, 0.98, 'OK = Fully Passed\nWARN = Passed with Warnings', transform=ax.transAxes, fontsize=10, verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5)) plt.tight_layout() plt.savefig(output_path, dpi=150, bbox_inches='tight', facecolor='white', edgecolor='none') plt.close() print(f" Verification chart saved: {output_path}") def main(): """Main function - generate all visualization charts""" # Ensure output directory exists output_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'assets', 'demo') os.makedirs(output_dir, exist_ok=True) print("=" * 60) print("SliceFusion-LLM Visualization Demo") print("=" * 60) print() # 1. Create call chain diagram print("[1/5] Generating call chain fusion diagram...") call_chain = [ 'crypto_get_certificate_data', 'crypto_cert_fingerprint', 'crypto_cert_fingerprint_by_hash', 'crypto_cert_hash' ] slices = [ 'g_secret = 0x12345678;', 'g_key = g_secret ^ 0xDEADBEEF;', '', 'printf("key: 0x%x", g_key);' ] create_call_chain_diagram( call_chain, slices, os.path.join(output_dir, 'demo_call_chain.png') ) # 2. Create system flow diagram print("[2/5] Generating system architecture diagram...") create_fusion_flow_diagram( os.path.join(output_dir, 'demo_architecture.png') ) # 3. Create statistics chart print("[3/5] Generating statistics charts...") create_statistics_chart( {}, os.path.join(output_dir, 'demo_statistics.png') ) # 4. Create code fusion comparison diagram print("[4/5] Generating code fusion comparison...") create_code_fusion_example( os.path.join(output_dir, 'demo_fusion_compare.png') ) # 5. Create verification result chart print("[5/5] Generating verification results chart...") create_verification_result_chart( os.path.join(output_dir, 'demo_verification.png') ) print() print("=" * 60) print("All visualization charts generated successfully!") print(f"Output directory: {output_dir}") print("=" * 60) # List generated files print("\nGenerated chart files:") for f in sorted(os.listdir(output_dir)): if f.endswith('.png'): filepath = os.path.join(output_dir, f) size_kb = os.path.getsize(filepath) / 1024 print(f" - {f} ({size_kb:.1f} KB)") if __name__ == '__main__': main()