1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"""This is a helper module to get and manipulate histogram data.
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)The histogram data is the same data as is visible from "chrome://histograms".
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)More information can be found at: chromium/src/base/metrics/histogram.h
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"""
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport collections
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import json
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import logging
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)BROWSER_HISTOGRAM = 'browser_histogram'
163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)RENDERER_HISTOGRAM = 'renderer_histogram'
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def CustomizeBrowserOptions(options):
201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Allows histogram collection."""
211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  options.AppendExtraBrowserArgs(['--enable-stats-collection-bindings'])
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def SubtractHistogram(histogram_json, start_histogram_json):
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """Subtracts a previous histogram from a histogram.
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Both parameters and the returned result are json serializations.
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  start_histogram = json.loads(start_histogram_json)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # It's ok if the start histogram is empty (we had no data, maybe even no
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # histogram at all, at the start of the test).
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if 'buckets' not in start_histogram:
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return histogram_json
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  histogram = json.loads(histogram_json)
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if ('pid' in start_histogram and 'pid' in histogram
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      and start_histogram['pid'] != histogram['pid']):
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    raise Exception(
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        'Trying to compare histograms from different processes (%d and %d)'
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        % (start_histogram['pid'], histogram['pid']))
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  start_histogram_buckets = dict()
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for b in start_histogram['buckets']:
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    start_histogram_buckets[b['low']] = b['count']
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  new_buckets = []
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for b in histogram['buckets']:
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    new_bucket = b
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    low = b['low']
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if low in start_histogram_buckets:
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new_bucket['count'] = b['count'] - start_histogram_buckets[low]
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if new_bucket['count'] < 0:
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        logging.error('Histogram subtraction error, starting histogram most '
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      'probably invalid.')
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if new_bucket['count']:
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new_buckets.append(new_bucket)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  histogram['buckets'] = new_buckets
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  histogram['count'] -= start_histogram['count']
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return json.dumps(histogram)
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef AddHistograms(histogram_jsons):
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  """Adds histograms together. Used for aggregating data.
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  The parameter is a list of json serializations and the returned result is a
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  json serialization too.
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Note that the histograms to be added together are typically from different
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  processes.
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  """
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  buckets = collections.defaultdict(int)
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for histogram_json in histogram_jsons:
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    h = json.loads(histogram_json)
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for b in h['buckets']:
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      key = (b['low'], b['high'])
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      buckets[key] += b['count']
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  buckets = [{'low': key[0], 'high': key[1], 'count': value}
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      for key, value in buckets.iteritems()]
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  buckets.sort(key = lambda h : h['low'])
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  result_histogram = {}
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  result_histogram['buckets'] = buckets
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return json.dumps(result_histogram)
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)def GetHistogram(histogram_type, histogram_name, tab):
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """Get a json serialization of a histogram."""
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  assert histogram_type in [BROWSER_HISTOGRAM, RENDERER_HISTOGRAM]
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  function = 'getHistogram'
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if histogram_type == BROWSER_HISTOGRAM:
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    function = 'getBrowserHistogram'
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  histogram_json = tab.EvaluateJavaScript(
96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      'statsCollectionController.%s("%s")' %
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      (function, histogram_name))
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if histogram_json:
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return histogram_json
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return None
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetHistogramCount(histogram_type, histogram_name, tab):
1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  """Get the count of events for the given histograms."""
1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  histogram_json = GetHistogram(histogram_type, histogram_name, tab)
1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  histogram = json.loads(histogram_json)
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if 'count' in histogram:
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return histogram['count']
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else:
1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return 0
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)def GetHistogramSum(histogram_type, histogram_name, tab):
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  """Get the sum of events for the given histograms."""
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  histogram_json = GetHistogram(histogram_type, histogram_name, tab)
115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  histogram = json.loads(histogram_json)
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if 'sum' in histogram:
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return histogram['sum']
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  else:
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return 0
120