toolkit/components/telemetry/histogram_tools.py

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 import json
     6 import math
     7 import re
     9 from collections import OrderedDict
    11 def table_dispatch(kind, table, body):
    12     """Call body with table[kind] if it exists.  Raise an error otherwise."""
    13     if kind in table:
    14         return body(table[kind])
    15     else:
    16         raise BaseException, "don't know how to handle a histogram of kind %s" % kind
    18 class DefinitionException(BaseException):
    19     pass
    21 def check_numeric_limits(dmin, dmax, n_buckets):
    22     if type(dmin) != int:
    23         raise DefinitionException, "minimum is not a number"
    24     if type(dmax) != int:
    25         raise DefinitionException, "maximum is not a number"
    26     if type(n_buckets) != int:
    27         raise DefinitionException, "number of buckets is not a number"
    29 def linear_buckets(dmin, dmax, n_buckets):
    30     check_numeric_limits(dmin, dmax, n_buckets)
    31     ret_array = [0] * n_buckets
    32     dmin = float(dmin)
    33     dmax = float(dmax)
    34     for i in range(1, n_buckets):
    35         linear_range = (dmin * (n_buckets - 1 - i) + dmax * (i - 1)) / (n_buckets - 2)
    36         ret_array[i] = int(linear_range + 0.5)
    37     return ret_array
    39 def exponential_buckets(dmin, dmax, n_buckets):
    40     check_numeric_limits(dmin, dmax, n_buckets)
    41     log_max = math.log(dmax);
    42     bucket_index = 2;
    43     ret_array = [0] * n_buckets
    44     current = dmin
    45     ret_array[1] = current
    46     for bucket_index in range(2, n_buckets):
    47         log_current = math.log(current)
    48         log_ratio = (log_max - log_current) / (n_buckets - bucket_index)
    49         log_next = log_current + log_ratio
    50         next_value = int(math.floor(math.exp(log_next) + 0.5))
    51         if next_value > current:
    52             current = next_value
    53         else:
    54             current = current + 1
    55         ret_array[bucket_index] = current
    56     return ret_array
    58 always_allowed_keys = ['kind', 'description', 'cpp_guard', 'expires_in_version']
    60 class Histogram:
    61     """A class for representing a histogram definition."""
    63     def __init__(self, name, definition):
    64         """Initialize a histogram named name with the given definition.
    65 definition is a dict-like object that must contain at least the keys:
    67  - 'kind': The kind of histogram.  Must be one of 'boolean', 'flag',
    68    'enumerated', 'linear', or 'exponential'.
    69  - 'description': A textual description of the histogram.
    71 The key 'cpp_guard' is optional; if present, it denotes a preprocessor
    72 symbol that should guard C/C++ definitions associated with the histogram."""
    73         self.verify_attributes(name, definition)
    74         self._name = name
    75         self._description = definition['description']
    76         self._kind = definition['kind']
    77         self._cpp_guard = definition.get('cpp_guard')
    78         self._extended_statistics_ok = definition.get('extended_statistics_ok', False)
    79         self._expiration = definition.get('expires_in_version')
    80         self.compute_bucket_parameters(definition)
    81         table = { 'boolean': 'BOOLEAN',
    82                   'flag': 'FLAG',
    83                   'enumerated': 'LINEAR',
    84                   'linear': 'LINEAR',
    85                   'exponential': 'EXPONENTIAL' }
    86         table_dispatch(self.kind(), table,
    87                        lambda k: self._set_nsITelemetry_kind(k))
    89     def name(self):
    90         """Return the name of the histogram."""
    91         return self._name
    93     def description(self):
    94         """Return the description of the histogram."""
    95         return self._description
    97     def kind(self):
    98         """Return the kind of the histogram.
    99 Will be one of 'boolean', 'flag', 'enumerated', 'linear', or 'exponential'."""
   100         return self._kind
   102     def expiration(self):
   103         """Return the expiration version of the histogram."""
   104         return self._expiration
   106     def nsITelemetry_kind(self):
   107         """Return the nsITelemetry constant corresponding to the kind of
   108 the histogram."""
   109         return self._nsITelemetry_kind
   111     def _set_nsITelemetry_kind(self, kind):
   112         self._nsITelemetry_kind = "nsITelemetry::HISTOGRAM_%s" % kind
   114     def low(self):
   115         """Return the lower bound of the histogram.  May be a string."""
   116         return self._low
   118     def high(self):
   119         """Return the high bound of the histogram.  May be a string."""
   120         return self._high
   122     def n_buckets(self):
   123         """Return the number of buckets in the histogram.  May be a string."""
   124         return self._n_buckets
   126     def cpp_guard(self):
   127         """Return the preprocessor symbol that should guard C/C++ definitions
   128 associated with the histogram.  Returns None if no guarding is necessary."""
   129         return self._cpp_guard
   131     def extended_statistics_ok(self):
   132         """Return True if gathering extended statistics for this histogram
   133 is enabled."""
   134         return self._extended_statistics_ok
   136     def ranges(self):
   137         """Return an array of lower bounds for each bucket in the histogram."""
   138         table = { 'boolean': linear_buckets,
   139                   'flag': linear_buckets,
   140                   'enumerated': linear_buckets,
   141                   'linear': linear_buckets,
   142                   'exponential': exponential_buckets }
   143         return table_dispatch(self.kind(), table,
   144                               lambda p: p(self.low(), self.high(), self.n_buckets()))
   146     def compute_bucket_parameters(self, definition):
   147         table = {
   148             'boolean': Histogram.boolean_flag_bucket_parameters,
   149             'flag': Histogram.boolean_flag_bucket_parameters,
   150             'enumerated': Histogram.enumerated_bucket_parameters,
   151             'linear': Histogram.linear_bucket_parameters,
   152             'exponential': Histogram.exponential_bucket_parameters
   153             }
   154         table_dispatch(self.kind(), table,
   155                        lambda p: self.set_bucket_parameters(*p(definition)))
   157     def verify_attributes(self, name, definition):
   158         global always_allowed_keys
   159         general_keys = always_allowed_keys + ['low', 'high', 'n_buckets']
   161         table = {
   162             'boolean': always_allowed_keys,
   163             'flag': always_allowed_keys,
   164             'enumerated': always_allowed_keys + ['n_values'],
   165             'linear': general_keys,
   166             'exponential': general_keys + ['extended_statistics_ok']
   167             }
   168         table_dispatch(definition['kind'], table,
   169                        lambda allowed_keys: Histogram.check_keys(name, definition, allowed_keys))
   171         Histogram.check_expiration(name, definition)
   173     @staticmethod
   174     def check_expiration(name, definition):
   175         expiration = definition.get('expires_in_version')
   177         if not expiration:
   178             return
   180         if re.match(r'^[1-9][0-9]*$', expiration):
   181             expiration = expiration + ".0a1"
   182         elif re.match(r'^[1-9][0-9]*\.0$', expiration):
   183             expiration = expiration + "a1"
   185         definition['expires_in_version'] = expiration
   187     @staticmethod
   188     def check_keys(name, definition, allowed_keys):
   189         for key in definition.iterkeys():
   190             if key not in allowed_keys:
   191                 raise KeyError, '%s not permitted for %s' % (key, name)
   193     def set_bucket_parameters(self, low, high, n_buckets):
   194         def try_to_coerce_to_number(v):
   195             try:
   196                 return eval(v, {})
   197             except:
   198                 return v
   199         self._low = try_to_coerce_to_number(low)
   200         self._high = try_to_coerce_to_number(high)
   201         self._n_buckets = try_to_coerce_to_number(n_buckets)
   203     @staticmethod
   204     def boolean_flag_bucket_parameters(definition):
   205         return (1, 2, 3)
   207     @staticmethod
   208     def linear_bucket_parameters(definition):
   209         return (definition.get('low', 1),
   210                 definition['high'],
   211                 definition['n_buckets'])
   213     @staticmethod
   214     def enumerated_bucket_parameters(definition):
   215         n_values = definition['n_values']
   216         return (1, n_values, "%s+1" % n_values)
   218     @staticmethod
   219     def exponential_bucket_parameters(definition):
   220         return (definition.get('low', 1),
   221                 definition['high'],
   222                 definition['n_buckets'])
   224 def from_file(filename):
   225     """Return an iterator that provides a sequence of Histograms for
   226 the histograms defined in filename.
   227     """
   228     with open(filename, 'r') as f:
   229         histograms = json.load(f, object_pairs_hook=OrderedDict)
   230         for (name, definition) in histograms.iteritems():
   231             yield Histogram(name, definition)

mercurial