Optimization Guide
Epochly Optimization Guide: Workload Analysis
How to analyze your Python workloads to predict which enhancement levels will apply and expected performance gains.
How to analyze workloads for optimal Epochly optimization.
Overview
Understanding your workload type is essential for choosing the right enhancement level:
| Workload Type | Characteristic | Recommended Level |
|---|---|---|
| I/O-bound | Waiting for external resources | Level 1 |
| CPU-bound loops | Numerical computation | Level 2 |
| Data-parallel | Independent computations | Level 3 |
| Large arrays | Massive parallelism needed | Level 4 |
Identifying Workload Type
I/O-Bound Workloads
Characteristics:
- Time spent waiting for network, disk, database
- Low CPU utilization during execution
- Performance limited by external resource latency
# I/O-bound: network requestsdef fetch_data(urls):return [requests.get(url) for url in urls]# I/O-bound: file operationsdef read_files(paths):return [open(p).read() for p in paths]# I/O-bound: database queriesdef query_db(queries):return [db.execute(q) for q in queries]
CPU-Bound Workloads
Characteristics:
- High CPU utilization
- Time spent in computation
- Limited by processing speed
# CPU-bound: numerical computationdef compute_heavy(data):result = 0for x in data:result += x ** 2 + x ** 0.5return result# CPU-bound: data transformationdef transform(records):return [complex_transform(r) for r in records]
Memory-Bound Workloads
Characteristics:
- Large data sets
- Performance limited by memory bandwidth
- CPU often waiting for memory
# Memory-bound: large array accessdef memory_heavy(large_array):return [arr[i:i+1000].sum() for i in range(0, len(arr), 1000)]
Using Profiling Tools
Epochly Built-in Profiling
import epochly# Enable monitoringepochly.set_level(0)with epochly.monitoring_context() as metrics:result = my_function(data)# Analyze workloadprint(f"CPU time: {metrics.get('cpu_time_ms')} ms")print(f"Wait time: {metrics.get('wait_time_ms')} ms")print(f"Memory peak: {metrics.get('memory_peak_mb')} MB")# Determine typecpu_ratio = metrics.get('cpu_time_ms') / metrics.get('total_time_ms')if cpu_ratio > 0.8:print("CPU-bound: use Level 2 or 3")elif cpu_ratio < 0.3:print("I/O-bound: use Level 1")else:print("Mixed workload")
Python cProfile
import cProfileimport pstatsdef analyze_with_cprofile():profiler = cProfile.Profile()profiler.enable()result = my_function(data)profiler.disable()stats = pstats.Stats(profiler)stats.sort_stats('cumulative')stats.print_stats(10) # Top 10 functions
line_profiler
# Install: pip install line_profiler@profile # Use with kernprof -l -v script.pydef my_function(data):result = []for x in data: # Line-by-line timingresult.append(x ** 2)return result
Interpreting Epochly Metrics
Key Metrics
| Metric | Meaning | Optimization Hint |
|---|---|---|
High cpu_time | CPU-bound | Level 2 or 3 |
High wait_time | I/O-bound | Level 1 |
High memory_peak | Memory-bound | Batch processing |
Many loop_iterations | Hot loops | Level 2 |
Large data_size | Parallelizable | Level 3 or 4 |
Example Analysis
import epochly@epochly.optimize(level=0)def analyze_me(data):return process(data)# Run multiple times to gather statsfor _ in range(100):analyze_me(test_data)metrics = epochly.get_metrics()# Analyzeif metrics.get('avg_loop_iterations', 0) > 10000:print("Hot loops detected - consider Level 2")if metrics.get('avg_data_size', 0) > 1_000_000:print("Large data - consider Level 3 or 4")if metrics.get('io_wait_ratio', 0) > 0.5:print("I/O-bound - consider Level 1")
Optimization Strategy Selection
Decision Tree
Start│├─ Is it I/O-bound? (network, disk, DB)│ └─ YES → Level 1 (Threading)│├─ Is it CPU-bound with hot loops?│ └─ YES → Level 2 (JIT)│├─ Is data large and parallelizable?│ └─ YES → Level 3 (Multicore)│├─ Are there large array operations?│ └─ YES → Level 4 (GPU) [if licensed]│└─ Mixed or unclear → Start with Level 0, analyze
Code-Based Decision
import epochlydef select_optimal_level(workload_metrics):"""Select optimal level based on workload analysis."""io_ratio = workload_metrics.get('io_wait_ratio', 0)loop_iters = workload_metrics.get('avg_loop_iterations', 0)data_size = workload_metrics.get('avg_data_size', 0)if io_ratio > 0.5:return 1 # I/O-boundelif loop_iters > 10000:if data_size > 10_000_000 and epochly.check_feature('gpu_acceleration'):return 4 # GPU for large arrayselif data_size > 100_000:return 3 # Parallel for large dataelse:return 2 # JIT for hot loopselif data_size > 100_000:return 3 # Parallel for large dataelse:return 0 # Monitor only (not enough work)
Benchmarking Levels
Comparative Benchmarking
import epochlyimport timedef benchmark_levels(func, data, levels=[0, 1, 2, 3]):results = {}for level in levels:with epochly.optimize_context(level=level):# Warmupfunc(data)# Measurestart = time.perf_counter()for _ in range(10):func(data)elapsed = time.perf_counter() - startresults[level] = elapsed / 10return results# Comparetimings = benchmark_levels(my_function, test_data)print("Level | Time (s) | Speedup")baseline = timings[0]for level, t in sorted(timings.items()):speedup = baseline / t if t > 0 else 0print(f" {level} | {t:.4f} | {speedup:.2f}x")
Common Patterns
Pattern: API Client
# I/O-bound: use Level 1@epochly.optimize(level=1)def api_client(endpoints):return [call_api(ep) for ep in endpoints]
Pattern: Data Pipeline
# Mixed: Level 1 for I/O, Level 2 for transformdef data_pipeline(sources):with epochly.optimize_context(level=1):raw_data = [fetch(s) for s in sources]with epochly.optimize_context(level=2):transformed = [transform(d) for d in raw_data]return transformed
Pattern: Scientific Computing
# CPU-bound with large arrays: Level 3 or 4@epochly.optimize(level=3)def scientific_compute(matrix):# Parallel processing for matrix operationsreturn complex_calculation(matrix)