zexus 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -0
- package/README.md +2513 -0
- package/bin/zexus +2 -0
- package/bin/zpics +2 -0
- package/bin/zpm +2 -0
- package/bin/zx +2 -0
- package/bin/zx-deploy +2 -0
- package/bin/zx-dev +2 -0
- package/bin/zx-run +2 -0
- package/package.json +66 -0
- package/scripts/README.md +24 -0
- package/scripts/postinstall.js +44 -0
- package/shared_config.json +24 -0
- package/src/README.md +1525 -0
- package/src/tests/run_zexus_tests.py +117 -0
- package/src/tests/test_all_phases.zx +346 -0
- package/src/tests/test_blockchain_features.zx +306 -0
- package/src/tests/test_complexity_features.zx +321 -0
- package/src/tests/test_core_integration.py +185 -0
- package/src/tests/test_phase10_ecosystem.zx +177 -0
- package/src/tests/test_phase1_modifiers.zx +87 -0
- package/src/tests/test_phase2_plugins.zx +80 -0
- package/src/tests/test_phase3_security.zx +97 -0
- package/src/tests/test_phase4_vfs.zx +116 -0
- package/src/tests/test_phase5_types.zx +117 -0
- package/src/tests/test_phase6_metaprogramming.zx +125 -0
- package/src/tests/test_phase7_optimization.zx +132 -0
- package/src/tests/test_phase9_advanced_types.zx +157 -0
- package/src/tests/test_security_features.py +419 -0
- package/src/tests/test_security_features.zx +276 -0
- package/src/tests/test_simple_zx.zx +1 -0
- package/src/tests/test_verification_simple.zx +69 -0
- package/src/zexus/__init__.py +28 -0
- package/src/zexus/__main__.py +5 -0
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +401 -0
- package/src/zexus/blockchain/__init__.py +40 -0
- package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/crypto.py +463 -0
- package/src/zexus/blockchain/ledger.py +255 -0
- package/src/zexus/blockchain/transaction.py +267 -0
- package/src/zexus/builtin_modules.py +284 -0
- package/src/zexus/builtin_plugins.py +317 -0
- package/src/zexus/capability_system.py +372 -0
- package/src/zexus/cli/__init__.py +2 -0
- package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +707 -0
- package/src/zexus/cli/zpm.py +203 -0
- package/src/zexus/compare_interpreter_compiler.py +146 -0
- package/src/zexus/compiler/__init__.py +169 -0
- package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +266 -0
- package/src/zexus/compiler/compat_runtime.py +277 -0
- package/src/zexus/compiler/lexer.py +257 -0
- package/src/zexus/compiler/parser.py +779 -0
- package/src/zexus/compiler/semantic.py +118 -0
- package/src/zexus/compiler/zexus_ast.py +454 -0
- package/src/zexus/complexity_system.py +575 -0
- package/src/zexus/concurrency_system.py +493 -0
- package/src/zexus/config.py +201 -0
- package/src/zexus/crypto_bridge.py +19 -0
- package/src/zexus/dependency_injection.py +423 -0
- package/src/zexus/ecosystem.py +434 -0
- package/src/zexus/environment.py +101 -0
- package/src/zexus/environment_manager.py +119 -0
- package/src/zexus/error_reporter.py +314 -0
- package/src/zexus/evaluator/__init__.py +12 -0
- package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +700 -0
- package/src/zexus/evaluator/core.py +891 -0
- package/src/zexus/evaluator/expressions.py +827 -0
- package/src/zexus/evaluator/functions.py +3989 -0
- package/src/zexus/evaluator/integration.py +396 -0
- package/src/zexus/evaluator/statements.py +4303 -0
- package/src/zexus/evaluator/utils.py +126 -0
- package/src/zexus/evaluator_original.py +2041 -0
- package/src/zexus/external_bridge.py +16 -0
- package/src/zexus/find_affected_imports.sh +155 -0
- package/src/zexus/hybrid_orchestrator.py +152 -0
- package/src/zexus/input_validation.py +259 -0
- package/src/zexus/lexer.py +571 -0
- package/src/zexus/logging.py +89 -0
- package/src/zexus/lsp/__init__.py +9 -0
- package/src/zexus/lsp/completion_provider.py +207 -0
- package/src/zexus/lsp/definition_provider.py +22 -0
- package/src/zexus/lsp/hover_provider.py +71 -0
- package/src/zexus/lsp/server.py +269 -0
- package/src/zexus/lsp/symbol_provider.py +31 -0
- package/src/zexus/metaprogramming.py +321 -0
- package/src/zexus/module_cache.py +89 -0
- package/src/zexus/module_manager.py +107 -0
- package/src/zexus/object.py +973 -0
- package/src/zexus/optimization.py +424 -0
- package/src/zexus/parser/__init__.py +31 -0
- package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/integration.py +86 -0
- package/src/zexus/parser/parser.py +3977 -0
- package/src/zexus/parser/strategy_context.py +7254 -0
- package/src/zexus/parser/strategy_structural.py +1033 -0
- package/src/zexus/persistence.py +391 -0
- package/src/zexus/plugin_system.py +290 -0
- package/src/zexus/policy_engine.py +365 -0
- package/src/zexus/profiler/__init__.py +5 -0
- package/src/zexus/profiler/profiler.py +233 -0
- package/src/zexus/purity_system.py +398 -0
- package/src/zexus/runtime/__init__.py +20 -0
- package/src/zexus/runtime/async_runtime.py +324 -0
- package/src/zexus/search_old_imports.sh +65 -0
- package/src/zexus/security.py +1407 -0
- package/src/zexus/stack_trace.py +233 -0
- package/src/zexus/stdlib/__init__.py +27 -0
- package/src/zexus/stdlib/blockchain.py +341 -0
- package/src/zexus/stdlib/compression.py +167 -0
- package/src/zexus/stdlib/crypto.py +124 -0
- package/src/zexus/stdlib/datetime.py +163 -0
- package/src/zexus/stdlib/db_mongo.py +199 -0
- package/src/zexus/stdlib/db_mysql.py +162 -0
- package/src/zexus/stdlib/db_postgres.py +163 -0
- package/src/zexus/stdlib/db_sqlite.py +133 -0
- package/src/zexus/stdlib/encoding.py +230 -0
- package/src/zexus/stdlib/fs.py +195 -0
- package/src/zexus/stdlib/http.py +219 -0
- package/src/zexus/stdlib/http_server.py +248 -0
- package/src/zexus/stdlib/json_module.py +61 -0
- package/src/zexus/stdlib/math.py +360 -0
- package/src/zexus/stdlib/os_module.py +265 -0
- package/src/zexus/stdlib/regex.py +148 -0
- package/src/zexus/stdlib/sockets.py +253 -0
- package/src/zexus/stdlib/test_framework.zx +208 -0
- package/src/zexus/stdlib/test_runner.zx +119 -0
- package/src/zexus/stdlib_integration.py +341 -0
- package/src/zexus/strategy_recovery.py +256 -0
- package/src/zexus/syntax_validator.py +356 -0
- package/src/zexus/testing/zpics.py +407 -0
- package/src/zexus/testing/zpics_runtime.py +369 -0
- package/src/zexus/type_system.py +374 -0
- package/src/zexus/validation_system.py +569 -0
- package/src/zexus/virtual_filesystem.py +355 -0
- package/src/zexus/vm/__init__.py +8 -0
- package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +420 -0
- package/src/zexus/vm/bytecode.py +428 -0
- package/src/zexus/vm/bytecode_converter.py +297 -0
- package/src/zexus/vm/cache.py +532 -0
- package/src/zexus/vm/jit.py +720 -0
- package/src/zexus/vm/memory_manager.py +520 -0
- package/src/zexus/vm/memory_pool.py +511 -0
- package/src/zexus/vm/optimizer.py +478 -0
- package/src/zexus/vm/parallel_vm.py +899 -0
- package/src/zexus/vm/peephole_optimizer.py +452 -0
- package/src/zexus/vm/profiler.py +527 -0
- package/src/zexus/vm/register_allocator.py +462 -0
- package/src/zexus/vm/register_vm.py +520 -0
- package/src/zexus/vm/ssa_converter.py +757 -0
- package/src/zexus/vm/vm.py +1392 -0
- package/src/zexus/zexus_ast.py +1782 -0
- package/src/zexus/zexus_token.py +253 -0
- package/src/zexus/zpm/__init__.py +15 -0
- package/src/zexus/zpm/installer.py +116 -0
- package/src/zexus/zpm/package_manager.py +208 -0
- package/src/zexus/zpm/publisher.py +98 -0
- package/src/zexus/zpm/registry.py +110 -0
- package/src/zexus.egg-info/PKG-INFO +2235 -0
- package/src/zexus.egg-info/SOURCES.txt +876 -0
- package/src/zexus.egg-info/dependency_links.txt +1 -0
- package/src/zexus.egg-info/entry_points.txt +3 -0
- package/src/zexus.egg-info/not-zip-safe +1 -0
- package/src/zexus.egg-info/requires.txt +14 -0
- package/src/zexus.egg-info/top_level.txt +2 -0
- package/zexus.json +14 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Instruction-Level Profiler for Zexus VM
|
|
3
|
+
|
|
4
|
+
Provides detailed execution profiling including:
|
|
5
|
+
- Per-instruction execution counts
|
|
6
|
+
- Timing statistics (min/max/avg/p95/p99)
|
|
7
|
+
- Hot loop detection
|
|
8
|
+
- Memory access patterns
|
|
9
|
+
- Branch prediction analysis
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
import json
|
|
14
|
+
from typing import Dict, List, Any, Optional, Tuple, Set
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from collections import defaultdict, Counter
|
|
17
|
+
from enum import Enum
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ProfilingLevel(Enum):
|
|
21
|
+
"""Profiling detail levels"""
|
|
22
|
+
NONE = 0 # No profiling
|
|
23
|
+
BASIC = 1 # Count only
|
|
24
|
+
DETAILED = 2 # Count + timing
|
|
25
|
+
FULL = 3 # Count + timing + memory + branches
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class InstructionStats:
|
|
30
|
+
"""Statistics for a single instruction"""
|
|
31
|
+
opcode: str
|
|
32
|
+
operand: Any
|
|
33
|
+
ip: int
|
|
34
|
+
|
|
35
|
+
# Execution statistics
|
|
36
|
+
count: int = 0
|
|
37
|
+
total_time: float = 0.0
|
|
38
|
+
min_time: float = float('inf')
|
|
39
|
+
max_time: float = 0.0
|
|
40
|
+
|
|
41
|
+
# Timing samples (for percentile calculation)
|
|
42
|
+
timing_samples: List[float] = field(default_factory=list)
|
|
43
|
+
|
|
44
|
+
# Memory tracking
|
|
45
|
+
memory_reads: int = 0
|
|
46
|
+
memory_writes: int = 0
|
|
47
|
+
|
|
48
|
+
# Branch tracking (for jumps)
|
|
49
|
+
branch_taken: int = 0
|
|
50
|
+
branch_not_taken: int = 0
|
|
51
|
+
|
|
52
|
+
def record_execution(self, execution_time: float = 0.0, increment_count: bool = True):
|
|
53
|
+
"""Record a single execution"""
|
|
54
|
+
if increment_count:
|
|
55
|
+
self.count += 1
|
|
56
|
+
if execution_time > 0:
|
|
57
|
+
self.total_time += execution_time
|
|
58
|
+
self.min_time = min(self.min_time, execution_time)
|
|
59
|
+
self.max_time = max(self.max_time, execution_time)
|
|
60
|
+
self.timing_samples.append(execution_time)
|
|
61
|
+
|
|
62
|
+
# Keep sample size manageable (max 10000 samples)
|
|
63
|
+
if len(self.timing_samples) > 10000:
|
|
64
|
+
# Keep percentiles and random samples
|
|
65
|
+
self.timing_samples = sorted(self.timing_samples)
|
|
66
|
+
keep = [self.timing_samples[i] for i in
|
|
67
|
+
[0, len(self.timing_samples)//4, len(self.timing_samples)//2,
|
|
68
|
+
3*len(self.timing_samples)//4, -1]]
|
|
69
|
+
self.timing_samples = keep
|
|
70
|
+
|
|
71
|
+
def avg_time(self) -> float:
|
|
72
|
+
"""Average execution time"""
|
|
73
|
+
return self.total_time / self.count if self.count > 0 else 0.0
|
|
74
|
+
|
|
75
|
+
def percentile(self, p: int) -> float:
|
|
76
|
+
"""Calculate percentile (0-100)"""
|
|
77
|
+
if not self.timing_samples:
|
|
78
|
+
return 0.0
|
|
79
|
+
sorted_samples = sorted(self.timing_samples)
|
|
80
|
+
idx = int(len(sorted_samples) * p / 100)
|
|
81
|
+
idx = min(idx, len(sorted_samples) - 1)
|
|
82
|
+
return sorted_samples[idx]
|
|
83
|
+
|
|
84
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
85
|
+
"""Convert to dictionary for serialization"""
|
|
86
|
+
return {
|
|
87
|
+
'opcode': self.opcode,
|
|
88
|
+
'operand': str(self.operand),
|
|
89
|
+
'ip': self.ip,
|
|
90
|
+
'count': self.count,
|
|
91
|
+
'total_time_ms': self.total_time * 1000,
|
|
92
|
+
'avg_time_us': self.avg_time() * 1_000_000,
|
|
93
|
+
'min_time_us': self.min_time * 1_000_000 if self.min_time != float('inf') else 0,
|
|
94
|
+
'max_time_us': self.max_time * 1_000_000,
|
|
95
|
+
'p50_us': self.percentile(50) * 1_000_000,
|
|
96
|
+
'p95_us': self.percentile(95) * 1_000_000,
|
|
97
|
+
'p99_us': self.percentile(99) * 1_000_000,
|
|
98
|
+
'memory_reads': self.memory_reads,
|
|
99
|
+
'memory_writes': self.memory_writes,
|
|
100
|
+
'branch_taken': self.branch_taken,
|
|
101
|
+
'branch_not_taken': self.branch_not_taken,
|
|
102
|
+
'branch_prediction_rate': self._branch_prediction_rate()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
def _branch_prediction_rate(self) -> float:
|
|
106
|
+
"""Calculate branch prediction success rate (always taken heuristic)"""
|
|
107
|
+
total = self.branch_taken + self.branch_not_taken
|
|
108
|
+
if total == 0:
|
|
109
|
+
return 0.0
|
|
110
|
+
# Simple heuristic: predict always taken
|
|
111
|
+
return (self.branch_taken / total) * 100
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass
|
|
115
|
+
class HotLoop:
|
|
116
|
+
"""Detected hot loop"""
|
|
117
|
+
start_ip: int
|
|
118
|
+
end_ip: int
|
|
119
|
+
iterations: int
|
|
120
|
+
total_time: float = 0.0
|
|
121
|
+
instructions: List[str] = field(default_factory=list)
|
|
122
|
+
|
|
123
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
124
|
+
return {
|
|
125
|
+
'start_ip': self.start_ip,
|
|
126
|
+
'end_ip': self.end_ip,
|
|
127
|
+
'iterations': self.iterations,
|
|
128
|
+
'total_time_ms': self.total_time * 1000,
|
|
129
|
+
'avg_iteration_us': (self.total_time / self.iterations * 1_000_000) if self.iterations > 0 else 0,
|
|
130
|
+
'instruction_count': len(self.instructions),
|
|
131
|
+
'instructions': self.instructions[:10] # First 10 instructions
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class InstructionProfiler:
|
|
136
|
+
"""
|
|
137
|
+
Profiler for VM instruction execution
|
|
138
|
+
|
|
139
|
+
Tracks execution statistics at instruction level with minimal overhead.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
def __init__(self, level: ProfilingLevel = ProfilingLevel.DETAILED):
|
|
143
|
+
self.level = level
|
|
144
|
+
self.enabled = level != ProfilingLevel.NONE
|
|
145
|
+
|
|
146
|
+
# Per-instruction statistics (keyed by instruction pointer)
|
|
147
|
+
self.stats: Dict[int, InstructionStats] = {}
|
|
148
|
+
|
|
149
|
+
# Opcode frequency counter
|
|
150
|
+
self.opcode_counter: Counter = Counter()
|
|
151
|
+
|
|
152
|
+
# Hot loop detection
|
|
153
|
+
self.loops: List[HotLoop] = []
|
|
154
|
+
self._backward_jumps: Dict[Tuple[int, int], int] = defaultdict(int) # (from_ip, to_ip) -> count
|
|
155
|
+
self._loop_start_times: Dict[Tuple[int, int], float] = {}
|
|
156
|
+
|
|
157
|
+
# Global statistics
|
|
158
|
+
self.total_instructions: int = 0
|
|
159
|
+
self.profiling_overhead: float = 0.0
|
|
160
|
+
self.start_time: Optional[float] = None
|
|
161
|
+
self.end_time: Optional[float] = None
|
|
162
|
+
|
|
163
|
+
# Memory access tracking
|
|
164
|
+
self.memory_operations: Set[str] = {
|
|
165
|
+
'LOAD_NAME', 'STORE_NAME', 'LOAD_CONST', 'LOAD_ATTR', 'STORE_ATTR',
|
|
166
|
+
'LOAD_INDEX', 'STORE_INDEX', 'STATE_READ', 'STATE_WRITE'
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# Branch instructions
|
|
170
|
+
self.branch_operations: Set[str] = {
|
|
171
|
+
'JUMP', 'JUMP_IF_FALSE', 'JUMP_IF_TRUE', 'JUMP_FORWARD', 'JUMP_BACKWARD'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
def start(self):
|
|
175
|
+
"""Start profiling session"""
|
|
176
|
+
self.start_time = time.perf_counter()
|
|
177
|
+
self.enabled = True
|
|
178
|
+
|
|
179
|
+
def stop(self):
|
|
180
|
+
"""Stop profiling session"""
|
|
181
|
+
self.end_time = time.perf_counter()
|
|
182
|
+
self.enabled = False
|
|
183
|
+
|
|
184
|
+
def reset(self):
|
|
185
|
+
"""Reset all profiling data"""
|
|
186
|
+
self.stats.clear()
|
|
187
|
+
self.opcode_counter.clear()
|
|
188
|
+
self.loops.clear()
|
|
189
|
+
self._backward_jumps.clear()
|
|
190
|
+
self._loop_start_times.clear()
|
|
191
|
+
self.total_instructions = 0
|
|
192
|
+
self.profiling_overhead = 0.0
|
|
193
|
+
self.start_time = None
|
|
194
|
+
self.end_time = None
|
|
195
|
+
|
|
196
|
+
def record_instruction(
|
|
197
|
+
self,
|
|
198
|
+
ip: int,
|
|
199
|
+
opcode: str,
|
|
200
|
+
operand: Any,
|
|
201
|
+
prev_ip: Optional[int] = None,
|
|
202
|
+
stack_size: int = 0
|
|
203
|
+
):
|
|
204
|
+
"""
|
|
205
|
+
Record execution of an instruction
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
ip: Instruction pointer
|
|
209
|
+
opcode: Operation code
|
|
210
|
+
operand: Operand value
|
|
211
|
+
prev_ip: Previous instruction pointer (for jump detection)
|
|
212
|
+
stack_size: Current stack size
|
|
213
|
+
"""
|
|
214
|
+
if not self.enabled:
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
overhead_start = time.perf_counter()
|
|
218
|
+
|
|
219
|
+
# Update counters
|
|
220
|
+
self.total_instructions += 1
|
|
221
|
+
self.opcode_counter[opcode] += 1
|
|
222
|
+
|
|
223
|
+
# Get or create stats for this instruction
|
|
224
|
+
if ip not in self.stats:
|
|
225
|
+
self.stats[ip] = InstructionStats(opcode=opcode, operand=operand, ip=ip)
|
|
226
|
+
|
|
227
|
+
stat = self.stats[ip]
|
|
228
|
+
|
|
229
|
+
# Only increment count (timing done separately by measure_instruction)
|
|
230
|
+
stat.count += 1
|
|
231
|
+
|
|
232
|
+
# Track memory operations (FULL level only)
|
|
233
|
+
if self.level == ProfilingLevel.FULL:
|
|
234
|
+
if opcode in self.memory_operations:
|
|
235
|
+
if opcode in ('LOAD_NAME', 'LOAD_CONST', 'LOAD_ATTR', 'LOAD_INDEX', 'STATE_READ'):
|
|
236
|
+
stat.memory_reads += 1
|
|
237
|
+
else:
|
|
238
|
+
stat.memory_writes += 1
|
|
239
|
+
|
|
240
|
+
# Track branches and detect hot loops
|
|
241
|
+
if prev_ip is not None and opcode in self.branch_operations:
|
|
242
|
+
# Detect backward jump (potential loop)
|
|
243
|
+
if ip < prev_ip:
|
|
244
|
+
jump_key = (prev_ip, ip)
|
|
245
|
+
self._backward_jumps[jump_key] += 1
|
|
246
|
+
|
|
247
|
+
# Hot loop threshold: >1000 iterations
|
|
248
|
+
if self._backward_jumps[jump_key] == 1:
|
|
249
|
+
self._loop_start_times[jump_key] = time.perf_counter()
|
|
250
|
+
elif self._backward_jumps[jump_key] % 1000 == 0:
|
|
251
|
+
# Record as hot loop
|
|
252
|
+
loop_time = time.perf_counter() - self._loop_start_times.get(jump_key, 0)
|
|
253
|
+
instructions = [self.stats[i].opcode for i in range(ip, prev_ip + 1) if i in self.stats]
|
|
254
|
+
loop = HotLoop(
|
|
255
|
+
start_ip=ip,
|
|
256
|
+
end_ip=prev_ip,
|
|
257
|
+
iterations=self._backward_jumps[jump_key],
|
|
258
|
+
total_time=loop_time,
|
|
259
|
+
instructions=instructions
|
|
260
|
+
)
|
|
261
|
+
# Update or add loop
|
|
262
|
+
existing = next((l for l in self.loops if l.start_ip == ip and l.end_ip == prev_ip), None)
|
|
263
|
+
if existing:
|
|
264
|
+
existing.iterations = loop.iterations
|
|
265
|
+
existing.total_time = loop_time
|
|
266
|
+
else:
|
|
267
|
+
self.loops.append(loop)
|
|
268
|
+
|
|
269
|
+
stat.branch_taken += 1
|
|
270
|
+
else:
|
|
271
|
+
stat.branch_not_taken += 1
|
|
272
|
+
|
|
273
|
+
# Minimal overhead tracking for non-FULL levels
|
|
274
|
+
self.profiling_overhead += (time.perf_counter() - overhead_start)
|
|
275
|
+
|
|
276
|
+
def measure_instruction(self, ip: int, execution_time: float):
|
|
277
|
+
"""
|
|
278
|
+
Record execution time for an instruction
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
ip: Instruction pointer
|
|
282
|
+
execution_time: Time taken to execute (seconds)
|
|
283
|
+
"""
|
|
284
|
+
if not self.enabled or self.level == ProfilingLevel.BASIC:
|
|
285
|
+
return
|
|
286
|
+
|
|
287
|
+
if ip in self.stats:
|
|
288
|
+
overhead_start = time.perf_counter()
|
|
289
|
+
# Don't increment count - that was already done by record_instruction
|
|
290
|
+
self.stats[ip].record_execution(execution_time, increment_count=False)
|
|
291
|
+
self.profiling_overhead += (time.perf_counter() - overhead_start)
|
|
292
|
+
|
|
293
|
+
def get_hottest_instructions(self, top_n: int = 10) -> List[InstructionStats]:
|
|
294
|
+
"""Get top N hottest instructions by execution count"""
|
|
295
|
+
return sorted(self.stats.values(), key=lambda s: s.count, reverse=True)[:top_n]
|
|
296
|
+
|
|
297
|
+
def get_slowest_instructions(self, top_n: int = 10) -> List[InstructionStats]:
|
|
298
|
+
"""Get top N slowest instructions by total time"""
|
|
299
|
+
return sorted(self.stats.values(), key=lambda s: s.total_time, reverse=True)[:top_n]
|
|
300
|
+
|
|
301
|
+
def get_hot_loops(self, min_iterations: int = 1000) -> List[HotLoop]:
|
|
302
|
+
"""Get hot loops (loops executed many times)"""
|
|
303
|
+
return [loop for loop in self.loops if loop.iterations >= min_iterations]
|
|
304
|
+
|
|
305
|
+
def get_summary(self) -> Dict[str, Any]:
|
|
306
|
+
"""Get profiling summary statistics"""
|
|
307
|
+
if not self.stats:
|
|
308
|
+
return {
|
|
309
|
+
'profiling_level': self.level.name,
|
|
310
|
+
'total_instructions': 0,
|
|
311
|
+
'unique_instructions': 0,
|
|
312
|
+
'total_time_sec': 0,
|
|
313
|
+
'instructions_per_sec': 0,
|
|
314
|
+
'profiling_overhead_ms': 0,
|
|
315
|
+
'overhead_percentage': 0,
|
|
316
|
+
'hot_loops_detected': 0,
|
|
317
|
+
'most_common_opcodes': {}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
total_time = (self.end_time or time.perf_counter()) - (self.start_time or 0)
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
'profiling_level': self.level.name,
|
|
324
|
+
'total_instructions': self.total_instructions,
|
|
325
|
+
'unique_instructions': len(self.stats),
|
|
326
|
+
'total_time_sec': total_time,
|
|
327
|
+
'instructions_per_sec': self.total_instructions / total_time if total_time > 0 else 0,
|
|
328
|
+
'profiling_overhead_ms': self.profiling_overhead * 1000,
|
|
329
|
+
'overhead_percentage': (self.profiling_overhead / total_time * 100) if total_time > 0 else 0,
|
|
330
|
+
'hot_loops_detected': len(self.loops),
|
|
331
|
+
'most_common_opcodes': dict(self.opcode_counter.most_common(10))
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
def generate_report(self, format: str = 'text', top_n: int = 20) -> str:
|
|
335
|
+
"""
|
|
336
|
+
Generate profiling report
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
format: Output format ('text', 'json', 'html')
|
|
340
|
+
top_n: Number of top items to include
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
Formatted report string
|
|
344
|
+
"""
|
|
345
|
+
if format == 'json':
|
|
346
|
+
return self._generate_json_report(top_n)
|
|
347
|
+
elif format == 'html':
|
|
348
|
+
return self._generate_html_report(top_n)
|
|
349
|
+
else:
|
|
350
|
+
return self._generate_text_report(top_n)
|
|
351
|
+
|
|
352
|
+
def _generate_text_report(self, top_n: int) -> str:
|
|
353
|
+
"""Generate text format report"""
|
|
354
|
+
summary = self.get_summary()
|
|
355
|
+
hottest = self.get_hottest_instructions(top_n)
|
|
356
|
+
slowest = self.get_slowest_instructions(top_n)
|
|
357
|
+
hot_loops = self.get_hot_loops()
|
|
358
|
+
|
|
359
|
+
lines = [
|
|
360
|
+
"=" * 80,
|
|
361
|
+
"ZEXUS VM INSTRUCTION PROFILING REPORT",
|
|
362
|
+
"=" * 80,
|
|
363
|
+
"",
|
|
364
|
+
"SUMMARY",
|
|
365
|
+
"-" * 80,
|
|
366
|
+
f"Profiling Level: {summary['profiling_level']}",
|
|
367
|
+
f"Total Instructions: {summary['total_instructions']:,}",
|
|
368
|
+
f"Unique Instructions: {summary['unique_instructions']:,}",
|
|
369
|
+
f"Total Time: {summary['total_time_sec']:.4f} seconds",
|
|
370
|
+
f"Instructions/Second: {summary['instructions_per_sec']:,.0f}",
|
|
371
|
+
f"Profiling Overhead: {summary['overhead_percentage']:.2f}% ({summary['profiling_overhead_ms']:.2f}ms)",
|
|
372
|
+
f"Hot Loops Detected: {summary['hot_loops_detected']}",
|
|
373
|
+
"",
|
|
374
|
+
"MOST COMMON OPCODES",
|
|
375
|
+
"-" * 80,
|
|
376
|
+
]
|
|
377
|
+
|
|
378
|
+
for opcode, count in summary['most_common_opcodes'].items():
|
|
379
|
+
pct = (count / summary['total_instructions'] * 100) if summary['total_instructions'] > 0 else 0
|
|
380
|
+
lines.append(f" {opcode:20} {count:10,} ({pct:5.1f}%)")
|
|
381
|
+
|
|
382
|
+
lines.extend([
|
|
383
|
+
"",
|
|
384
|
+
f"TOP {top_n} HOTTEST INSTRUCTIONS (by count)",
|
|
385
|
+
"-" * 80,
|
|
386
|
+
f"{'IP':>6} {'Opcode':20} {'Count':>12} {'Avg (μs)':>12} {'Total (ms)':>12}",
|
|
387
|
+
"-" * 80,
|
|
388
|
+
])
|
|
389
|
+
|
|
390
|
+
for stat in hottest:
|
|
391
|
+
lines.append(
|
|
392
|
+
f"{stat.ip:6} {stat.opcode:20} {stat.count:12,} "
|
|
393
|
+
f"{stat.avg_time() * 1_000_000:12.2f} {stat.total_time * 1000:12.2f}"
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
if self.level in (ProfilingLevel.DETAILED, ProfilingLevel.FULL):
|
|
397
|
+
lines.extend([
|
|
398
|
+
"",
|
|
399
|
+
f"TOP {top_n} SLOWEST INSTRUCTIONS (by total time)",
|
|
400
|
+
"-" * 80,
|
|
401
|
+
f"{'IP':>6} {'Opcode':20} {'Total (ms)':>12} {'Count':>12} {'Avg (μs)':>12}",
|
|
402
|
+
"-" * 80,
|
|
403
|
+
])
|
|
404
|
+
|
|
405
|
+
for stat in slowest:
|
|
406
|
+
lines.append(
|
|
407
|
+
f"{stat.ip:6} {stat.opcode:20} {stat.total_time * 1000:12.2f} "
|
|
408
|
+
f"{stat.count:12,} {stat.avg_time() * 1_000_000:12.2f}"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
if hot_loops:
|
|
412
|
+
lines.extend([
|
|
413
|
+
"",
|
|
414
|
+
"HOT LOOPS (>1000 iterations)",
|
|
415
|
+
"-" * 80,
|
|
416
|
+
f"{'Start':>6} {'End':>6} {'Iterations':>12} {'Total (ms)':>12} {'Avg/iter (μs)':>15}",
|
|
417
|
+
"-" * 80,
|
|
418
|
+
])
|
|
419
|
+
|
|
420
|
+
for loop in sorted(hot_loops, key=lambda l: l.iterations, reverse=True):
|
|
421
|
+
avg_iter = (loop.total_time / loop.iterations * 1_000_000) if loop.iterations > 0 else 0
|
|
422
|
+
lines.append(
|
|
423
|
+
f"{loop.start_ip:6} {loop.end_ip:6} {loop.iterations:12,} "
|
|
424
|
+
f"{loop.total_time * 1000:12.2f} {avg_iter:15.2f}"
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
lines.extend([
|
|
428
|
+
"",
|
|
429
|
+
"=" * 80,
|
|
430
|
+
])
|
|
431
|
+
|
|
432
|
+
return "\n".join(lines)
|
|
433
|
+
|
|
434
|
+
def _generate_json_report(self, top_n: int) -> str:
|
|
435
|
+
"""Generate JSON format report"""
|
|
436
|
+
return json.dumps({
|
|
437
|
+
'summary': self.get_summary(),
|
|
438
|
+
'hottest_instructions': [s.to_dict() for s in self.get_hottest_instructions(top_n)],
|
|
439
|
+
'slowest_instructions': [s.to_dict() for s in self.get_slowest_instructions(top_n)],
|
|
440
|
+
'hot_loops': [l.to_dict() for l in self.get_hot_loops()],
|
|
441
|
+
'opcode_distribution': dict(self.opcode_counter)
|
|
442
|
+
}, indent=2)
|
|
443
|
+
|
|
444
|
+
def _generate_html_report(self, top_n: int) -> str:
|
|
445
|
+
"""Generate HTML format report"""
|
|
446
|
+
summary = self.get_summary()
|
|
447
|
+
|
|
448
|
+
html = f"""
|
|
449
|
+
<!DOCTYPE html>
|
|
450
|
+
<html>
|
|
451
|
+
<head>
|
|
452
|
+
<title>Zexus VM Profiling Report</title>
|
|
453
|
+
<style>
|
|
454
|
+
body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
|
|
455
|
+
.container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }}
|
|
456
|
+
h1 {{ color: #333; border-bottom: 3px solid #4CAF50; padding-bottom: 10px; }}
|
|
457
|
+
h2 {{ color: #555; margin-top: 30px; border-bottom: 2px solid #ddd; padding-bottom: 5px; }}
|
|
458
|
+
table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
|
|
459
|
+
th, td {{ padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }}
|
|
460
|
+
th {{ background: #4CAF50; color: white; }}
|
|
461
|
+
tr:hover {{ background: #f5f5f5; }}
|
|
462
|
+
.summary {{ display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin: 20px 0; }}
|
|
463
|
+
.summary-item {{ background: #f9f9f9; padding: 15px; border-left: 4px solid #4CAF50; }}
|
|
464
|
+
.summary-item strong {{ display: block; color: #333; margin-bottom: 5px; }}
|
|
465
|
+
</style>
|
|
466
|
+
</head>
|
|
467
|
+
<body>
|
|
468
|
+
<div class="container">
|
|
469
|
+
<h1>🔍 Zexus VM Instruction Profiling Report</h1>
|
|
470
|
+
|
|
471
|
+
<h2>Summary</h2>
|
|
472
|
+
<div class="summary">
|
|
473
|
+
<div class="summary-item">
|
|
474
|
+
<strong>Total Instructions</strong>
|
|
475
|
+
{summary['total_instructions']:,}
|
|
476
|
+
</div>
|
|
477
|
+
<div class="summary-item">
|
|
478
|
+
<strong>Unique Instructions</strong>
|
|
479
|
+
{summary['unique_instructions']:,}
|
|
480
|
+
</div>
|
|
481
|
+
<div class="summary-item">
|
|
482
|
+
<strong>Total Time</strong>
|
|
483
|
+
{summary['total_time_sec']:.4f} seconds
|
|
484
|
+
</div>
|
|
485
|
+
<div class="summary-item">
|
|
486
|
+
<strong>Instructions/Second</strong>
|
|
487
|
+
{summary['instructions_per_sec']:,.0f}
|
|
488
|
+
</div>
|
|
489
|
+
<div class="summary-item">
|
|
490
|
+
<strong>Profiling Overhead</strong>
|
|
491
|
+
{summary['overhead_percentage']:.2f}%
|
|
492
|
+
</div>
|
|
493
|
+
<div class="summary-item">
|
|
494
|
+
<strong>Hot Loops Detected</strong>
|
|
495
|
+
{summary['hot_loops_detected']}
|
|
496
|
+
</div>
|
|
497
|
+
</div>
|
|
498
|
+
|
|
499
|
+
<h2>Top {top_n} Hottest Instructions</h2>
|
|
500
|
+
<table>
|
|
501
|
+
<tr>
|
|
502
|
+
<th>IP</th>
|
|
503
|
+
<th>Opcode</th>
|
|
504
|
+
<th>Count</th>
|
|
505
|
+
<th>Avg (μs)</th>
|
|
506
|
+
<th>Total (ms)</th>
|
|
507
|
+
</tr>
|
|
508
|
+
"""
|
|
509
|
+
|
|
510
|
+
for stat in self.get_hottest_instructions(top_n):
|
|
511
|
+
html += f"""
|
|
512
|
+
<tr>
|
|
513
|
+
<td>{stat.ip}</td>
|
|
514
|
+
<td>{stat.opcode}</td>
|
|
515
|
+
<td>{stat.count:,}</td>
|
|
516
|
+
<td>{stat.avg_time() * 1_000_000:.2f}</td>
|
|
517
|
+
<td>{stat.total_time * 1000:.2f}</td>
|
|
518
|
+
</tr>
|
|
519
|
+
"""
|
|
520
|
+
|
|
521
|
+
html += """
|
|
522
|
+
</table>
|
|
523
|
+
</div>
|
|
524
|
+
</body>
|
|
525
|
+
</html>
|
|
526
|
+
"""
|
|
527
|
+
return html
|