Skip to main content
โšก Calmops

Performance Optimization: Profiling and Optimization Techniques

Introduction

Performance optimization requires understanding where time is spent and making targeted improvements. This guide covers profiling techniques, common bottlenecks, and optimization strategies.

First, measure. Then optimize.

Profiling

Python Profiling

import cProfile
import pstats
from io import StringIO

def profile_function(func, *args, **kwargs):
    """Profile a function."""
    profiler = cProfile.Profile()
    profiler.enable()
    
    result = func(*args, **kwargs)
    
    profiler.disable()
    
    # Print stats
    s = StringIO()
    ps = pstats.Stats(profiler, stream=s).sort_stats('cumulative')
    ps.print_stats(20)
    
    print(s.getvalue())
    
    return result

# Using line_profiler
# pip install line_profiler
# @profile decorator

from line_profiler import LineProfiler

def slow_function():
    result = 0
    for i in range(10000):
        result += i ** 2
    return result

# Run with: kernprof -l -v script.py

JavaScript Profiling

// Chrome DevTools Profiling
// 1. Open DevTools
// 2. Performance tab
// 3. Click Record
// 4. Perform actions
// 5. Stop and analyze

// Programmatic profiling
console.time('myOperation');
// Do operation
console.timeEnd('myOperation');

// Performance Mark
performance.mark('operation-start');
// Do operation
performance.mark('operation-end');
performance.measure('operation', 'operation-start', 'operation-end');

Common Bottlenecks

Database Queries

# โŒ N+1 Query Problem
def get_users_with_posts():
    users = db.query(User).all()
    
    for user in users:
        # This runs N queries!
        posts = db.query(Post).filter_by(user_id=user.id).all()
        user.posts = posts
    
    return users

# โœ… Optimized
def get_users_with_posts():
    # Eager loading
    users = db.query(User).options(
        joinedload(User.posts)
    ).all()
    
    return users

Caching

# โŒ Repeated expensive computation
def calculate_total(order_id):
    order = get_order(order_id)
    total = 0
    for item in order.items:
        # Recalculates tax every time!
        tax = calculate_tax(item.price)
        total += item.price + tax
    return total

# โœ… Cached
from functools import lru_cache

@lru_cache(maxsize=1000)
def get_tax_rate(state):
    # Expensive lookup - now cached
    return database.query_tax_rate(state)

Benchmarking

import timeit

def slow_way():
    result = []
    for i in range(1000):
        if i % 2 == 0:
            result.append(i)
    return result

def fast_way():
    return [i for i in range(1000) if i % 2 == 0]

# Benchmark
slow_time = timeit.timeit(slow_way, number=10000)
fast_time = timeit.timeit(fast_way, number=10000)

print(f"Slow: {slow_time:.3f}s")
print(f"Fast: {fast_time:.3f}s")
print(f"Speedup: {slow_time/fast_time:.1f}x")

Optimization Techniques

Algorithm Optimization

# โŒ O(nยฒ) - Nested loops
def find_duplicates_slow(items):
    duplicates = []
    for i in range(len(items)):
        for j in range(i + 1, len(items)):
            if items[i] == items[j]:
                duplicates.append(items[i])
    return duplicates

# โœ… O(n) - Using set
def find_duplicates_fast(items):
    seen = set()
    duplicates = []
    
    for item in items:
        if item in seen:
            duplicates.append(item)
        seen.add(item)
    
    return duplicates

Lazy Evaluation

# โŒ Eager loading - load everything
def get_top_users():
    all_users = db.query(User).all()  # Load all!
    return sorted(all_users, key=lambda u: u.score)[:10]

# โœ… Lazy - only load what we need
def get_top_users():
    return db.query(User).order_by(
        User.score.desc()
    ).limit(10).all()

Database Optimization

Indexing

-- Create index for frequently queried column
CREATE INDEX idx_users_email ON users(email);

-- Composite index for multi-column queries
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at DESC);

-- Partial index for specific queries
CREATE INDEX idx_active_orders ON orders(user_id) 
WHERE status = 'active';

-- Analyze query plan
EXPLAIN ANALYZE SELECT * FROM users WHERE email = '[email protected]';

Best Practices

  1. Measure first: Don’t optimize without data
  2. Profile in production-like environment: Staging isn’t enough
  3. Optimize the biggest bottleneck: Small gains elsewhere don’t matter
  4. Verify improvements: Measure after changes
  5. Document trade-offs: Optimizations often have costs

Conclusion

Performance optimization is about finding and fixing the actual bottlenecks. Use profiling tools to identify where time is spent, then make targeted improvements. Always measure before and after.

Resources

Comments