profiling.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import asyncio
  2. import inspect
  3. import logging
  4. import time
  5. logger = logging.getLogger(__name__)
  6. def time_decorator(func=None, *, log_slow_seconds: float = None):
  7. """A decorator that logs the execution time of a function.
  8. Args:
  9. func: The function to be decorated.
  10. log_slow_seconds (float, optional): Threshold in seconds to log slow executions. None means log all executions.
  11. """
  12. def decorator(inner_func):
  13. if asyncio.iscoroutinefunction(inner_func):
  14. async def async_wrapper(*args, **kwargs):
  15. start_time = time.time()
  16. result = await inner_func(*args, **kwargs)
  17. end_time = time.time()
  18. model_info = get_model_info(inner_func, args, kwargs)
  19. if log_slow_seconds:
  20. # Only log if execution time exceeds threshold
  21. if (end_time - start_time) > log_slow_seconds:
  22. logger.debug(
  23. f"{inner_func.__name__}{model_info} execution time: {end_time - start_time:.2f} seconds, exceeded threshold of {log_slow_seconds} seconds"
  24. )
  25. else:
  26. logger.debug(
  27. f"{inner_func.__name__}{model_info} execution time: {end_time - start_time:.2f} seconds"
  28. )
  29. return result
  30. return async_wrapper
  31. else:
  32. def sync_wrapper(*args, **kwargs):
  33. start_time = time.time()
  34. result = inner_func(*args, **kwargs)
  35. end_time = time.time()
  36. if log_slow_seconds:
  37. # Only log if execution time exceeds threshold
  38. if (end_time - start_time) > log_slow_seconds:
  39. logger.debug(
  40. f"{inner_func.__name__} execution time: {end_time - start_time} seconds, exceeded threshold of {log_slow_seconds} seconds"
  41. )
  42. else:
  43. logger.debug(
  44. f"{inner_func.__name__} execution time: {end_time - start_time} seconds"
  45. )
  46. return result
  47. return sync_wrapper
  48. if func is None:
  49. return decorator
  50. else:
  51. return decorator(func)
  52. def get_model_info(func, args, kwargs) -> str:
  53. """
  54. Get model info from the function arguments."""
  55. sig = inspect.signature(func)
  56. bound_args = sig.bind_partial(*args, **kwargs).arguments
  57. model = bound_args.get("model")
  58. model_name = ""
  59. if model and hasattr(model, "name"):
  60. model_name = model.name
  61. if model and hasattr(model, "readable_source"):
  62. model_name = model.readable_source
  63. if model_name:
  64. return f"(model: '{model_name}')"
  65. return ""