Repository: redis/redis-py
File: benchmarks/otel_benchmark.py (Python)

Code before:
        p50_latency_ms=sum(r.p50_latency_ms for r in results) / n,
        p95_latency_ms=sum(r.p95_latency_ms for r in results) / n,
        p99_latency_ms=sum(r.p99_latency_ms for r in results) / n,
        min_latency_ms=min(r.min_latency_ms for r in results),
        max_latency_ms=max(r.max_latency_ms for r in results),
        errors=sum(r.errors for r in results),
        first_error=first_error,
        cpu_percent_avg=sum(cpu_avgs) / len(cpu_avgs) if cpu_avgs else None,
        cpu_percent_max=max(cpu_maxs) if cpu_maxs else None,
        memory_mb_avg=sum(mem_avgs) / len(mem_avgs) if mem_avgs else None,
        memory_mb_max=max(mem_maxs) if mem_maxs else None,
        metadata=results[0].metadata,
    )


def parse_args() -> argparse.Namespace:
    """Parse command line arguments."""
    parser = argparse.ArgumentParser(
        description="Benchmark OTel instrumentation overhead in redis-py. Run one scenario at a time."
    )
    parser.add_argument(
        "--scenario", type=str, required=True,
        choices=["baseline", "otel_disabled", "otel_noop", "otel_inmemory", "otel_enabled_http", "otel_enabled_grpc"],
        help="Scenario to run (required)"
    )
    parser.add_argument(
        "--baseline-tag", type=str, default=None,
        help="Git tag to use for baseline scenario (required when --scenario baseline)"
    )
    parser.add_argument(
        "--duration", type=float, default=30.0,
        help="Duration of benchmark in seconds (default: 30)"
    )
    parser.add_argument(
        "--warmup", type=float, default=5.0,
        help="Warmup duration in seconds (default: 5)"
    )
    parser.add_argument(
        "--value-size", type=int, default=100,
        help="Size of values in bytes (default: 100)"
    )
    parser.add_argument(
        "--host", type=str, default="localhost",
        help="Redis host (default: localhost)"
    )
    parser.add_argument(
        "--port", type=int, default=6379,
        help="Redis port (default: 6379)"
    )
    parser.add_argument(
        "--json", action="store_true",

Review comment (suggestion):
Variable name 'Redis' uses PascalCase, which conventionally indicates a class definition. Since this is a reference to an imported class, consider using lowercase like 'redis_class' to avoid confusion.
```suggestion
        redis_client_cls = redis_mod.asyncio.Redis

        # Main client for commands
        self.client = redis_client_cls(
            host=self.config.redis_host,
            port=self.config.redis_port,
            decode_responses=True
        )

        # PubSub publisher (separate connection)
        self.pubsub_publisher = redis_client_cls(
            host=self.config.redis_host,
            port=self.config.redis_port,
            decode_responses=True
        )

        # PubSub subscriber
        subscriber = redis_client_cls(
```

Code after:
        """Generate a key for the current operation."""
        key = f"{self.config.key_prefix}:{self._key_counter % 1000}"
        self._key_counter += 1
        return key

    async def setup(self) -> None:
        """Set up all Redis resources."""
        redis_mod = self._get_redis_module()
        Redis = redis_mod.asyncio.Redis

        # Main client for commands
        self.client = Redis(
            host=self.config.redis_host,
            port=self.config.redis_port,
            decode_responses=True
        )

        # PubSub publisher (separate connection)
        self.pubsub_publisher = Redis(
            host=self.config.redis_host,
            port=self.config.redis_port,
            decode_responses=True
        )

        # PubSub subscriber
        subscriber = Redis(
            host=self.config.redis_host,
            port=self.config.redis_port,
            decode_responses=True
        )
        self.pubsub = subscriber.pubsub()
        await self.pubsub.subscribe(self.pubsub_channel)
        # Consume subscription confirmation
        await self.pubsub.get_message(timeout=1.0)

        # Create stream and consumer group
        try:
            await self.client.xgroup_create(
                self.stream_name,
                self.consumer_group,
                id="0",
                mkstream=True
            )
        except Exception:
            # Group may already exist
            pass

    async def teardown(self) -> None:
        """Clean up all Redis resources."""
        if self.pubsub:
            try: