buildstack.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import sys
  2. def merge_items(data, all_items, nocollapse = False, no_complain_others = False):
  3. # Recursively walk the contributor list
  4. # Current list is in <items>, remaining values to be mapped in <values>,
  5. # conversion factor to calculate percentages to compare with the threshold in <scale>
  6. def get_items(prefix, items, values, scale):
  7. res = [] # Sub-components in this stack
  8. total = 0 # Total value of this (sub)stack, based on this we'll later decide whether to show this stack as components or aggregate
  9. other = 0 # Subcomponents that were too small to include in <res>
  10. for name, threshold, key_or_items in items:
  11. if type(key_or_items) is list:
  12. _res, _total, _other = get_items(prefix+name+'-', key_or_items, values, scale)
  13. total += _total
  14. if _total / scale <= threshold and not nocollapse:
  15. # Sub-stack total is below threshold: add to Others
  16. other += _total
  17. elif not _res and not nocollapse:
  18. # Sub-stack has no components above threshold: add aggregate value only
  19. res.append((prefix+name, _total))
  20. else:
  21. # Sub-stack is above threshold: add each component + others component
  22. res += _res
  23. other += _other
  24. else:
  25. if type(key_or_items) is not tuple:
  26. key_or_items = (key_or_items,)
  27. value = 0
  28. for key in key_or_items:
  29. if key in values:
  30. value += values[key]
  31. # Delete this value so we don't count it with 'Others'
  32. del values[key]
  33. total += value
  34. if value / scale <= threshold and not nocollapse:
  35. # Value is below threshold: add to others
  36. other += value
  37. else:
  38. # Value is above threshold: add by itself
  39. res.append((prefix+name, value))
  40. return res, total, other
  41. results = {}
  42. for core, values in data.items():
  43. scale = float(sum(values.values())) or 1. # Conversion factor from sim.stats values to %, for comparison with threshold
  44. res, total, other = get_items('', all_items, values, scale)
  45. # Everything that's left in <values> is unknown
  46. other += sum(values.values())
  47. if other:
  48. res.append(('other', other))
  49. if values and (not no_complain_others or sum(values.values()) > 0):
  50. sys.stderr.write('Also found but not in all_items: %s\n' % values)
  51. results[core] = (res, total, other, scale)
  52. return results
  53. def get_names(items, prefix = '', add_prefixes = True, keys = None):
  54. names = []
  55. for name, threshold, key_or_items in items:
  56. if not keys or name in keys:
  57. if type(key_or_items) is list:
  58. if add_prefixes:
  59. names.append(name) # Add the top-level name if requested
  60. names += get_names(key_or_items, name, add_prefixes)
  61. else:
  62. if prefix:
  63. names.append(prefix+'-'+name)
  64. else:
  65. names.append(name)
  66. return names