code: def after_epoch_profile(self, epoch_id, profile: TimeProfile, train_stream_name: str, extra_streams: Iterable[str]) -> None:
          
  
          read_data_total = 0
          eval_total = 0
          train_total = sum(profile.get('eval_batch_{}'.format(train_stream_name), []))
          hooks_total = sum(profile.get('after_epoch_hooks', []))
  
          for stream_name in chain(extra_streams, [train_stream_name]):
              read_data_total += sum(profile.get('read_batch_' + stream_name, []))
              hooks_total += sum(profile.get('after_batch_hooks_' + stream_name, []))
              if stream_name != train_stream_name:
                  eval_total += sum(profile.get('eval_batch_' + stream_name, []))
  
          logging.info('\tT read data:\t%f', read_data_total)
          logging.info('\tT train:\t%f', train_total)
          logging.info('\tT eval:\t%f', eval_total)
          logging.info('\tT hooks:\t%f', hooks_total)
docs: Summarize and log the given epoch profile.
  
          The profile is expected to contain at least:
              - ``read_data_train``, ``eval_batch_train`` and ``after_batch_hooks_train`` entries produced by the train
                stream (if train stream name is `train`)
              - ``after_epoch_hooks`` entry
  
          :param profile: epoch timings profile
          :param extra_streams: enumeration of additional stream names