code: def timefun(fun):
      
      @wraps(fun)
      def measure_time(*args, **kwargs):
          t1 = timer()
          result = fun(*args, **kwargs)
          t2 = timer()
          print("@timefun:" + fun.__name__ + " took " + str(t2 - t1) + " seconds")
          return result
      return measure_time
docs: Timing decorator
  
      Timers require you to do some digging. Start wrapping a few of the higher level
      functions and confirm where the bottleneck is, then drill down into that function,
      repeating as you go. When you find the disproportionately slow bit of code, fix it,
      and work your way back out confirming that it is fixed.
  
      Handy tip: Don't forget the handy timeit module! It tends to be more useful for
      benchmarking small pieces of code than for doing the actual investigation.
  
      Timer Pros:
      Easy to understand and implement. Also very simple to compare before and after fixes.
      Works across many languages.
  
      Timer Cons:
      Sometimes a little too simplistic for extremely complex codebases, you might spend
      more time placing and replacing boilerplate code than you will fixing the problem!