Skip to content

Profiling

Profiling provides comprehensive performance analysis and optimization tools for your InjectQ dependency injection container and services.

📊 Performance Profiling

Container Profiling

from injectq.profiling import ContainerProfiler

# Profile container performance
profiler = ContainerProfiler(container)

# Profile service resolution
with profiler.profile_resolution(SomeService) as profile:
    service = container.get(SomeService)

# Get profiling results
results = profile.get_results()
print("Resolution Profile:")
print(f"- Total time: {results.total_time}ms")
print(f"- Initialization time: {results.init_time}ms")
print(f"- Dependency resolution time: {results.dep_resolution_time}ms")
print(f"- Memory usage: {results.memory_usage} bytes")
print(f"- Cache hits: {results.cache_hits}")

# Profile multiple resolutions
batch_profile = profiler.profile_batch_resolutions(
    [ServiceA, ServiceB, ServiceC],
    iterations=100
)
print("Batch Resolution Profile:")
for service_type, result in batch_profile.items():
    print(f"- {service_type.__name__}: {result.avg_time}ms avg")

Memory Profiling

from injectq.profiling import MemoryProfiler

# Profile memory usage
memory_profiler = MemoryProfiler(container)

# Profile memory usage during resolution
with memory_profiler.profile_memory(SomeService) as mem_profile:
    service = container.get(SomeService)

memory_results = mem_profile.get_results()
print("Memory Profile:")
print(f"- Peak memory usage: {memory_results.peak_memory} bytes")
print(f"- Memory growth: {memory_results.memory_growth} bytes")
print(f"- Objects created: {memory_results.objects_created}")
print(f"- Memory leaks detected: {memory_results.memory_leaks}")

# Profile memory over time
memory_timeline = memory_profiler.profile_memory_timeline(
    operations=[
        lambda: container.get(ServiceA),
        lambda: container.get(ServiceB),
        lambda: container.clear_cache()
    ]
)

print("Memory Timeline:")
for timestamp, memory in memory_timeline:
    print(f"- {timestamp}: {memory} bytes")

CPU Profiling

from injectq.profiling import CPUProfiler

# Profile CPU usage
cpu_profiler = CPUProfiler(container)

# Profile CPU usage during resolution
with cpu_profiler.profile_cpu(SomeService) as cpu_profile:
    service = container.get(SomeService)

cpu_results = cpu_profile.get_results()
print("CPU Profile:")
print(f"- CPU time: {cpu_results.cpu_time}ms")
print(f"- User time: {cpu_results.user_time}ms")
print(f"- System time: {cpu_results.system_time}ms")
print(f"- CPU utilization: {cpu_results.cpu_utilization}%")

# Profile CPU bottlenecks
bottlenecks = cpu_profiler.identify_bottlenecks()
print("CPU Bottlenecks:")
for bottleneck in bottlenecks:
    print(f"- {bottleneck.location}: {bottleneck.cpu_time}ms ({bottleneck.percentage}%)")

🔍 Dependency Profiling

Dependency Chain Analysis

from injectq.profiling import DependencyProfiler

# Profile dependency chains
dep_profiler = DependencyProfiler(container)

# Analyze dependency chain
chain_analysis = dep_profiler.analyze_chain(SomeService)
print("Dependency Chain Analysis:")
print(f"- Chain length: {chain_analysis.length}")
print(f"- Total dependencies: {chain_analysis.total_deps}")
print(f"- Circular dependencies: {chain_analysis.circular_deps}")
print(f"- Resolution time: {chain_analysis.resolution_time}ms")

# Print dependency tree
dep_profiler.print_dependency_tree(SomeService)

# Find optimization opportunities
optimizations = dep_profiler.find_optimizations()
print("Optimization Opportunities:")
for opt in optimizations:
    print(f"- {opt.type}: {opt.description}")
    print(f"  Potential improvement: {opt.improvement}%")

Resolution Path Profiling

# Profile resolution paths
class ResolutionPathProfiler:
    """Profile different resolution paths."""

    def __init__(self, container):
        self.container = container
        self.paths = {}

    def profile_resolution_path(self, service_type, path_name: str):
        """Profile a specific resolution path."""
        import time

        start_time = time.time()
        start_memory = self.get_memory_usage()

        # Resolve service
        service = self.container.get(service_type)

        end_time = time.time()
        end_memory = self.get_memory_usage()

        path_profile = {
            "service_type": service_type,
            "resolution_time": (end_time - start_time) * 1000,
            "memory_usage": end_memory - start_memory,
            "path_name": path_name
        }

        self.paths[path_name] = path_profile
        return path_profile

    def compare_paths(self, path1: str, path2: str):
        """Compare two resolution paths."""
        if path1 not in self.paths or path2 not in self.paths:
            return None

        p1 = self.paths[path1]
        p2 = self.paths[path2]

        comparison = {
            "time_difference": p2["resolution_time"] - p1["resolution_time"],
            "memory_difference": p2["memory_usage"] - p1["memory_usage"],
            "faster_path": path1 if p1["resolution_time"] < p2["resolution_time"] else path2,
            "more_memory_efficient": path1 if p1["memory_usage"] < p2["memory_usage"] else path2
        }

        return comparison

    def get_memory_usage(self):
        """Get current memory usage."""
        import psutil
        import os
        process = psutil.Process(os.getpid())
        return process.memory_info().rss

# Usage
path_profiler = ResolutionPathProfiler(container)

# Profile different resolution strategies
singleton_path = path_profiler.profile_resolution_path(SingletonService, "singleton")
scoped_path = path_profiler.profile_resolution_path(ScopedService, "scoped")
transient_path = path_profiler.profile_resolution_path(TransientService, "transient")

# Compare paths
comparison = path_profiler.compare_paths("singleton", "transient")
print("Path Comparison:")
print(f"- Time difference: {comparison['time_difference']}ms")
print(f"- Memory difference: {comparison['memory_difference']} bytes")
print(f"- Faster path: {comparison['faster_path']}")
print(f"- More memory efficient: {comparison['more_memory_efficient']}")

📈 Performance Metrics

Real-time Metrics Collection

from injectq.profiling import MetricsCollector

# Collect real-time performance metrics
metrics_collector = MetricsCollector(container)

# Start metrics collection
metrics_collector.start_collection(interval_seconds=5)

# Perform operations
for i in range(100):
    service = container.get(SomeService)
    # Use service...

# Stop collection and get report
metrics_collector.stop_collection()
report = metrics_collector.get_report()

print("Performance Metrics Report:")
print(f"- Total resolutions: {report.total_resolutions}")
print(f"- Average resolution time: {report.avg_resolution_time}ms")
print(f"- Peak resolution time: {report.peak_resolution_time}ms")
print(f"- Memory usage trend: {report.memory_trend}")
print(f"- Cache hit rate: {report.cache_hit_rate}%")

# Export metrics
metrics_collector.export_metrics("performance_metrics.json")

Custom Metrics

from injectq.profiling import CustomMetrics

# Define custom performance metrics
custom_metrics = CustomMetrics()

# Define metric
@custom_metrics.metric("service_initialization_time")
def measure_service_init(service_type):
    """Measure service initialization time."""
    import time
    start_time = time.time()

    # Service initialization logic
    service = container.get(service_type)

    end_time = time.time()
    return (end_time - start_time) * 1000  # ms

# Define another metric
@custom_metrics.metric("dependency_count")
def count_dependencies(service_type):
    """Count number of dependencies for a service."""
    # This would analyze the service's dependencies
    return len(container.get_dependencies(service_type))

# Collect custom metrics
results = custom_metrics.collect_metrics({
    "service_init_time": lambda: measure_service_init(SomeService),
    "dep_count": lambda: count_dependencies(SomeService)
})

print("Custom Metrics:")
for metric_name, value in results.items():
    print(f"- {metric_name}: {value}")

Performance Baselines

from injectq.profiling import PerformanceBaseline

# Establish performance baselines
baseline = PerformanceBaseline(container)

# Establish baseline for service resolution
resolution_baseline = baseline.establish_baseline(
    operation=lambda: container.get(SomeService),
    iterations=1000
)

print("Resolution Baseline:")
print(f"- Average time: {resolution_baseline.avg_time}ms")
print(f"- Standard deviation: {resolution_baseline.std_dev}ms")
print(f"- 95th percentile: {resolution_baseline.percentile_95}ms")

# Monitor against baseline
monitoring_results = baseline.monitor_against_baseline(
    operation=lambda: container.get(SomeService),
    iterations=100
)

print("Baseline Monitoring:")
print(f"- Within baseline: {monitoring_results.within_baseline}")
print(f"- Deviation: {monitoring_results.deviation}%")
if monitoring_results.regression_detected:
    print("⚠️  Performance regression detected!")
    print(f"Regression magnitude: {monitoring_results.regression_magnitude}%")

🐛 Bottleneck Analysis

Automatic Bottleneck Detection

from injectq.profiling import BottleneckAnalyzer

# Analyze performance bottlenecks
analyzer = BottleneckAnalyzer(container)

# Analyze resolution bottlenecks
bottlenecks = analyzer.analyze_resolution_bottlenecks(SomeService)
print("Resolution Bottlenecks:")
for bottleneck in bottlenecks:
    print(f"- {bottleneck.component}: {bottleneck.impact}% impact")
    print(f"  Description: {bottleneck.description}")
    print(f"  Recommendation: {bottleneck.recommendation}")

# Analyze memory bottlenecks
memory_bottlenecks = analyzer.analyze_memory_bottlenecks()
print("Memory Bottlenecks:")
for bottleneck in memory_bottlenecks:
    print(f"- {bottleneck.type}: {bottleneck.memory_usage} bytes")
    print(f"  Recommendation: {bottleneck.recommendation}")

# Generate optimization report
optimization_report = analyzer.generate_optimization_report()
print("Optimization Report:")
print(optimization_report.summary)
for recommendation in optimization_report.recommendations:
    print(f"- {recommendation}")

Hot Path Analysis

from injectq.profiling import HotPathAnalyzer

# Analyze frequently used code paths
hot_path_analyzer = HotPathAnalyzer(container)

# Identify hot paths
hot_paths = hot_path_analyzer.identify_hot_paths()
print("Hot Paths:")
for path in hot_paths:
    print(f"- {path.name}: {path.call_count} calls")
    print(f"  Total time: {path.total_time}ms")
    print(f"  Average time: {path.avg_time}ms")

# Optimize hot paths
optimizations = hot_path_analyzer.optimize_hot_paths()
print("Hot Path Optimizations:")
for optimization in optimizations:
    print(f"- {optimization.path}: {optimization.improvement}% improvement")
    print(f"  Optimization: {optimization.description}")

📊 Profiling Reports

HTML Report Generation

from injectq.profiling import HTMLReportGenerator

# Generate HTML profiling reports
report_generator = HTMLReportGenerator(container)

# Generate comprehensive report
report = report_generator.generate_comprehensive_report(
    services=[ServiceA, ServiceB, ServiceC],
    include_memory=True,
    include_cpu=True,
    include_dependencies=True
)

# Save report
report_generator.save_report(report, "profiling_report.html")

# Generate summary report
summary_report = report_generator.generate_summary_report()
report_generator.save_report(summary_report, "profiling_summary.html")

JSON Export

from injectq.profiling import JSONExporter

# Export profiling data as JSON
exporter = JSONExporter(container)

# Export profiling session
profiling_data = exporter.export_profiling_session(
    session_name="comprehensive_analysis",
    include_metrics=True,
    include_bottlenecks=True,
    include_recommendations=True
)

# Save to file
exporter.save_to_file(profiling_data, "profiling_data.json")

# Export specific metrics
metrics_data = exporter.export_metrics(
    metrics=["resolution_time", "memory_usage", "cache_hit_rate"]
)
exporter.save_to_file(metrics_data, "metrics_data.json")

Performance Comparison Reports

from injectq.profiling import PerformanceComparator

# Compare performance across different configurations
comparator = PerformanceComparator()

# Compare different container configurations
configs = {
    "default": lambda: InjectQ(),
    "optimized": lambda: InjectQ(config=OptimizedConfig()),
    "minimal": lambda: InjectQ(config=MinimalConfig())
}

comparison_results = comparator.compare_configurations(
    configs=configs,
    test_operation=lambda c: c.get(SomeService),
    iterations=1000
)

print("Configuration Comparison:")
for config_name, results in comparison_results.items():
    print(f"- {config_name}:")
    print(f"  Average time: {results.avg_time}ms")
    print(f"  Memory usage: {results.memory_usage} bytes")
    print(f"  Performance rank: {results.rank}")

# Compare before/after optimization
before_results = comparator.measure_performance(
    container=lambda: create_container_before_optimization(),
    operation=lambda c: c.get(SomeService),
    iterations=1000
)

after_results = comparator.measure_performance(
    container=lambda: create_container_after_optimization(),
    operation=lambda c: c.get(SomeService),
    iterations=1000
)

improvement = comparator.calculate_improvement(before_results, after_results)
print("Optimization Improvement:")
print(f"- Time improvement: {improvement.time_improvement}%")
print(f"- Memory improvement: {improvement.memory_improvement}%")
print(f"- Overall improvement: {improvement.overall_improvement}%")

🎯 Profiling Best Practices

✅ Good Profiling Practices

1. Establish Baselines

# ✅ Good: Establish performance baselines
class BaselineProfiling:
    """Profiling with established baselines."""

    def __init__(self, container):
        self.container = container
        self.baselines = {}

    def establish_baseline(self, operation_name: str, operation, iterations: int = 1000):
        """Establish performance baseline."""
        import time
        import statistics

        times = []
        for _ in range(iterations):
            start_time = time.time()
            operation()
            end_time = time.time()
            times.append((end_time - start_time) * 1000)  # ms

        baseline = {
            "avg_time": statistics.mean(times),
            "median_time": statistics.median(times),
            "std_dev": statistics.stdev(times),
            "min_time": min(times),
            "max_time": max(times),
            "iterations": iterations
        }

        self.baselines[operation_name] = baseline
        return baseline

    def monitor_against_baseline(self, operation_name: str, operation, threshold: float = 0.1):
        """Monitor performance against baseline."""
        if operation_name not in self.baselines:
            raise ValueError(f"No baseline established for {operation_name}")

        baseline = self.baselines[operation_name]

        # Measure current performance
        current = self.establish_baseline(f"{operation_name}_current", operation, 100)

        # Compare
        time_diff = current["avg_time"] - baseline["avg_time"]
        time_diff_percent = (time_diff / baseline["avg_time"]) * 100

        result = {
            "baseline_avg": baseline["avg_time"],
            "current_avg": current["avg_time"],
            "time_difference": time_diff,
            "time_difference_percent": time_diff_percent,
            "within_threshold": abs(time_diff_percent) <= (threshold * 100),
            "regression_detected": time_diff_percent > (threshold * 100)
        }

        return result

# Usage
profiler = BaselineProfiling(container)

# Establish baseline
baseline = profiler.establish_baseline(
    "service_resolution",
    lambda: container.get(SomeService),
    iterations=1000
)

# Monitor performance
monitoring = profiler.monitor_against_baseline(
    "service_resolution",
    lambda: container.get(SomeService)
)

if monitoring["regression_detected"]:
    print("⚠️  Performance regression detected!")
    print(f"Time difference: {monitoring['time_difference']:.2f}ms ({monitoring['time_difference_percent']:.2f}%)")

2. Profile in Production-Like Conditions

# ✅ Good: Profile under realistic conditions
class RealisticProfiling:
    """Profiling under production-like conditions."""

    def __init__(self, container):
        self.container = container

    def simulate_load(self, service_type, concurrent_users: int = 10, duration_seconds: int = 60):
        """Simulate realistic load."""
        import asyncio
        import time

        async def user_simulation(user_id: int):
            """Simulate a user making requests."""
            requests_made = 0
            start_time = time.time()

            while time.time() - start_time < duration_seconds:
                try:
                    # Simulate user request
                    service = self.container.get(service_type)
                    # Simulate processing time
                    await asyncio.sleep(0.01)
                    requests_made += 1
                except Exception as e:
                    print(f"User {user_id} error: {e}")

            return {"user_id": user_id, "requests_made": requests_made}

        async def run_simulation():
            """Run the load simulation."""
            tasks = [
                user_simulation(user_id)
                for user_id in range(concurrent_users)
            ]

            results = await asyncio.gather(*tasks)
            return results

        # Run simulation
        results = asyncio.run(run_simulation())

        # Analyze results
        total_requests = sum(result["requests_made"] for result in results)
        avg_requests_per_user = total_requests / concurrent_users
        requests_per_second = total_requests / duration_seconds

        analysis = {
            "total_requests": total_requests,
            "avg_requests_per_user": avg_requests_per_user,
            "requests_per_second": requests_per_second,
            "user_results": results
        }

        return analysis

    def profile_under_load(self, service_type):
        """Profile service under load."""
        print("Profiling under load...")

        # Light load
        light_load = self.simulate_load(service_type, concurrent_users=5, duration_seconds=10)
        print(f"Light load: {light_load['requests_per_second']} req/sec")

        # Medium load
        medium_load = self.simulate_load(service_type, concurrent_users=20, duration_seconds=10)
        print(f"Medium load: {medium_load['requests_per_second']} req/sec")

        # Heavy load
        heavy_load = self.simulate_load(service_type, concurrent_users=50, duration_seconds=10)
        print(f"Heavy load: {heavy_load['requests_per_second']} req/sec")

        return {
            "light_load": light_load,
            "medium_load": medium_load,
            "heavy_load": heavy_load
        }

# Usage
realistic_profiler = RealisticProfiling(container)
load_profile = realistic_profiler.profile_under_load(SomeService)

3. Continuous Profiling

# ✅ Good: Continuous performance monitoring
class ContinuousProfiler:
    """Continuous profiling and monitoring."""

    def __init__(self, container):
        self.container = container
        self.is_monitoring = False
        self.metrics_history = []

    async def start_continuous_monitoring(self, interval_seconds: int = 60):
        """Start continuous performance monitoring."""
        self.is_monitoring = True

        while self.is_monitoring:
            try:
                # Collect metrics
                metrics = await self.collect_current_metrics()

                # Store in history
                self.metrics_history.append({
                    "timestamp": time.time(),
                    "metrics": metrics
                })

                # Check for anomalies
                await self.check_for_anomalies(metrics)

                # Keep only recent history (last 24 hours)
                cutoff_time = time.time() - (24 * 60 * 60)
                self.metrics_history = [
                    entry for entry in self.metrics_history
                    if entry["timestamp"] > cutoff_time
                ]

            except Exception as e:
                print(f"Monitoring error: {e}")

            await asyncio.sleep(interval_seconds)

    async def collect_current_metrics(self):
        """Collect current performance metrics."""
        # Measure resolution time
        start_time = time.time()
        service = self.container.get(SomeService)
        resolution_time = (time.time() - start_time) * 1000

        # Get memory usage
        memory_usage = self.get_memory_usage()

        # Get cache statistics
        cache_stats = self.container.get_cache_stats()

        return {
            "resolution_time": resolution_time,
            "memory_usage": memory_usage,
            "cache_hit_rate": cache_stats.get("hit_rate", 0),
            "total_resolutions": cache_stats.get("total_resolutions", 0)
        }

    async def check_for_anomalies(self, current_metrics):
        """Check for performance anomalies."""
        if len(self.metrics_history) < 10:
            return  # Need more data

        # Calculate recent average
        recent_metrics = self.metrics_history[-10:]
        avg_resolution_time = sum(
            entry["metrics"]["resolution_time"] for entry in recent_metrics
        ) / len(recent_metrics)

        # Check for significant deviation
        deviation = abs(current_metrics["resolution_time"] - avg_resolution_time)
        deviation_percent = (deviation / avg_resolution_time) * 100

        if deviation_percent > 20:  # 20% deviation
            print(f"⚠️  Performance anomaly detected!")
            print(f"Current: {current_metrics['resolution_time']:.2f}ms")
            print(f"Average: {avg_resolution_time:.2f}ms")
            print(f"Deviation: {deviation_percent:.2f}%")

            # Could trigger alerts, logging, etc.

    def get_memory_usage(self):
        """Get current memory usage."""
        import psutil
        import os
        process = psutil.Process(os.getpid())
        return process.memory_info().rss

    def stop_monitoring(self):
        """Stop continuous monitoring."""
        self.is_monitoring = False

    def get_performance_report(self):
        """Generate performance report from history."""
        if not self.metrics_history:
            return None

        # Analyze trends
        resolution_times = [entry["metrics"]["resolution_time"] for entry in self.metrics_history]
        memory_usages = [entry["metrics"]["memory_usage"] for entry in self.metrics_history]

        report = {
            "total_measurements": len(self.metrics_history),
            "avg_resolution_time": sum(resolution_times) / len(resolution_times),
            "min_resolution_time": min(resolution_times),
            "max_resolution_time": max(resolution_times),
            "avg_memory_usage": sum(memory_usages) / len(memory_usages),
            "memory_trend": "increasing" if memory_usages[-1] > memory_usages[0] else "decreasing"
        }

        return report

# Usage
continuous_profiler = ContinuousProfiler(container)

# Start monitoring
asyncio.create_task(continuous_profiler.start_continuous_monitoring(interval_seconds=30))

# Later...
report = continuous_profiler.get_performance_report()
print("Continuous Monitoring Report:")
print(f"- Average resolution time: {report['avg_resolution_time']:.2f}ms")
print(f"- Memory trend: {report['memory_trend']}")

# Stop monitoring
continuous_profiler.stop_monitoring()

❌ Bad Profiling Practices

1. Profiling in Development Only

# ❌ Bad: Only profile in development
class DevelopmentOnlyProfiler:
    """Only profiles in development - misses production issues."""

    def __init__(self, container, environment: str = "development"):
        self.container = container
        self.environment = environment

    def profile_service(self, service_type):
        """Only profile in development."""
        if self.environment == "development":
            # Profile here
            import time
            start_time = time.time()
            service = self.container.get(service_type)
            end_time = time.time()

            print(f"Resolution time: {(end_time - start_time) * 1000}ms")
        else:
            # No profiling in production
            service = self.container.get(service_type)

        return service

# ✅ Good: Profile in all environments
class EnvironmentAgnosticProfiler:
    """Profiles in all environments with appropriate levels."""

    def __init__(self, container, environment: str = "development"):
        self.container = container
        self.environment = environment

    def profile_service(self, service_type):
        """Profile with appropriate level for environment."""
        import time

        start_time = time.time()
        service = self.container.get(service_type)
        end_time = time.time()

        resolution_time = (end_time - start_time) * 1000

        if self.environment == "development":
            # Detailed profiling in development
            print(f"Resolution time: {resolution_time}ms")
            # Additional detailed metrics...

        elif self.environment == "production":
            # Minimal profiling in production
            if resolution_time > 100:  # Only log slow resolutions
                print(f"Slow resolution: {service_type.__name__} took {resolution_time}ms")

        return service

2. Ignoring Memory Profiling

# ❌ Bad: Focus only on CPU time
class CPUTimeOnlyProfiler:
    """Only profiles CPU time - misses memory issues."""

    def __init__(self, container):
        self.container = container

    def profile_resolution(self, service_type):
        """Only measure CPU time."""
        import time

        start_time = time.time()
        service = self.container.get(service_type)
        end_time = time.time()

        resolution_time = (end_time - start_time) * 1000

        return {
            "resolution_time": resolution_time,
            "memory_usage": "not measured",  # ❌ Missing memory profiling
            "object_count": "not measured"   # ❌ Missing object analysis
        }

# ✅ Good: Comprehensive profiling
class ComprehensiveProfiler:
    """Profiles CPU, memory, and other metrics."""

    def __init__(self, container):
        self.container = container

    def profile_resolution(self, service_type):
        """Comprehensive profiling."""
        import time
        import psutil
        import os

        # Memory before
        process = psutil.Process(os.getpid())
        memory_before = process.memory_info().rss

        # CPU time
        start_time = time.time()
        service = self.container.get(service_type)
        end_time = time.time()

        # Memory after
        memory_after = process.memory_info().rss

        resolution_time = (end_time - start_time) * 1000
        memory_usage = memory_after - memory_before

        return {
            "resolution_time": resolution_time,
            "memory_usage": memory_usage,
            "memory_before": memory_before,
            "memory_after": memory_after,
            "service_type": service_type.__name__
        }

🎯 Summary

Profiling provides comprehensive performance analysis:

  • Performance profiling - Container, memory, and CPU profiling
  • Dependency profiling - Chain analysis and resolution path profiling
  • Metrics collection - Real-time metrics and custom metrics
  • Bottleneck analysis - Automatic bottleneck detection and hot path analysis
  • Reporting - HTML reports, JSON export, and performance comparisons
  • Best practices - Baselines, realistic conditions, continuous monitoring

Key features: - Comprehensive performance profiling (CPU, memory, dependencies) - Real-time metrics collection and analysis - Automatic bottleneck detection - Performance baseline establishment and monitoring - Multiple report formats (HTML, JSON) - Continuous profiling capabilities

Best practices: - Establish performance baselines - Profile under production-like conditions - Implement continuous monitoring - Use comprehensive profiling (CPU + memory) - Profile in all environments appropriately - Monitor for performance regressions

Common profiling scenarios: - Service resolution performance analysis - Memory usage and leak detection - Dependency chain optimization - Bottleneck identification and resolution - Performance regression detection - Load testing and capacity planning

This completes the advanced features documentation. The InjectQ documentation now provides comprehensive coverage of all library features from basic concepts to advanced optimization techniques.