main_wrapper.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import functools
  2. import inspect
  3. import os
  4. import time
  5. from lib.memory_control import MemoryLimiter
  6. from lib.my_logger import logging
  7. from lib.print_exc_plus import print_exc_plus
  8. try:
  9. import winsound as win_sound
  10. def beep(*args, **kwargs):
  11. win_sound.Beep(*args, **kwargs)
  12. except ImportError:
  13. win_sound = None
  14. beep = lambda x, y: ...
  15. ENABLE_PROFILING = False
  16. def start_profiling():
  17. try:
  18. import yappi
  19. except ModuleNotFoundError:
  20. return
  21. yappi.set_clock_type("wall")
  22. print(f'Starting yappi profiler.')
  23. yappi.start()
  24. def currently_profiling_yappi():
  25. try:
  26. import yappi
  27. except ModuleNotFoundError:
  28. return False
  29. return len(yappi.get_func_stats()) > 0
  30. def profile_wall_time_instead_if_profiling():
  31. try:
  32. import yappi
  33. except ModuleNotFoundError:
  34. return
  35. currently_profiling = len(yappi.get_func_stats())
  36. if currently_profiling and yappi.get_clock_type() != 'wall':
  37. yappi.stop()
  38. print('Profiling wall time instead of cpu time.')
  39. yappi.clear_stats()
  40. yappi.set_clock_type("wall")
  41. yappi.start()
  42. def dump_pstats_if_profiling(relating_to_object):
  43. try:
  44. import yappi
  45. except ModuleNotFoundError:
  46. return
  47. currently_profiling = len(yappi.get_func_stats())
  48. if currently_profiling:
  49. try:
  50. pstats_file = 'logs/profiling/' + os.path.normpath(inspect.getfile(relating_to_object)).replace(os.path.abspath('.'), '') + '.pstat'
  51. except AttributeError:
  52. print('WARNING: unable to set pstat file path for profiling.')
  53. return
  54. os.makedirs(os.path.dirname(pstats_file), exist_ok=True)
  55. yappi.get_func_stats()._save_as_PSTAT(pstats_file)
  56. print(f'Saved profiling log to {pstats_file}.')
  57. class YappiProfiler():
  58. def __init__(self, relating_to_object):
  59. self.relating_to_object = relating_to_object
  60. def __enter__(self):
  61. start_profiling()
  62. profile_wall_time_instead_if_profiling()
  63. def __exit__(self, exc_type, exc_val, exc_tb):
  64. dump_pstats_if_profiling(self.relating_to_object)
  65. def list_logger(base_logging_function, store_in_list: list):
  66. def print_and_store(*args, **kwargs):
  67. base_logging_function(*args, **kwargs)
  68. store_in_list.extend(args)
  69. return print_and_store
  70. EMAIL_CRASHES_TO = []
  71. def main_wrapper(f):
  72. @functools.wraps(f)
  73. def wrapper(*args, **kwargs):
  74. if ENABLE_PROFILING:
  75. start_profiling()
  76. from lib.memory_control import MemoryLimiter
  77. MemoryLimiter.limit_memory_usage()
  78. start = time.perf_counter()
  79. # import lib.stack_tracer
  80. import __main__
  81. # does not help much
  82. # monitoring_thread = hanging_threads.start_monitoring(seconds_frozen=180, test_interval=1000)
  83. os.makedirs('logs', exist_ok=True)
  84. # stack_tracer.trace_start('logs/' + os.path.split(__main__.__file__)[-1] + '.html', interval=5)
  85. # faulthandler.enable()
  86. profile_wall_time_instead_if_profiling()
  87. # noinspection PyBroadException
  88. try:
  89. return f(*args, **kwargs)
  90. except KeyboardInterrupt:
  91. error_messages = []
  92. print_exc_plus(print=list_logger(logging.error, error_messages),
  93. serialize_to='logs/' + os.path.split(__main__.__file__)[-1] + '.dill')
  94. except:
  95. error_messages = []
  96. print_exc_plus(print=list_logger(logging.error, error_messages),
  97. serialize_to='logs/' + os.path.split(__main__.__file__)[-1] + '.dill')
  98. for recipient in EMAIL_CRASHES_TO:
  99. from jobs.sending_emails import send_mail
  100. send_mail.create_simple_mail_via_gmail(body='\n'.join(error_messages), filepath=None, excel_name=None, to_mail=recipient, subject='Crash report')
  101. finally:
  102. logging.info('Terminated.')
  103. total_time = time.perf_counter() - start
  104. # faulthandler.disable()
  105. # stack_tracer.trace_stop()
  106. frequency = 2000
  107. duration = 500
  108. beep(frequency, duration)
  109. if ENABLE_PROFILING:
  110. dump_pstats_if_profiling(f)
  111. print('Total time', total_time)
  112. wrapper.func = f
  113. return wrapper