nodes: 0, module; 1, function_definition; 2, function_name:aggregate_registry_timers; 3, parameters; 4, block; 5, expression_statement; 6, import_statement; 7, expression_statement; 8, expression_statement; 9, for_statement; 10, expression_statement; 11, return_statement; 12, comment:"""Returns a list of aggregate timing information for registered timers.
  
      Each element is a 3-tuple of
  
          - timer description
          - aggregate elapsed time
          - number of calls
  
      The list is sorted by the first start time of each aggregate timer.
  
      """; 13, dotted_name; 14, assignment; 15, assignment; 16, pattern_list; 17, call; 18, block; 19, call; 20, subscript; 21, identifier:itertools; 22, identifier:timers; 23, call; 24, identifier:aggregate_timers; 25, list; 26, identifier:k; 27, identifier:g; 28, attribute; 29, argument_list; 30, expression_statement; 31, expression_statement; 32, expression_statement; 33, expression_statement; 34, comment:# We'll use the first start time as a sort key.; 35, expression_statement; 36, attribute; 37, argument_list; 38, call; 39, integer:1; 40, identifier:sorted; 41, argument_list; 42, identifier:itertools; 43, identifier:groupby; 44, identifier:timers; 45, keyword_argument; 46, assignment; 47, assignment; 48, assignment; 49, assignment; 50, call; 51, identifier:aggregate_timers; 52, identifier:sort; 53, identifier:zip; 54, argument_list; 55, call; 56, keyword_argument; 57, identifier:key; 58, lambda; 59, identifier:group; 60, call; 61, identifier:num_calls; 62, call; 63, identifier:total_elapsed_ms; 64, call; 65, identifier:first_start_time; 66, call; 67, attribute; 68, argument_list; 69, list_splat; 70, attribute; 71, argument_list; 72, identifier:key; 73, lambda; 74, lambda_parameters; 75, attribute; 76, identifier:list; 77, argument_list; 78, identifier:len; 79, argument_list; 80, identifier:sum; 81, generator_expression; 82, identifier:min; 83, generator_expression; 84, identifier:aggregate_timers; 85, identifier:append; 86, tuple; 87, identifier:aggregate_timers; 88, identifier:shared_registry; 89, identifier:values; 90, lambda_parameters; 91, attribute; 92, identifier:t; 93, identifier:t; 94, identifier:desc; 95, identifier:g; 96, identifier:group; 97, attribute; 98, for_in_clause; 99, attribute; 100, for_in_clause; 101, identifier:first_start_time; 102, tuple; 103, identifier:t; 104, identifier:t; 105, identifier:desc; 106, identifier:t; 107, identifier:elapsed_time_ms; 108, identifier:t; 109, identifier:group; 110, identifier:t; 111, identifier:start_time; 112, identifier:t; 113, identifier:group; 114, identifier:k; 115, identifier:total_elapsed_ms; 116, identifier:num_calls
code: def aggregate_registry_timers():
      """Returns a list of aggregate timing information for registered timers.
  
      Each element is a 3-tuple of
  
          - timer description
          - aggregate elapsed time
          - number of calls
  
      The list is sorted by the first start time of each aggregate timer.
  
      """
      import itertools
  
      timers = sorted(shared_registry.values(), key=lambda t: t.desc)
      aggregate_timers = []
      for k, g in itertools.groupby(timers, key=lambda t: t.desc):
          group = list(g)
          num_calls = len(group)
          total_elapsed_ms = sum(t.elapsed_time_ms for t in group)
          first_start_time = min(t.start_time for t in group)
          # We'll use the first start time as a sort key.
          aggregate_timers.append(
              (first_start_time, (k, total_elapsed_ms, num_calls)))
  
      aggregate_timers.sort()
      return zip(*aggregate_timers)[1]