Home | History | Annotate | Download | only in local
      1 # Copyright 2012 the V8 project authors. All rights reserved.
      2 # Redistribution and use in source and binary forms, with or without
      3 # modification, are permitted provided that the following conditions are
      4 # met:
      5 #
      6 #     * Redistributions of source code must retain the above copyright
      7 #       notice, this list of conditions and the following disclaimer.
      8 #     * Redistributions in binary form must reproduce the above
      9 #       copyright notice, this list of conditions and the following
     10 #       disclaimer in the documentation and/or other materials provided
     11 #       with the distribution.
     12 #     * Neither the name of Google Inc. nor the names of its
     13 #       contributors may be used to endorse or promote products derived
     14 #       from this software without specific prior written permission.
     15 #
     16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 
     29 import os
     30 import shelve
     31 import threading
     32 
     33 
     34 class PerfDataEntry(object):
     35   def __init__(self):
     36     self.avg = 0.0
     37     self.count = 0
     38 
     39   def AddResult(self, result):
     40     kLearnRateLimiter = 99  # Greater value means slower learning.
     41     # We use an approximation of the average of the last 100 results here:
     42     # The existing average is weighted with kLearnRateLimiter (or less
     43     # if there are fewer data points).
     44     effective_count = min(self.count, kLearnRateLimiter)
     45     self.avg = self.avg * effective_count + result
     46     self.count = effective_count + 1
     47     self.avg /= self.count
     48 
     49 
     50 class PerfDataStore(object):
     51   def __init__(self, datadir, arch, mode):
     52     filename = os.path.join(datadir, "%s.%s.perfdata" % (arch, mode))
     53     self.database = shelve.open(filename, protocol=2)
     54     self.closed = False
     55     self.lock = threading.Lock()
     56 
     57   def __del__(self):
     58     self.close()
     59 
     60   def close(self):
     61     if self.closed: return
     62     self.database.close()
     63     self.closed = True
     64 
     65   def GetKey(self, test):
     66     """Computes the key used to access data for the given testcase."""
     67     flags = "".join(test.flags)
     68     return str("%s.%s.%s" % (test.suitename(), test.path, flags))
     69 
     70   def FetchPerfData(self, test):
     71     """Returns the observed duration for |test| as read from the store."""
     72     key = self.GetKey(test)
     73     if key in self.database:
     74       return self.database[key].avg
     75     return None
     76 
     77   def UpdatePerfData(self, test):
     78     """Updates the persisted value in the store with test.duration."""
     79     testkey = self.GetKey(test)
     80     self.RawUpdatePerfData(testkey, test.duration)
     81 
     82   def RawUpdatePerfData(self, testkey, duration):
     83     with self.lock:
     84       if testkey in self.database:
     85         entry = self.database[testkey]
     86       else:
     87         entry = PerfDataEntry()
     88       entry.AddResult(duration)
     89       self.database[testkey] = entry
     90 
     91 
     92 class PerfDataManager(object):
     93   def __init__(self, datadir):
     94     self.datadir = os.path.abspath(datadir)
     95     if not os.path.exists(self.datadir):
     96       os.makedirs(self.datadir)
     97     self.stores = {}  # Keyed by arch, then mode.
     98     self.closed = False
     99     self.lock = threading.Lock()
    100 
    101   def __del__(self):
    102     self.close()
    103 
    104   def close(self):
    105     if self.closed: return
    106     for arch in self.stores:
    107       modes = self.stores[arch]
    108       for mode in modes:
    109         store = modes[mode]
    110         store.close()
    111     self.closed = True
    112 
    113   def GetStore(self, arch, mode):
    114     with self.lock:
    115       if not arch in self.stores:
    116         self.stores[arch] = {}
    117       modes = self.stores[arch]
    118       if not mode in modes:
    119         modes[mode] = PerfDataStore(self.datadir, arch, mode)
    120       return modes[mode]
    121 
    122 
    123 class NullPerfDataStore(object):
    124   def UpdatePerfData(self, test):
    125     pass
    126 
    127   def FetchPerfData(self, test):
    128     return None
    129 
    130 
    131 class NullPerfDataManager(object):
    132   def __init__(self):
    133     pass
    134 
    135   def GetStore(self, *args, **kwargs):
    136     return NullPerfDataStore()
    137 
    138   def close(self):
    139     pass
    140 
    141 
    142 def GetPerfDataManager(context, datadir):
    143   if context.use_perf_data:
    144     return PerfDataManager(datadir)
    145   else:
    146     return NullPerfDataManager()
    147