[IMP] ormcache: compute hit/miss/err statistics per database
In ormcache, those statistic numbers were counted per cached method for all registries. We introduce separate statistic counters, and create a counter per (database, model, method). The existing attributes that are no longer used have been removed.
This commit is contained in:
parent
68969c9716
commit
5aa23f8280
|
@ -21,24 +21,36 @@
|
||||||
|
|
||||||
# decorator makes wrappers that have the same API as their wrapped function;
|
# decorator makes wrappers that have the same API as their wrapped function;
|
||||||
# this is important for the openerp.api.guess() that relies on signatures
|
# this is important for the openerp.api.guess() that relies on signatures
|
||||||
|
from collections import defaultdict
|
||||||
from decorator import decorator
|
from decorator import decorator
|
||||||
from inspect import getargspec
|
from inspect import getargspec
|
||||||
|
|
||||||
import lru
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ormcache_counter(object):
|
||||||
|
""" Statistic counters for cache entries. """
|
||||||
|
__slots__ = ['hit', 'miss', 'err']
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.hit = 0
|
||||||
|
self.miss = 0
|
||||||
|
self.err = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ratio(self):
|
||||||
|
return 100.0 * self.hit / (self.hit + self.miss or 1)
|
||||||
|
|
||||||
|
# statistic counters dictionary, maps (dbname, modelname, method) to counter
|
||||||
|
STAT = defaultdict(ormcache_counter)
|
||||||
|
|
||||||
|
|
||||||
class ormcache(object):
|
class ormcache(object):
|
||||||
""" LRU cache decorator for orm methods. """
|
""" LRU cache decorator for orm methods. """
|
||||||
|
|
||||||
def __init__(self, skiparg=2, size=8192, multi=None, timeout=None):
|
def __init__(self, skiparg=2, size=8192, multi=None, timeout=None):
|
||||||
self.skiparg = skiparg
|
self.skiparg = skiparg
|
||||||
self.size = size
|
|
||||||
self.stat_miss = 0
|
|
||||||
self.stat_hit = 0
|
|
||||||
self.stat_err = 0
|
|
||||||
|
|
||||||
def __call__(self, method):
|
def __call__(self, method):
|
||||||
self.method = method
|
self.method = method
|
||||||
|
@ -46,11 +58,6 @@ class ormcache(object):
|
||||||
lookup.clear_cache = self.clear
|
lookup.clear_cache = self.clear
|
||||||
return lookup
|
return lookup
|
||||||
|
|
||||||
def stat(self):
|
|
||||||
return "lookup-stats %6d hit %6d miss %6d err %4.1f ratio" % \
|
|
||||||
(self.stat_hit, self.stat_miss, self.stat_err,
|
|
||||||
(100*float(self.stat_hit))/(self.stat_miss+self.stat_hit or 1))
|
|
||||||
|
|
||||||
def lru(self, model):
|
def lru(self, model):
|
||||||
return model.pool.cache, (model.pool.db_name, model._name, self.method)
|
return model.pool.cache, (model.pool.db_name, model._name, self.method)
|
||||||
|
|
||||||
|
@ -59,14 +66,14 @@ class ormcache(object):
|
||||||
key = key0 + args[self.skiparg:]
|
key = key0 + args[self.skiparg:]
|
||||||
try:
|
try:
|
||||||
r = d[key]
|
r = d[key]
|
||||||
self.stat_hit += 1
|
STAT[key0].hit += 1
|
||||||
return r
|
return r
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.stat_miss += 1
|
STAT[key0].miss += 1
|
||||||
value = d[key] = self.method(*args, **kwargs)
|
value = d[key] = self.method(*args, **kwargs)
|
||||||
return value
|
return value
|
||||||
except TypeError:
|
except TypeError:
|
||||||
self.stat_err += 1
|
STAT[key0].err += 1
|
||||||
return self.method(*args, **kwargs)
|
return self.method(*args, **kwargs)
|
||||||
|
|
||||||
def clear(self, model, *args):
|
def clear(self, model, *args):
|
||||||
|
@ -107,14 +114,14 @@ class ormcache_context(ormcache):
|
||||||
key = key0 + args[self.skiparg:self.context_pos] + tuple(ckey)
|
key = key0 + args[self.skiparg:self.context_pos] + tuple(ckey)
|
||||||
try:
|
try:
|
||||||
r = d[key]
|
r = d[key]
|
||||||
self.stat_hit += 1
|
STAT[key0].hit += 1
|
||||||
return r
|
return r
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.stat_miss += 1
|
STAT[key0].miss += 1
|
||||||
value = d[key] = self.method(*args, **kwargs)
|
value = d[key] = self.method(*args, **kwargs)
|
||||||
return value
|
return value
|
||||||
except TypeError:
|
except TypeError:
|
||||||
self.stat_err += 1
|
STAT[key0].err += 1
|
||||||
return self.method(*args, **kwargs)
|
return self.method(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -136,9 +143,9 @@ class ormcache_multi(ormcache):
|
||||||
key = base_key + (i,)
|
key = base_key + (i,)
|
||||||
try:
|
try:
|
||||||
result[i] = d[key]
|
result[i] = d[key]
|
||||||
self.stat_hit += 1
|
STAT[key0].hit += 1
|
||||||
except Exception:
|
except Exception:
|
||||||
self.stat_miss += 1
|
STAT[key0].miss += 1
|
||||||
missed.append(i)
|
missed.append(i)
|
||||||
|
|
||||||
if missed:
|
if missed:
|
||||||
|
@ -171,20 +178,18 @@ class dummy_cache(object):
|
||||||
def log_ormcache_stats(sig=None, frame=None):
|
def log_ormcache_stats(sig=None, frame=None):
|
||||||
""" Log statistics of ormcache usage by database, model, and method. """
|
""" Log statistics of ormcache usage by database, model, and method. """
|
||||||
from openerp.modules.registry import RegistryManager
|
from openerp.modules.registry import RegistryManager
|
||||||
from collections import defaultdict
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
me = threading.currentThread()
|
me = threading.currentThread()
|
||||||
entries = defaultdict(int)
|
entries = defaultdict(int)
|
||||||
for key in RegistryManager.cache.iterkeys():
|
for key in RegistryManager.cache.iterkeys():
|
||||||
entries[key[:3]] += 1
|
entries[key[:3]] += 1
|
||||||
for (dbname, model_name, method), count in sorted(entries.items()):
|
for key, count in sorted(entries.items()):
|
||||||
|
dbname, model_name, method = key
|
||||||
me.dbname = dbname
|
me.dbname = dbname
|
||||||
model = RegistryManager.get(dbname)[model_name]
|
stat = STAT[key]
|
||||||
func = getattr(model, method.__name__).im_func
|
_logger.info("%6d entries, %6d hit, %6d miss, %6d err, %4.1f%% ratio, for %s.%s",
|
||||||
ormcache = func.clear_cache.im_self
|
count, stat.hit, stat.miss, stat.err, stat.ratio, model_name, method.__name__)
|
||||||
_logger.info("%6d entries, %s, for %s.%s",
|
|
||||||
count, ormcache.stat(), model_name, method.__name__)
|
|
||||||
|
|
||||||
|
|
||||||
# For backward compatibility
|
# For backward compatibility
|
||||||
|
|
Loading…
Reference in New Issue