* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-07-25 14:28 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-07-25 14:28 UTC (permalink / raw
To: gentoo-commits
commit: 80380eae890dfe4411b61991f942c54f02cf4f15
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jul 25 14:28:37 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jul 25 14:28:37 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=80380eae
roverlay/stats/__init__.py
---
roverlay/stats/__init__.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/roverlay/stats/__init__.py b/roverlay/stats/__init__.py
new file mode 100644
index 0000000..e69de29
^ permalink raw reply [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2014-02-21 17:36 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2014-02-21 17:36 UTC (permalink / raw
To: gentoo-commits
commit: f6cd141477e64a7500366206f4cb098f3a249256
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Feb 20 21:18:14 2014 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Feb 20 21:18:14 2014 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f6cd1414
roverlay/stats, timestats: add reset() method
Fixes a bug when using the remote console ("./bin/debug/console remote") where
the second query_packages command fails due to reset() missing for timestats
objects.
---
roverlay/stats/abstract.py | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/roverlay/stats/abstract.py b/roverlay/stats/abstract.py
index 5ac87bc..c2ecace 100644
--- a/roverlay/stats/abstract.py
+++ b/roverlay/stats/abstract.py
@@ -120,16 +120,26 @@ class TimeStatsItem ( RoverlayStatsBase ):
# doc TODO: note somewhere that those timestats are just approximate
# values
- def __init__ ( self, t_begin=None, t_end=None, description=None ):
- super ( TimeStatsItem, self ).__init__ ( description=description )
+ def _setup_time_stats_item ( self, t_begin, t_end ):
self.time_begin = t_begin if t_begin is not None else time.time()
self.time_end = t_end
+ # --- end of _setup_time_stats_item (...) ---
+
+ def __init__ ( self, t_begin=None, t_end=None, description=None ):
+ super ( TimeStatsItem, self ).__init__ ( description=description )
+ self.time_begin = None
+ self.time_end = None
+ self._setup_time_stats_item ( t_begin, t_end )
# --- end of __init__ (...) ---
def end ( self, t_end=None ):
self.time_end = time.time() if t_end is None else t_end
# --- end of end (...) ---
+ def reset ( self ):
+ self._setup_time_stats_item ( None, None )
+ # --- end of reset (...) ---
+
def get_delta ( self ):
if self.time_begin is None:
return -1.0
@@ -153,6 +163,11 @@ class TimeStats ( RoverlayStats ):
self._timestats = collections.OrderedDict()
# --- end of __init__ (...) ---
+ def reset ( self ):
+ for tstat in self._timestats.values():
+ tstat.reset()
+ # --- end of reset (...) ---
+
def has_changes ( self ):
return False
# --- end of has_changes (...) ---
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-09-05 10:24 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-09-05 10:24 UTC (permalink / raw
To: gentoo-commits
commit: 01bcf594038714fcd576a9ef2357d16e40ac2e3d
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Sep 5 10:13:51 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Sep 5 10:13:51 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=01bcf594
dbcollector: fix as_dict
---
roverlay/stats/dbcollector.py | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/roverlay/stats/dbcollector.py b/roverlay/stats/dbcollector.py
index 788110d..2b30aec 100644
--- a/roverlay/stats/dbcollector.py
+++ b/roverlay/stats/dbcollector.py
@@ -9,6 +9,16 @@ import weakref
from . import rating
+def get_dict ( k ):
+ if k:
+ try:
+ return k._asdict()
+ except AttributeError:
+ return dict ( k )
+ else:
+ return dict()
+# --- end of get_dict (...) ---
+
class StatsDBCollector ( object ):
VERSION = 0
@@ -65,11 +75,12 @@ class StatsDBCollector ( object ):
# --- end of make_timestats (...) ---
def get_numstats ( self, as_dict=False ):
- return self._numstats._as_dict() if as_dict else self._numstats
+ #dict(zip(<rating~>.keys(),<>))
+ return get_dict ( self._numstats ) if as_dict else self._numstats
# --- end of get_numstats (...) ---
def get_timestats ( self, as_dict=False ):
- return self._timestats._as_dict() if as_dict else self._timestats
+ return get_dict ( self._timestats ) if as_dict else self._timestats
# --- end of get_timestats (...) ---
def get_all ( self ):
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-09-05 9:25 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-09-05 9:25 UTC (permalink / raw
To: gentoo-commits
commit: 149d64984da9534e73c4e805b3892a2fc925bad4
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Sep 5 09:07:01 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Sep 5 09:07:01 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=149d6498
dbcollector: fix typo
---
roverlay/stats/dbcollector.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/roverlay/stats/dbcollector.py b/roverlay/stats/dbcollector.py
index 4fad61c..788110d 100644
--- a/roverlay/stats/dbcollector.py
+++ b/roverlay/stats/dbcollector.py
@@ -65,7 +65,7 @@ class StatsDBCollector ( object ):
# --- end of make_timestats (...) ---
def get_numstats ( self, as_dict=False ):
- return self._numstats._as_dict() if as_dict self._numstats
+ return self._numstats._as_dict() if as_dict else self._numstats
# --- end of get_numstats (...) ---
def get_timestats ( self, as_dict=False ):
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-09-05 9:25 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-09-05 9:25 UTC (permalink / raw
To: gentoo-commits
commit: 13cdf0835c8a8d2c190e100288d385dd9cad6d54
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Sep 5 09:04:03 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Sep 5 09:04:03 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=13cdf083
dbcollector: collect time/numstats separately
---
roverlay/stats/dbcollector.py | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/roverlay/stats/dbcollector.py b/roverlay/stats/dbcollector.py
index 2961aec..4fad61c 100644
--- a/roverlay/stats/dbcollector.py
+++ b/roverlay/stats/dbcollector.py
@@ -25,12 +25,14 @@ class StatsDBCollector ( object ):
def __init__ ( self, stats ):
super ( StatsDBCollector, self ).__init__()
- self.stats = weakref.ref ( stats )
- self._collected_stats = None
+ self.stats = weakref.ref ( stats )
+ self._numstats = None
+ self._timestats = None
# --- end of __init__ (...) ---
def update ( self ):
- self._collected_stats = self.make_all()
+ self._numstats = self.make_numstats()
+ self._timestats = self.make_timestats()
# --- end of update (...) ---
def make_numstats ( self ):
@@ -62,12 +64,16 @@ class StatsDBCollector ( object ):
return ()
# --- end of make_timestats (...) ---
- def make_all ( self ):
- return self.make_numstats() + self.make_timestats()
- # --- end of make_all (...) ---
+ def get_numstats ( self, as_dict=False ):
+ return self._numstats._as_dict() if as_dict self._numstats
+ # --- end of get_numstats (...) ---
+
+ def get_timestats ( self, as_dict=False ):
+ return self._timestats._as_dict() if as_dict else self._timestats
+ # --- end of get_timestats (...) ---
def get_all ( self ):
- return self._collected_stats
+ return self._numstats + self._timestats
# --- end of get_all (...) ---
# --- end of StatsDBCollector #v0 ---
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-08-16 12:42 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-08-16 12:42 UTC (permalink / raw
To: gentoo-commits
commit: 90b6001bfd4225013b36e7a652a6c829446d6fc4
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 16 12:40:59 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 16 12:40:59 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=90b6001b
roverlay/stats/rating: handle UNKNOWNs
---
roverlay/stats/rating.py | 167 +++++++++++++++++++++++++++++------------------
1 file changed, 102 insertions(+), 65 deletions(-)
diff --git a/roverlay/stats/rating.py b/roverlay/stats/rating.py
index ec36002..3f6b9e0 100644
--- a/roverlay/stats/rating.py
+++ b/roverlay/stats/rating.py
@@ -41,6 +41,7 @@ class StatsRating ( object ):
STATUS_CRIT = 2**4
STATUS_TOO_HIGH = 2**5
STATUS_TOO_LOW = 2**6
+ STATUS_UNDEF = 2**7
STATUS_WARN_LOW = STATUS_WARN | STATUS_TOO_LOW
@@ -50,7 +51,7 @@ class StatsRating ( object ):
STATUS_CRIT_LOW = STATUS_CRIT | STATUS_TOO_LOW
STATUS_CRIT_HIGH = STATUS_CRIT | STATUS_TOO_HIGH
- STATUS_FAIL = ( ( 2**7 ) - 1 ) ^ STATUS_OK
+ STATUS_FAIL = ( ( 2**8 ) - 1 ) ^ STATUS_OK
def __init__ ( self, description ):
@@ -79,9 +80,7 @@ class NumStatsCounterRating ( StatsRating ):
self.err_low = err_low
self.crit_low = crit_low
self.value = value
- self.status = (
- self.get_rating ( value ) if value is not None else None
- )
+ self.status = self.get_rating ( value )
# --- end of __init__ (...) ---
@classmethod
@@ -89,30 +88,38 @@ class NumStatsCounterRating ( StatsRating ):
return cls ( description, value, warn, err, crit )
# --- end of new_fail_counter (...) ---
+ def get_value ( self, unknown_value=0 ):
+ return self.value or unknown_value
+ # --- end of get_value (...) ---
+
def get_rating ( self, value ):
- too_high = lambda high, k: ( high is not None and k > high )
- too_low = lambda low, k: ( low is not None and k < low )
- ret = self.STATUS_NONE
+ if value is None:
+ return self.STATUS_UNDEF
+
+ else:
+ too_high = lambda high, k: ( high is not None and k > high )
+ too_low = lambda low, k: ( low is not None and k < low )
+ ret = self.STATUS_NONE
- if too_high ( self.warn_high, value ):
- ret |= self.STATUS_WARN_HIGH
+ if too_high ( self.warn_high, value ):
+ ret |= self.STATUS_WARN_HIGH
- if too_low ( self.warn_low, value ):
- ret |= self.STATUS_WARN_LOW
+ if too_low ( self.warn_low, value ):
+ ret |= self.STATUS_WARN_LOW
- if too_high ( self.err_high, value ):
- ret |= self.STATUS_ERR_HIGH
+ if too_high ( self.err_high, value ):
+ ret |= self.STATUS_ERR_HIGH
- if too_low ( self.err_low, value ):
- ret |= self.STATUS_ERR_LOW
+ if too_low ( self.err_low, value ):
+ ret |= self.STATUS_ERR_LOW
- if too_high ( self.crit_high, value ):
- ret |= self.STATUS_CRIT_HIGH
+ if too_high ( self.crit_high, value ):
+ ret |= self.STATUS_CRIT_HIGH
- if too_low ( self.crit_low, value ):
- ret |= self.STATUS_CRIT_LOW
+ if too_low ( self.crit_low, value ):
+ ret |= self.STATUS_CRIT_LOW
- return self.STATUS_OK if ret == self.STATUS_NONE else ret
+ return self.STATUS_OK if ret == self.STATUS_NONE else ret
# --- end of get_rating (...) ---
def is_warning ( self ):
@@ -132,9 +139,9 @@ class NumStatsCounterRating ( StatsRating ):
# --- end of is_ok (...) ---
def format_value ( self,
- fmt_ok=None, fmt_warn=None, fmt_err=None, fmt_crit=None
+ fmt_ok=None, fmt_warn=None, fmt_err=None, fmt_crit=None, fmt_undef=None
):
- fmt = self.get_item ( fmt_ok, fmt_warn, fmt_err, fmt_crit )
+ fmt = self.get_item ( fmt_ok, fmt_warn, fmt_err, fmt_crit, fmt_undef )
if fmt:
return fmt.format ( str ( self.value ) )
elif fmt == "":
@@ -143,7 +150,7 @@ class NumStatsCounterRating ( StatsRating ):
return str ( self.value )
# --- end of format_value (...) ---
- def get_item ( self, item_ok, item_warn, item_err, item_crit ):
+ def get_item ( self, item_ok, item_warn, item_err, item_crit, item_undef ):
status = self.status
if self.status & self.STATUS_CRIT:
return item_crit
@@ -156,9 +163,12 @@ class NumStatsCounterRating ( StatsRating ):
# --- end of get_item (...) ---
def get_word ( self,
- word_ok="ok", word_warn="warn", word_err="err", word_crit="crit"
+ word_ok="ok", word_warn="warn", word_err="err", word_crit="crit",
+ word_undef="undef",
):
- return str ( self.get_item ( word_ok, word_warn, word_err, word_crit ) )
+ return str ( self.get_item (
+ word_ok, word_warn, word_err, word_crit, word_undef
+ ) )
# --- end of get_word (...) ---
@@ -201,8 +211,28 @@ class RoverlayNumStatsRating ( NumStatsRating ):
# FIXME: err/crit
values = self.values
- v_ec_post = values['ec_post']
- v_pc_repo = values['pc_repo']
+
+ # very efficient.
+ # TODO/COULDFIX: find a better solution for handling UNKNOWNS
+ # * 0 or 0 == 0 == None or 0
+ # * don't use v_* as value when creating NumStatsCounterRating objects,
+ # the "UNKNOWN" state would get lost
+ #
+ v_pc_repo = values['pc_repo'] or 0
+ v_pc_distmap = values['pc_distmap'] or 0
+ v_pc_filtered = values['pc_filtered'] or 0
+ v_pc_queued = values['pc_queued'] or 0
+ v_pc_success = values['pc_success'] or 0
+ v_pc_fail = values['pc_fail'] or 0
+ v_pc_fail_empty = values['pc_fail_empty'] or 0
+ v_pc_fail_dep = values['pc_fail_dep'] or 0
+ v_pc_fail_selfdep = values['pc_fail_selfdep'] or 0
+ v_pc_fail_err = values['pc_fail_err'] or 0
+ v_ec_pre = values['ec_pre'] or 0
+ v_ec_post = values['ec_post'] or 0
+ v_ec_written = values['ec_written'] or 0
+ v_ec_revbump = values['ec_revbump'] or 0
+
# *_high=k -- warn/... if value > k
# *_low=k -- warn/... if value < k
@@ -211,77 +241,76 @@ class RoverlayNumStatsRating ( NumStatsRating ):
)
self.pc_repo = new_numstats ( 'pc_repo',
- warn_low=1,
- err_low=( 1 if values['pc_distmap'] > 0 else 0 ),
+ warn_low = 1,
+ err_low = ( 1 if v_pc_distmap > 0 else 0 ),
)
self.pc_distmap = new_numstats ( 'pc_distmap',
# src files of imported ebuilds don't get written to the distmap
# (can be "fixed" with --distmap-verify)
- warn_low=max ( 1, v_ec_post ),
- err_low=( 1 if v_ec_post > 0 else 0 ),
- warn_high=( 1.01*v_ec_post if v_ec_post > 0 else None ),
- err_high=( 1.1*v_ec_post if v_ec_post > 0 else None ),
+ warn_low = max ( 1, v_ec_post ),
+ err_low = ( 1 if v_ec_post > 0 else 0 ),
+ warn_high = ( ( 1.01 * v_ec_post ) if v_ec_post > 0 else None ),
+ err_high = ( ( 1.1 * v_ec_post ) if v_ec_post > 0 else None ),
)
self.pc_filtered = new_numstats ( 'pc_filtered',
- crit_high=( v_pc_repo - values['pc_queued'] ),
+ crit_high = ( v_pc_repo - v_pc_queued ),
)
self.pc_queued = new_numstats ( 'pc_queued',
# cannot queue more packages than available
- crit_high=( v_pc_repo - values['pc_filtered'] ),
+ crit_high = ( v_pc_repo - v_pc_filtered ),
)
self.pc_success = new_numstats ( 'pc_success',
- crit_high=values['pc_queued'],
+ crit_high = v_pc_queued,
# warn about low pc_success/pc_queued ratio
- warn_low=(
- 0.9*values['pc_queued'] if values['pc_queued'] > 0 else None
- ),
+ warn_low = ( ( 0.9 * v_pc_queued ) if v_pc_queued > 0 else None ),
)
self.pc_fail = new_numstats ( 'pc_fail',
# pc_queued would produce "false" warnings in incremental mode
- warn_high=( max ( 0, 0.15 * v_pc_repo ) ),
- err_high=( max ( 0, 0.3 * v_pc_repo ) ),
- crit_high=( max ( 0, 0.5 * v_pc_repo ) ),
- crit_low=(
- values['pc_fail_empty'] + values['pc_fail_dep']
- + values['pc_fail_selfdep'] + values['pc_fail_err']
- ),
+ warn_high = max ( 0, 0.15 * v_pc_repo ),
+ err_high = max ( 0, 0.3 * v_pc_repo ),
+ crit_high = max ( 0, 0.5 * v_pc_repo ),
+ crit_low = sum ((
+ v_pc_fail_empty, v_pc_fail_dep, v_pc_fail_selfdep, v_pc_fail_err
+ )),
)
self.pc_fail_empty = new_numstats ( 'pc_fail_empty',
- crit_high=values['pc_fail'],
+ crit_high = v_pc_fail,
)
self.pc_fail_dep = new_numstats ( 'pc_fail_dep',
- crit_high=values['pc_fail'],
- warn_high=max ( 10, 0.01*values['pc_repo'] ),
+ crit_high = v_pc_fail,
+ warn_high = max ( 10, ( 0.01 * v_pc_repo ) ),
)
self.pc_fail_selfdep = new_numstats ( 'pc_fail_selfdep',
- crit_high=values['pc_fail'],
+ crit_high = v_pc_fail,
)
self.pc_fail_err = new_numstats ( 'pc_fail_err',
- warn_high=1, err_high=1, crit_high=values['pc_fail'],
+ warn_high = 1,
+ err_high = 1,
+ crit_high = v_pc_fail,
)
- self.ec_pre = new_numstats ( 'ec_pre',
- warn_high=v_ec_post,
- err_high=max ( 0, 1.05*v_ec_post ),
+ self.ec_pre = new_numstats ( 'ec_pre',
+ warn_high = v_ec_post,
+ err_high = max ( 0, ( 1.05 * v_ec_post ) ),
)
- self.ec_post = new_numstats ( 'ec_post',
- warn_low=values['ec_pre'],
+ self.ec_post = new_numstats ( 'ec_post',
+ warn_low = v_ec_pre,
# tolerate 5% ebuild loss (1/1.05 ~= 0.95)
- err_low=max ( 1, 0.95*values['ec_pre'] ),
+ err_low = max ( 1, ( 0.95 * v_ec_pre ) ),
)
- self.ec_written = new_numstats ( 'ec_written',
- err_low=values['pc_success'],
+ self.ec_written = new_numstats ( 'ec_written',
+ err_low = v_pc_success,
)
self.ec_revbump = new_numstats ( 'ec_revbump',
- crit_high=min ( v_pc_repo, values['ec_pre'] ),
- warn_high=min ( 1, 0.1*values['ec_pre'] ),
+ crit_high = min ( v_pc_repo, v_ec_pre ),
+ warn_high = min ( 1, ( 0.1 * v_ec_pre ) ),
)
# --- end of setup (...) ---
@@ -296,6 +325,13 @@ class RoverlayNumStatsRating ( NumStatsRating ):
else:
code_format = { 'cstart': "<code>", 'cend': "</code>", }
+
+ if any ( value is None for value in self.values ):
+ yield (
+ "database contains UNKNOWNS",
+ [ "run roverlay", ]
+ )
+
if not self.pc_repo.is_ok():
yield (
"low repo package count",
@@ -321,7 +357,7 @@ class RoverlayNumStatsRating ( NumStatsRating ):
yield ( topic, details )
- if self.pc_success.value < 1:
+ if self.pc_success.get_value(2) < 1:
if self.pc_success.status & (self.STATUS_ERR|self.STATUS_CRIT):
yield ( "no ebuilds created", None )
else:
@@ -335,9 +371,9 @@ class RoverlayNumStatsRating ( NumStatsRating ):
None
)
- if self.pc_fail.value > 0 or not self.pc_success.is_ok():
+ if self.pc_fail.get_value() > 0 or not self.pc_success.is_ok():
details = []
- if self.pc_fail_dep.value > 0:
+ if self.pc_fail_dep.get_value() > 0:
details.append ( "write dependency rules" )
details.append ( 'configure package ignore rules' )
@@ -351,7 +387,6 @@ class RoverlayNumStatsRating ( NumStatsRating ):
)
-
if not self.pc_fail_err.is_ok():
yield (
"failures due to unknown errors",
@@ -367,6 +402,8 @@ class RoverlayNumStatsRating ( NumStatsRating ):
None
)
+ # +++ UNKNOWNS
+
# --- end of get_suggestions (...) ---
# --- end of RoverlayNumStatsRating ---
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-08-16 10:43 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-08-16 10:43 UTC (permalink / raw
To: gentoo-commits
commit: f400284d5fab7c5157796437fb6d0b47cde16072
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 16 10:21:10 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 16 10:21:10 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f400284d
roverlay/stats: rate stats
check stats for min/max values, get suggestions/notes
---
roverlay/stats/dbcollector.py | 13 +-
roverlay/stats/rating.py | 372 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 377 insertions(+), 8 deletions(-)
diff --git a/roverlay/stats/dbcollector.py b/roverlay/stats/dbcollector.py
index a9169e6..2961aec 100644
--- a/roverlay/stats/dbcollector.py
+++ b/roverlay/stats/dbcollector.py
@@ -7,21 +7,18 @@
import collections
import weakref
+from . import rating
+
class StatsDBCollector ( object ):
VERSION = 0
- # 'pc' := package count(er), 'ec' := ebuild _
- NUMSTATS_KEYS = (
- 'pc_repo', 'pc_distmap', 'pc_filtered', 'pc_queued', 'pc_success',
- 'pc_fail', 'pc_fail_empty', 'pc_fail_dep', 'pc_fail_selfdep',
- 'pc_fail_err',
- 'ec_pre', 'ec_post', 'ec_written', 'ec_revbump',
- )
+ NUMSTATS_KEYS = rating.NUMSTATS.keys()
NUMSTATS = collections.namedtuple (
"numstats", ' '.join ( NUMSTATS_KEYS )
)
- TIMESTATS_KEYS = ()
+
+ TIMESTATS_KEYS = rating.TIMESTATS.keys()
TIMESTATS = collections.namedtuple (
"timestats", ' '.join ( TIMESTATS_KEYS )
)
diff --git a/roverlay/stats/rating.py b/roverlay/stats/rating.py
new file mode 100644
index 0000000..ec36002
--- /dev/null
+++ b/roverlay/stats/rating.py
@@ -0,0 +1,372 @@
+# R overlay -- stats collection, "rate" stats ("good","bad",...)
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import collections
+
+import roverlay.util.objects
+
+# 'pc' := package count(er), 'ec' := ebuild _
+#
+NUMSTATS = collections.OrderedDict ((
+ ( 'pc_repo', "package files found in the repositories" ),
+ ( 'pc_distmap', "package files in the mirror directory" ),
+ ( 'pc_filtered', "packages ignored by package rules" ),
+ ( 'pc_queued', "packages queued for ebuild creation" ),
+ ( 'pc_success', "packages for which ebuild creation succeeded" ),
+ ( 'pc_fail', "packages for which ebuild creation failed" ),
+ # actually, it's not the package that "fails"
+ ( 'pc_fail_empty', "packages failed due to empty/unsuitable DESCRIPTION" ),
+ ( 'pc_fail_dep', "packages failed due to unresolvable dependencies" ),
+ ( 'pc_fail_selfdep', "packages failed due to unsatisfiable selfdeps" ),
+ ( 'pc_fail_err', "packages failed due to unknown errors" ),
+ ( 'ec_pre', "ebuild count prior to overlay creation" ),
+ ( 'ec_post', "ebuild count after overlay creation" ),
+ ( 'ec_written', "ebuilds written" ),
+ ( 'ec_revbump', "ebuilds rev-bumped due to package file content change" ),
+))
+
+
+TIMESTATS = {}
+
+class StatsRating ( object ):
+
+ STATUS_NONE = 0
+ ##STATUS_OK = 2**1
+ STATUS_OK = STATUS_NONE
+ STATUS_WARN = 2**2
+ STATUS_ERR = 2**3
+ STATUS_CRIT = 2**4
+ STATUS_TOO_HIGH = 2**5
+ STATUS_TOO_LOW = 2**6
+
+
+ STATUS_WARN_LOW = STATUS_WARN | STATUS_TOO_LOW
+ STATUS_WARN_HIGH = STATUS_WARN | STATUS_TOO_HIGH
+ STATUS_ERR_LOW = STATUS_ERR | STATUS_TOO_LOW
+ STATUS_ERR_HIGH = STATUS_ERR | STATUS_TOO_HIGH
+ STATUS_CRIT_LOW = STATUS_CRIT | STATUS_TOO_LOW
+ STATUS_CRIT_HIGH = STATUS_CRIT | STATUS_TOO_HIGH
+
+ STATUS_FAIL = ( ( 2**7 ) - 1 ) ^ STATUS_OK
+
+
+ def __init__ ( self, description ):
+ super ( StatsRating, self ).__init__()
+ self.description = description
+ # --- end of __init__ (...) ---
+
+ @roverlay.util.objects.abstractmethod
+ def get_rating ( self, value ):
+ return STATUS_NONE
+ # --- end of get_rating (...) ---
+
+# --- end of StatsRating ---
+
+class NumStatsCounterRating ( StatsRating ):
+
+ def __init__ ( self, description, value,
+ warn_high=None, err_high=None, crit_high=None,
+ warn_low=0, err_low=0, crit_low=0
+ ):
+ super ( NumStatsCounterRating, self ).__init__ ( description )
+ self.warn_high = warn_high
+ self.err_high = err_high
+ self.crit_high = crit_high
+ self.warn_low = warn_low
+ self.err_low = err_low
+ self.crit_low = crit_low
+ self.value = value
+ self.status = (
+ self.get_rating ( value ) if value is not None else None
+ )
+ # --- end of __init__ (...) ---
+
+ @classmethod
+ def new_fail_counter ( cls, description, value, warn=1, err=1, crit=1 ):
+ return cls ( description, value, warn, err, crit )
+ # --- end of new_fail_counter (...) ---
+
+ def get_rating ( self, value ):
+ too_high = lambda high, k: ( high is not None and k > high )
+ too_low = lambda low, k: ( low is not None and k < low )
+ ret = self.STATUS_NONE
+
+ if too_high ( self.warn_high, value ):
+ ret |= self.STATUS_WARN_HIGH
+
+ if too_low ( self.warn_low, value ):
+ ret |= self.STATUS_WARN_LOW
+
+ if too_high ( self.err_high, value ):
+ ret |= self.STATUS_ERR_HIGH
+
+ if too_low ( self.err_low, value ):
+ ret |= self.STATUS_ERR_LOW
+
+ if too_high ( self.crit_high, value ):
+ ret |= self.STATUS_CRIT_HIGH
+
+ if too_low ( self.crit_low, value ):
+ ret |= self.STATUS_CRIT_LOW
+
+ return self.STATUS_OK if ret == self.STATUS_NONE else ret
+ # --- end of get_rating (...) ---
+
+ def is_warning ( self ):
+ return self.status & self.STATUS_WARN
+ # --- end of is_warning (...) ---
+
+ def is_error ( self ):
+ return self.status & self.STATUS_ERR
+ # --- end of is_error (...) ---
+
+ def is_critical ( self ):
+ return self.status & self.STATUS_CRIT
+ # --- end of is_critical (...) ---
+
+ def is_ok ( self ):
+ return self.status == self.STATUS_OK
+ # --- end of is_ok (...) ---
+
+ def format_value ( self,
+ fmt_ok=None, fmt_warn=None, fmt_err=None, fmt_crit=None
+ ):
+ fmt = self.get_item ( fmt_ok, fmt_warn, fmt_err, fmt_crit )
+ if fmt:
+ return fmt.format ( str ( self.value ) )
+ elif fmt == "":
+ return fmt
+ else:
+ return str ( self.value )
+ # --- end of format_value (...) ---
+
+ def get_item ( self, item_ok, item_warn, item_err, item_crit ):
+ status = self.status
+ if self.status & self.STATUS_CRIT:
+ return item_crit
+ elif self.status & self.STATUS_ERR:
+ return item_err
+ elif self.status & self.STATUS_WARN:
+ return item_warn
+ else:
+ return item_ok
+ # --- end of get_item (...) ---
+
+ def get_word ( self,
+ word_ok="ok", word_warn="warn", word_err="err", word_crit="crit"
+ ):
+ return str ( self.get_item ( word_ok, word_warn, word_err, word_crit ) )
+ # --- end of get_word (...) ---
+
+
+# --- end of NumStatsCounterRating ---
+
+
+class NumStatsRating ( StatsRating ):
+
+ def __init__ ( self, values, description=None ):
+ assert isinstance ( values, dict )
+ super ( NumStatsRating, self ).__init__ ( description=description )
+ self.values = values
+ self.setup()
+ # --- end of __init__ (...) ---
+
+ @roverlay.util.objects.abstractmethod
+ def setup ( self ):
+ pass
+ # --- end of setup (...) ---
+
+ def get_rating ( self ):
+ return self
+ # --- end of get_rating (...) ---
+
+# --- end of NumStatsRating ---
+
+
+class RoverlayNumStatsRating ( NumStatsRating ):
+
+ ## COULDFIX: yield str key / int indizes in get_suggestions() and
+ ## optionall "translate" them using a map
+ ## "event" => message
+ ##SUGGESTIONS = {}
+
+
+ def setup ( self ):
+ if __debug__:
+ assert set ( NUMSTATS.keys() ) == set ( self.values.keys() )
+
+ # FIXME: err/crit
+
+ values = self.values
+ v_ec_post = values['ec_post']
+ v_pc_repo = values['pc_repo']
+
+ # *_high=k -- warn/... if value > k
+ # *_low=k -- warn/... if value < k
+ new_numstats = lambda key, **b: (
+ NumStatsCounterRating ( NUMSTATS[key], values[key], **b )
+ )
+
+ self.pc_repo = new_numstats ( 'pc_repo',
+ warn_low=1,
+ err_low=( 1 if values['pc_distmap'] > 0 else 0 ),
+ )
+
+ self.pc_distmap = new_numstats ( 'pc_distmap',
+ # src files of imported ebuilds don't get written to the distmap
+ # (can be "fixed" with --distmap-verify)
+ warn_low=max ( 1, v_ec_post ),
+ err_low=( 1 if v_ec_post > 0 else 0 ),
+ warn_high=( 1.01*v_ec_post if v_ec_post > 0 else None ),
+ err_high=( 1.1*v_ec_post if v_ec_post > 0 else None ),
+ )
+
+ self.pc_filtered = new_numstats ( 'pc_filtered',
+ crit_high=( v_pc_repo - values['pc_queued'] ),
+ )
+
+ self.pc_queued = new_numstats ( 'pc_queued',
+ # cannot queue more packages than available
+ crit_high=( v_pc_repo - values['pc_filtered'] ),
+ )
+
+ self.pc_success = new_numstats ( 'pc_success',
+ crit_high=values['pc_queued'],
+ # warn about low pc_success/pc_queued ratio
+ warn_low=(
+ 0.9*values['pc_queued'] if values['pc_queued'] > 0 else None
+ ),
+ )
+
+ self.pc_fail = new_numstats ( 'pc_fail',
+ # pc_queued would produce "false" warnings in incremental mode
+ warn_high=( max ( 0, 0.15 * v_pc_repo ) ),
+ err_high=( max ( 0, 0.3 * v_pc_repo ) ),
+ crit_high=( max ( 0, 0.5 * v_pc_repo ) ),
+ crit_low=(
+ values['pc_fail_empty'] + values['pc_fail_dep']
+ + values['pc_fail_selfdep'] + values['pc_fail_err']
+ ),
+ )
+
+ self.pc_fail_empty = new_numstats ( 'pc_fail_empty',
+ crit_high=values['pc_fail'],
+ )
+ self.pc_fail_dep = new_numstats ( 'pc_fail_dep',
+ crit_high=values['pc_fail'],
+ warn_high=max ( 10, 0.01*values['pc_repo'] ),
+ )
+ self.pc_fail_selfdep = new_numstats ( 'pc_fail_selfdep',
+ crit_high=values['pc_fail'],
+ )
+ self.pc_fail_err = new_numstats ( 'pc_fail_err',
+ warn_high=1, err_high=1, crit_high=values['pc_fail'],
+ )
+
+ self.ec_pre = new_numstats ( 'ec_pre',
+ warn_high=v_ec_post,
+ err_high=max ( 0, 1.05*v_ec_post ),
+ )
+
+ self.ec_post = new_numstats ( 'ec_post',
+ warn_low=values['ec_pre'],
+ # tolerate 5% ebuild loss (1/1.05 ~= 0.95)
+ err_low=max ( 1, 0.95*values['ec_pre'] ),
+ )
+ self.ec_written = new_numstats ( 'ec_written',
+ err_low=values['pc_success'],
+ )
+ self.ec_revbump = new_numstats ( 'ec_revbump',
+ crit_high=min ( v_pc_repo, values['ec_pre'] ),
+ warn_high=min ( 1, 0.1*values['ec_pre'] ),
+ )
+ # --- end of setup (...) ---
+
+ def __iter__ ( self ):
+ for key in NUMSTATS.keys():
+ yield ( key, getattr ( self, key ) )
+ # --- end of __iter__ (...) ---
+
+ def get_suggestions ( self, pure_text=False ):
+ if pure_text:
+ code_format = { 'cstart': "\'", 'cend': "\'", }
+ else:
+ code_format = { 'cstart': "<code>", 'cend': "</code>", }
+
+ if not self.pc_repo.is_ok():
+ yield (
+ "low repo package count",
+ [ "check the repo config file", "drop repos without packages" ]
+ )
+
+ if not self.pc_distmap.is_ok():
+ details = [
+ 'run {cstart}roverlay --distmap-verify{cend} to fix '
+ 'the distmap'.format ( **code_format )
+ ]
+
+ if self.pc_distmap.status & self.STATUS_TOO_HIGH:
+ topic = "distmap file count is higher than the ebuild count"
+ else:
+ topic = "distmap file count is lower than the ebuild count"
+ details.append (
+ 'run {cstart}roverlay --fixup-category-move[-reverse]{cend} '
+ ' after configuring relocations (in the package rules)'.format (
+ **code_format
+ )
+ )
+ yield ( topic, details )
+
+
+ if self.pc_success.value < 1:
+ if self.pc_success.status & (self.STATUS_ERR|self.STATUS_CRIT):
+ yield ( "no ebuilds created", None )
+ else:
+ yield (
+ "no ebuilds created (not an issue in incremental mode)",
+ None
+ )
+ elif not self.pc_success.is_ok():
+ yield (
+ "only a few ebuilds created (not an issue in incremental mode)",
+ None
+ )
+
+ if self.pc_fail.value > 0 or not self.pc_success.is_ok():
+ details = []
+ if self.pc_fail_dep.value > 0:
+ details.append ( "write dependency rules" )
+ details.append ( 'configure package ignore rules' )
+
+ yield (
+ '{adj} failure rate'.format (
+ adj=self.pc_fail.get_word (
+ "normal/expected", "moderate", "high", "very high"
+ )
+ ),
+ details
+ )
+
+
+
+ if not self.pc_fail_err.is_ok():
+ yield (
+ "failures due to unknown errors",
+ [ 'check the log files for python exceptions and report them', ]
+ )
+
+ if not self.ec_pre.is_ok() or not self.ec_post.is_ok():
+ yield ( "ebuild loss occurred (no suggestions available)", None )
+
+ if not self.ec_revbump.is_ok():
+ yield (
+ "unexpected ebuild revbump count (no suggestions available)",
+ None
+ )
+
+ # --- end of get_suggestions (...) ---
+
+# --- end of RoverlayNumStatsRating ---
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-08-15 9:18 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-08-15 9:18 UTC (permalink / raw
To: gentoo-commits
commit: e469805008ebc3743087694844d319e862f0803d
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug 15 09:17:22 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug 15 09:17:22 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=e4698050
roverlay/stats/rrd: use GAUGE for numstats
---
roverlay/stats/dbcollector.py | 2 ++
roverlay/stats/rrd.py | 5 +++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/roverlay/stats/dbcollector.py b/roverlay/stats/dbcollector.py
index 402e64d..a9169e6 100644
--- a/roverlay/stats/dbcollector.py
+++ b/roverlay/stats/dbcollector.py
@@ -41,6 +41,8 @@ class StatsDBCollector ( object ):
ov_create = stats.overlay_creation
ov = stats.overlay
+ # note that the int() casts are necessary here
+ #
return self.__class__.NUMSTATS (
pc_repo = int ( stats.repo.pkg_count ),
pc_distmap = int ( stats.distmap.pkg_count ),
diff --git a/roverlay/stats/rrd.py b/roverlay/stats/rrd.py
index ffccbe1..2a09bdd 100644
--- a/roverlay/stats/rrd.py
+++ b/roverlay/stats/rrd.py
@@ -43,14 +43,15 @@ class StatsDB ( roverlay.db.rrdtool.RRD ):
def make_vars ( self ):
heartbeat = 2 * self.step
return tuple (
- RRDVariable ( k, 'DERIVE', val_min=0, heartbeat=heartbeat )
+ RRDVariable ( k, 'GAUGE', val_min=0, heartbeat=heartbeat )
for k in self.collector.NUMSTATS_KEYS
)
# --- end of make_vars (...) ---
def make_rra ( self ):
return (
- RRDArchive.new_day ( 'LAST', 0.7, step=self.step ),
+ #RRDArchive.new_day ( 'MIN', 0.7, step=self.step ),
+ RRDArchive.new_day ( 'MAX', 0.7, step=self.step ),
RRDArchive.new_week ( 'AVERAGE', 0.7, step=self.step ),
RRDArchive.new_month ( 'AVERAGE', 0.7, step=self.step ),
)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-08-02 10:34 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-08-02 10:34 UTC (permalink / raw
To: gentoo-commits
commit: a343c180f2d22c0411086c3dbca5eb2d85da235e
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Aug 2 10:20:04 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Aug 2 10:20:04 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a343c180
stats collection: has_changes(), count imports
* overlay_has_changes()
* count imported ebuilds
---
roverlay/stats/abstract.py | 54 ++++++++++++++++++++++++++++++++++++++++-----
roverlay/stats/base.py | 36 ++++++++++++++++++++++++------
roverlay/stats/collector.py | 7 ++++++
3 files changed, 84 insertions(+), 13 deletions(-)
diff --git a/roverlay/stats/abstract.py b/roverlay/stats/abstract.py
index 68728f4..5ac87bc 100644
--- a/roverlay/stats/abstract.py
+++ b/roverlay/stats/abstract.py
@@ -9,7 +9,8 @@ from __future__ import division
import collections
import time
-from roverlay.util.objects import MethodNotImplementedError
+import roverlay.util.objects
+from roverlay.util.objects import MethodNotImplementedError, abstractmethod
class RoverlayStatsBase ( object ):
@@ -47,15 +48,15 @@ class RoverlayStatsBase ( object ):
getattr ( self, member ).merge_with ( getattr ( other, member ) )
# --- end of merge_members (...) ---
- def _iter_members ( self, nofail=False ):
+ def iter_members ( self, nofail=False ):
if not nofail or hasattr ( self, '_MEMBERS' ):
for member in self.__class__._MEMBERS:
yield getattr ( self, member )
- # --- end of _iter_members (...) ---
+ # --- end of iter_members (...) ---
def has_nonzero ( self ):
if hasattr ( self, '_MEMBERS' ):
- for member in self._iter_members():
+ for member in self.iter_members():
if int ( member ) != 0:
return member
else:
@@ -63,7 +64,7 @@ class RoverlayStatsBase ( object ):
# --- end of has_nonzero (...) ---
def reset_members ( self ):
- for member in self._iter_members():
+ for member in self.iter_members():
member.reset()
# --- end of reset_members (...) ---
@@ -86,7 +87,7 @@ class RoverlayStatsBase ( object ):
if desc:
yield desc
- for member in self._iter_members( nofail=True ):
+ for member in self.iter_members( nofail=True ):
yield str ( member )
# --- end of gen_str (...) ---
@@ -103,6 +104,15 @@ class RoverlayStatsBase ( object ):
class RoverlayStats ( RoverlayStatsBase ):
pass
+
+ @abstractmethod
+ def has_changes ( self ):
+ """Returns True if this stats item has any numbers indicating that
+ the overlay has changes.
+ """
+ return False
+ # --- end of has_changes (...) ---
+
# --- end of RoverlayStats ---
@@ -143,6 +153,10 @@ class TimeStats ( RoverlayStats ):
self._timestats = collections.OrderedDict()
# --- end of __init__ (...) ---
+ def has_changes ( self ):
+ return False
+ # --- end of has_changes (...) ---
+
def merge_with ( self, other ):
self._timestats.update ( other._timestats )
# --- end of merge_with (...) ---
@@ -225,6 +239,10 @@ class Counter ( RoverlayStatsBase ):
return float ( self.total_count )
# --- end of __float__ (...) ---
+ def __bool__ ( self ):
+ return bool ( self.total_count )
+ # --- end of __bool__ (...) ---
+
def __add__ ( self, other ):
return self.total_count + int ( other )
# --- end of __add__ (...) ---
@@ -233,6 +251,30 @@ class Counter ( RoverlayStatsBase ):
return self.total_count - int ( other )
# --- end of __sub__ (...) ---
+ def __gt__ ( self, other ):
+ return self.total_count > int ( other )
+ # --- end of __gt__ (...) ---
+
+ def __ge__ ( self, other ):
+ return self.total_count >= int ( other )
+ # --- end of __ge__ (...) ---
+
+ def __lt__ ( self, other ):
+ return self.total_count < int ( other )
+ # --- end of __lt__ (...) ---
+
+ def __le__ ( self, other ):
+ return self.total_count <= int ( other )
+ # --- end of __le__ (...) ---
+
+ def __eq__ ( self, other ):
+ return self.total_count == int ( other )
+ # --- end of __eq__ (...) ---
+
+ def __ne__ ( self, other ):
+ return self.total_count != int ( other )
+ # --- end of __ne__ (...) ---
+
def has_details ( self ):
return False
# --- end of has_details (...) ---
diff --git a/roverlay/stats/base.py b/roverlay/stats/base.py
index 28531c2..282ff78 100644
--- a/roverlay/stats/base.py
+++ b/roverlay/stats/base.py
@@ -19,6 +19,10 @@ class RepoStats ( abstract.RoverlayStats ):
)
# --- end of __init__ (...) ---
+ def has_changes ( self ):
+ return False
+ # --- end of has_changes (...) ---
+
def package_file_found ( self, repo ):
self.pkg_count.inc ( repo.name )
# --- end of add_package (...) ---
@@ -37,6 +41,10 @@ class DistmapStats ( abstract.RoverlayStats ):
)
# --- end of __init__ (...) ---
+ def has_changes ( self ):
+ return False
+ # --- end of has_changes (...) ---
+
def file_added ( self, *origin ):
self.pkg_count.inc ( *origin )
# --- end of file_added (...) ---
@@ -58,6 +66,10 @@ class OverlayCreationWorkerStats ( abstract.RoverlayStats ):
self.pkg_success = abstract.Counter ( "success" )
# --- end of __init__ (...) ---
+ def has_changes ( self ):
+ return bool ( self.pkg_success )
+ # --- end of has_changes (...) ---
+
# --- end of OverlayCreationWorkerStats ---
@@ -103,24 +115,34 @@ class OverlayStats ( abstract.RoverlayStats ):
_MEMBERS = (
'scan_time', 'write_time',
- 'ebuilds_scanned', 'ebuild_count', 'revbump_count', 'ebuilds_written',
+ 'ebuilds_scanned', 'ebuild_count', 'revbump_count',
+ 'ebuilds_imported', 'ebuilds_written',
)
def __init__ ( self ):
super ( OverlayStats, self ).__init__()
# ebuilds_scanned: ebuild count prior to running overlay creation
- self.ebuilds_scanned = abstract.Counter ( "pre" )
+ self.ebuilds_scanned = abstract.Counter ( "pre" )
# ebuild count: ebuild count after writing the overlay
- self.ebuild_count = abstract.Counter ( "post" )
+ self.ebuild_count = abstract.Counter ( "post" )
- self.revbump_count = abstract.Counter ( "revbumps" )
- self.ebuilds_written = abstract.Counter ( "written" )
+ self.revbump_count = abstract.Counter ( "revbumps" )
+ self.ebuilds_written = abstract.Counter ( "written" )
+ self.ebuilds_imported = abstract.Counter ( "imported" )
- self.write_time = abstract.TimeStats ( "write_time" )
- self.scan_time = abstract.TimeStats ( "scan_time" )
+ self.write_time = abstract.TimeStats ( "write_time" )
+ self.scan_time = abstract.TimeStats ( "scan_time" )
# --- end of __init__ (...) ---
+ def has_changes ( self ):
+ return (
+ ( self.ebuild_count - self.ebuilds_scanned ) != 0 or
+ self.ebuilds_written > 0 or
+ self.revbump_count > 0
+ )
+ # --- end of has_changes (...) ---
+
def set_ebuild_written ( self, p_info ):
self.ebuilds_written.inc()
# direct dict access
diff --git a/roverlay/stats/collector.py b/roverlay/stats/collector.py
index 85eb358..ebae1a6 100644
--- a/roverlay/stats/collector.py
+++ b/roverlay/stats/collector.py
@@ -26,6 +26,13 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
return cls._instance
# --- end of instance (...) ---
+ def overlay_has_any_changes ( self ):
+ """Returns True if the resulting overlay has any changes (according to
+ stats).
+ """
+ return any ( x.has_changes() for x in self.iter_members() )
+ # --- end of overlay_has_any_changes (...) ---
+
def get_success_ratio ( self ):
# success ratio for "this" run:
# new ebuilds / relevant package count (new packages - unsuitable,
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-07-29 14:56 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-07-29 14:56 UTC (permalink / raw
To: gentoo-commits
commit: d1300fc92439e26b6941eec62ec888329835ee77
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 29 14:53:05 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 29 14:53:05 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d1300fc9
write stats to round-robin database (rrdtool)
This commit makes (/allows to/) stats data persistent by adding them to a db,
which can later be used to draw graphs etc.
---
roverlay/stats/abstract.py | 37 +-----
roverlay/stats/collector.py | 156 +++++---------------------
roverlay/stats/dbcollector.py | 74 ++++++++++++
roverlay/stats/rrd.py | 63 +++++++++++
roverlay/stats/{collector.py => visualize.py} | 91 +++------------
5 files changed, 189 insertions(+), 232 deletions(-)
diff --git a/roverlay/stats/abstract.py b/roverlay/stats/abstract.py
index 6d0575a..68728f4 100644
--- a/roverlay/stats/abstract.py
+++ b/roverlay/stats/abstract.py
@@ -9,34 +9,7 @@ from __future__ import division
import collections
import time
-class MethodNotImplemented ( NotImplementedError ):
- def __init__ ( self, obj, method ):
- super ( MethodNotImplemented, self ).__init__ (
- "{n}.{f}()".format ( n=obj.__class__.__name__, f=method )
- )
- # --- end of __init__ (...) ---
-
-# --- end of MethodNotImplemented ---
-
-class StatsVisualizer ( object ):
-
- def __init__ ( self, stats ):
- super ( StatsVisualizer, self ).__init__()
- self.stats = stats
- self.lines = None
-
- self.prepare()
- # --- end of __init__ (...) ---
-
- def prepare ( self ):
- raise MethodNotImplemented ( self, 'prepare' )
- # --- end of prepare (...) ---
-
- def __str__ ( self ):
- return '\n'.join ( self.lines )
- # --- end of __str__ (...) ---
-
-# --- end of StatsVisualizer ---
+from roverlay.util.objects import MethodNotImplementedError
class RoverlayStatsBase ( object ):
@@ -66,7 +39,7 @@ class RoverlayStatsBase ( object ):
self.merge_members ( other, my_cls._MEMBERS )
else:
- raise MethodNotImplemented ( self, 'merge_with' )
+ raise MethodNotImplementedError ( self, 'merge_with' )
# --- end of merge_with (...) ---
def merge_members ( self, other, members ):
@@ -86,7 +59,7 @@ class RoverlayStatsBase ( object ):
if int ( member ) != 0:
return member
else:
- raise MethodNotImplemented ( self, 'has_nonzero' )
+ raise MethodNotImplementedError ( self, 'has_nonzero' )
# --- end of has_nonzero (...) ---
def reset_members ( self ):
@@ -98,7 +71,7 @@ class RoverlayStatsBase ( object ):
if hasattr ( self.__class__, '_MEMBERS' ):
self.reset_members()
else:
- raise MethodNotImplemented ( self, 'reset' )
+ raise MethodNotImplementedError ( self, 'reset' )
# --- end of reset (...) ---
def get_description_str ( self ):
@@ -122,7 +95,7 @@ class RoverlayStatsBase ( object ):
if ret:
return ret
else:
- raise MethodNotImplemented ( self, '__str__' )
+ raise MethodNotImplementedError ( self, '__str__' )
# --- end of __str__ (...) ---
# --- end of RoverlayStatsBase ---
diff --git a/roverlay/stats/collector.py b/roverlay/stats/collector.py
index 3e3dee7..30b0e76 100644
--- a/roverlay/stats/collector.py
+++ b/roverlay/stats/collector.py
@@ -4,10 +4,15 @@
# Distributed under the terms of the GNU General Public License;
# either version 2 of the License, or (at your option) any later version.
-import collections
+import time
+
+import roverlay.config.static
from . import abstract
from . import base
+from . import dbcollector
+from . import visualize
+from . import rrd
class StatsCollector ( abstract.RoverlayStatsBase ):
@@ -57,13 +62,29 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
# --- end of get_net_gain (...) ---
def __init__ ( self ):
+ super ( StatsCollector, self ).__init__()
+
self.time = abstract.TimeStats ( "misc time stats" )
self.distmap = base.DistmapStats()
self.overlay = base.OverlayStats()
self.overlay_creation = base.OverlayCreationStats()
self.repo = base.RepoStats()
+ self.db_collector = None
+ self._database = None
# --- end of __init__ (...) ---
+ def setup_database ( self, config=None ):
+ conf = (
+ config if config is not None else roverlay.config.static.access()
+ )
+
+ self.db_collector = dbcollector.StatsDBCollector ( self )
+ self._database = rrd.StatsDB (
+ conf.get_or_fail ( "RRD_DB.file" ), self.db_collector
+ )
+ self._database.create_if_missing()
+ # --- end of setup_database (...) ---
+
def gen_str ( self ):
yield "{success}, overall {osuccess}".format (
success = self.get_success_ratio(),
@@ -77,136 +98,17 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
# --- end of gen_str (...) ---
def get_creation_str ( self ):
- return str ( CreationStatsVisualizer ( self ) )
+ return str ( visualize.CreationStatsVisualizer ( self ) )
# --- end of to_creation_str (...) ---
-# --- end of StatsCollector ---
-
-
-class CreationStatsVisualizer ( abstract.StatsVisualizer ):
-
- def prepare ( self ):
- EMPTY_LINE = ""
-
- pkg_count = self.stats.repo.pkg_count
- pkg_queued = self.stats.overlay_creation.pkg_queued
- pkg_fail = self.stats.overlay_creation.pkg_fail
- pkg_success = self.stats.overlay_creation.pkg_success
- ebuild_delta = self.stats.get_net_gain()
- revbumps = self.stats.overlay.revbump_count
-
- max_number_len = min (
- len ( str ( int ( k ) ) ) for k in (
- pkg_queued, pkg_fail, pkg_success
- )
- )
- max_number_len = min ( 5, max_number_len )
-
- success_ratio = self.stats.get_success_ratio()
- overall_success_ratio = self.stats.get_overall_success_ratio()
-
+ def write_db ( self ):
+ self.db_collector.update()
+ self._database.update()
+ self._database.commit()
+ # --- end of write_db (...) ---
- timestats = (
- ( 'scan_overlay', self.stats.overlay.scan_time.get_total_str() ),
- ( 'add_packages', self.stats.repo.queue_time.get_total_str() ),
- (
- 'ebuild_creation',
- self.stats.overlay_creation.creation_time.get_total_str()
- ),
- ( 'write_overlay', self.stats.overlay.write_time.get_total_str() ),
- )
-
- try:
- max_time_len = max ( len(k) for k, v in timestats if v is not None )
- except ValueError:
- # empty sequence -> no timestats
- max_time_len = -1
- else:
- # necessary?
- max_time_len = min ( 39, max_time_len )
-
-
- # create lines
- lines = collections.deque()
- unshift = lines.appendleft
- append = lines.append
-
- numstats = lambda k, s: "{num:<{l}d} {s}".format (
- num=int ( k ), s=s, l=max_number_len
- )
-
-
- append (
- 'success ratio {s_i:.2%} (overall {s_o:.2%})'.format (
- s_i = success_ratio.get_ratio(),
- s_o = overall_success_ratio.get_ratio()
- )
- )
- append ( EMPTY_LINE )
-
- append (
- "{e:+d} ebuilds ({r:d} revbumps)".format (
- e=ebuild_delta, r=int ( revbumps )
- )
- )
- append ( EMPTY_LINE )
-
- if int ( pkg_count ) != int ( pkg_queued ):
- append ( numstats (
- pkg_queued,
- '/ {n:d} packages added to the ebuild creation queue'.format (
- n=int ( pkg_count )
- )
- ) )
- else:
- append ( numstats (
- pkg_queued, 'packages added to the ebuild creation queue'
- ) )
-
- append ( numstats (
- pkg_success, 'packages passed ebuild creation'
- ) )
-
- append ( numstats (
- pkg_fail, 'packages failed ebuild creation'
- ) )
-
- if pkg_fail.has_details() and int ( pkg_fail ) != 0:
- append ( EMPTY_LINE )
- append ( "Details for ebuild creation failure:" )
- details = sorted (
- ( ( k, int(v) ) for k, v in pkg_fail.iter_details() ),
- key=lambda kv: kv[1]
- )
- dlen = len ( str ( max ( details, key=lambda kv: kv[1] ) [1] ) )
-
- for key, value in details:
- append ( "* {v:>{l}d}: {k}".format ( k=key, v=value, l=dlen ) )
- # -- end if <have pkg_fail details>
-
- if max_time_len > 0:
- # or >= 0
- append ( EMPTY_LINE )
- for k, v in timestats:
- if v is not None:
- append (
- "time for {0:<{l}} : {1}".format ( k, v, l=max_time_len )
- )
- # -- end if timestats
-
-
- append ( EMPTY_LINE )
-
- # add header/footer line(s)
- max_line_len = 2 + min ( 78, max ( len(s) for s in lines ) )
- unshift (
- "{0:-^{1}}\n".format ( " Overlay creation stats ", max_line_len )
- )
- append ( max_line_len * '-' )
+# --- end of StatsCollector ---
- self.lines = lines
- # --- end of gen_str (...) ---
-# --- end of CreationStatsVisualizer ---
static = StatsCollector()
StatsCollector._instance = static
diff --git a/roverlay/stats/dbcollector.py b/roverlay/stats/dbcollector.py
new file mode 100644
index 0000000..402e64d
--- /dev/null
+++ b/roverlay/stats/dbcollector.py
@@ -0,0 +1,74 @@
+# R overlay -- stats collection, prepare data for db storage
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import collections
+import weakref
+
+class StatsDBCollector ( object ):
+ VERSION = 0
+
+ # 'pc' := package count(er), 'ec' := ebuild _
+ NUMSTATS_KEYS = (
+ 'pc_repo', 'pc_distmap', 'pc_filtered', 'pc_queued', 'pc_success',
+ 'pc_fail', 'pc_fail_empty', 'pc_fail_dep', 'pc_fail_selfdep',
+ 'pc_fail_err',
+ 'ec_pre', 'ec_post', 'ec_written', 'ec_revbump',
+ )
+ NUMSTATS = collections.namedtuple (
+ "numstats", ' '.join ( NUMSTATS_KEYS )
+ )
+
+ TIMESTATS_KEYS = ()
+ TIMESTATS = collections.namedtuple (
+ "timestats", ' '.join ( TIMESTATS_KEYS )
+ )
+
+ def __init__ ( self, stats ):
+ super ( StatsDBCollector, self ).__init__()
+ self.stats = weakref.ref ( stats )
+ self._collected_stats = None
+ # --- end of __init__ (...) ---
+
+ def update ( self ):
+ self._collected_stats = self.make_all()
+ # --- end of update (...) ---
+
+ def make_numstats ( self ):
+ stats = self.stats()
+ ov_create = stats.overlay_creation
+ ov = stats.overlay
+
+ return self.__class__.NUMSTATS (
+ pc_repo = int ( stats.repo.pkg_count ),
+ pc_distmap = int ( stats.distmap.pkg_count ),
+ pc_filtered = int ( ov_create.pkg_filtered ),
+ pc_queued = int ( ov_create.pkg_queued ),
+ pc_success = int ( ov_create.pkg_success ),
+ pc_fail = int ( ov_create.pkg_fail ),
+ pc_fail_empty = ov_create.pkg_fail.get ( 'empty_desc' ),
+ pc_fail_dep = ov_create.pkg_fail.get ( 'unresolved_deps' ),
+ pc_fail_selfdep = ov_create.pkg_fail.get ( 'bad_selfdeps' ),
+ pc_fail_err = ov_create.pkg_fail.get ( 'exception' ),
+ ec_pre = int ( ov.ebuilds_scanned ),
+ ec_post = int ( ov.ebuild_count ),
+ ec_written = int ( ov.ebuilds_written ),
+ ec_revbump = int ( ov.revbump_count ),
+ )
+ # --- end of make_numstats (...) ---
+
+ def make_timestats ( self ):
+ return ()
+ # --- end of make_timestats (...) ---
+
+ def make_all ( self ):
+ return self.make_numstats() + self.make_timestats()
+ # --- end of make_all (...) ---
+
+ def get_all ( self ):
+ return self._collected_stats
+ # --- end of get_all (...) ---
+
+# --- end of StatsDBCollector #v0 ---
diff --git a/roverlay/stats/rrd.py b/roverlay/stats/rrd.py
new file mode 100644
index 0000000..66da434
--- /dev/null
+++ b/roverlay/stats/rrd.py
@@ -0,0 +1,63 @@
+# R overlay -- stats collection, rrd database (using rrdtool)
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+
+# NOT using rrdtool's python bindings as they're available for python 2 only
+
+import roverlay.db.rrdtool
+from roverlay.db.rrdtool import RRDVariable, RRDArchive
+
+
+class StatsDB ( roverlay.db.rrdtool.RRD ):
+
+ # default step
+ STEP = 300
+
+ def __init__ ( self, filepath, collector, step=None ):
+ # COULDFIX:
+ # vars / RRA creation is only necessary when creating a new database
+ #
+ self.collector = collector
+ self.rrd_vars = self.make_vars()
+ self.rrd_archives = self.make_rra()
+ self.step = step if step is not None else self.__class__.STEP
+ super ( StatsDB, self ).__init__ ( filepath )
+ # --- end of __init__ (...) ---
+
+ def _do_create ( self, filepath ):
+ return self._call_rrdtool (
+ (
+ 'create', filepath,
+ '--start', str ( self.INIT_TIME ),
+ '--step', str ( self.step ),
+ ) + tuple (
+ v.get_key() for v in self.rrd_vars
+ ) + tuple (
+ v.get_key() for v in self.rrd_archives
+ )
+ )
+ # --- end of _do_create (...) ---
+
+ def update ( self ):
+ self.add ( self.collector.get_all() )
+ # --- end of update (...) ---
+
+ def make_vars ( self ):
+ return tuple (
+ RRDVariable ( k, 'DERIVE', val_max=0 )
+ for k in self.collector.NUMSTATS_KEYS
+ )
+ # --- end of make_vars (...) ---
+
+ def make_rra ( self ):
+ return (
+ RRDArchive.new_day ( 'LAST', 0.7 ),
+ RRDArchive.new_week ( 'AVERAGE', 0.7 ),
+ RRDArchive.new_month ( 'AVERAGE', 0.7 ),
+ )
+ # --- end of make_rra (...) ---
+
+# --- end of StatsDB ---
diff --git a/roverlay/stats/collector.py b/roverlay/stats/visualize.py
similarity index 61%
copy from roverlay/stats/collector.py
copy to roverlay/stats/visualize.py
index 3e3dee7..09ca48e 100644
--- a/roverlay/stats/collector.py
+++ b/roverlay/stats/visualize.py
@@ -1,4 +1,4 @@
-# R overlay -- stats collection, stats collector
+# R overlay -- stats collection, print stats
# -*- coding: utf-8 -*-
# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
# Distributed under the terms of the GNU General Public License;
@@ -6,84 +6,31 @@
import collections
-from . import abstract
-from . import base
+import roverlay.util.objects
-class StatsCollector ( abstract.RoverlayStatsBase ):
+class StatsVisualizer ( object ):
- _instance = None
+ def __init__ ( self, stats ):
+ super ( StatsVisualizer, self ).__init__()
+ self.stats = stats
+ self.lines = None
- _MEMBERS = ( 'time', 'repo', 'distmap', 'overlay_creation', 'overlay', )
-
- @classmethod
- def get_instance ( cls ):
- return cls._instance
- # --- end of instance (...) ---
-
- def get_success_ratio ( self ):
- # success ratio for "this" run:
- # new ebuilds / relevant package count (new packages - unsuitable,
- # where unsuitable is e.g. "OS_Type not supported")
- #
- return abstract.SuccessRatio (
- num_ebuilds = self.overlay_creation.pkg_success,
- num_pkg = self.overlay_creation.get_relevant_package_count(),
- )
- # --- end of get_success_ratio (...) ---
-
- def get_overall_success_ratio ( self ):
- # overall success ratio:
- # "relevant ebuild count" / "guessed package count"
- # ratio := <all ebuilds> / (<all ebuilds> + <failed packages>)
- #
- #
- # *Not* accurate as it includes imported ebuilds
- # (Still better than using the repo package count since that may
- # not include old package files)
- #
- return abstract.SuccessRatio (
- num_ebuilds = self.overlay.ebuild_count,
- num_pkg = (
- self.overlay.ebuild_count + self.overlay_creation.pkg_fail
- ),
- )
- # --- end of get_overall_success_ratio (...) ---
-
- def get_net_gain ( self ):
- return (
- self.overlay.ebuild_count - self.overlay.ebuilds_scanned
- )
- # --- end of get_net_gain (...) ---
-
- def __init__ ( self ):
- self.time = abstract.TimeStats ( "misc time stats" )
- self.distmap = base.DistmapStats()
- self.overlay = base.OverlayStats()
- self.overlay_creation = base.OverlayCreationStats()
- self.repo = base.RepoStats()
+ self.prepare()
# --- end of __init__ (...) ---
- def gen_str ( self ):
- yield "{success}, overall {osuccess}".format (
- success = self.get_success_ratio(),
- osuccess = self.get_overall_success_ratio(),
- )
- yield ""
-
- for s in super ( StatsCollector, self ).gen_str():
- yield s
- yield ""
- # --- end of gen_str (...) ---
-
- def get_creation_str ( self ):
- return str ( CreationStatsVisualizer ( self ) )
- # --- end of to_creation_str (...) ---
+ @roverlay.util.objects.not_implemented
+ def prepare ( self ):
+ pass
+ # --- end of prepare (...) ---
-# --- end of StatsCollector ---
+ def __str__ ( self ):
+ return '\n'.join ( self.lines )
+ # --- end of __str__ (...) ---
+# --- end of StatsVisualizer ---
-class CreationStatsVisualizer ( abstract.StatsVisualizer ):
+class CreationStatsVisualizer ( StatsVisualizer ):
def prepare ( self ):
EMPTY_LINE = ""
@@ -206,7 +153,5 @@ class CreationStatsVisualizer ( abstract.StatsVisualizer ):
self.lines = lines
# --- end of gen_str (...) ---
-# --- end of CreationStatsVisualizer ---
-static = StatsCollector()
-StatsCollector._instance = static
+# --- end of CreationStatsVisualizer ---
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-07-29 8:55 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-07-29 8:55 UTC (permalink / raw
To: gentoo-commits
commit: 55537b3dd0f8f1624f882af50f5dc9ea0de65678
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jul 29 08:54:35 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jul 29 08:54:35 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=55537b3d
visualize stats (formatted str output)
---
roverlay/stats/abstract.py | 68 +++++++++++++++++++++-
roverlay/stats/collector.py | 137 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 204 insertions(+), 1 deletion(-)
diff --git a/roverlay/stats/abstract.py b/roverlay/stats/abstract.py
index 36c81ca..6d0575a 100644
--- a/roverlay/stats/abstract.py
+++ b/roverlay/stats/abstract.py
@@ -18,6 +18,26 @@ class MethodNotImplemented ( NotImplementedError ):
# --- end of MethodNotImplemented ---
+class StatsVisualizer ( object ):
+
+ def __init__ ( self, stats ):
+ super ( StatsVisualizer, self ).__init__()
+ self.stats = stats
+ self.lines = None
+
+ self.prepare()
+ # --- end of __init__ (...) ---
+
+ def prepare ( self ):
+ raise MethodNotImplemented ( self, 'prepare' )
+ # --- end of prepare (...) ---
+
+ def __str__ ( self ):
+ return '\n'.join ( self.lines )
+ # --- end of __str__ (...) ---
+
+# --- end of StatsVisualizer ---
+
class RoverlayStatsBase ( object ):
@@ -60,6 +80,15 @@ class RoverlayStatsBase ( object ):
yield getattr ( self, member )
# --- end of _iter_members (...) ---
+ def has_nonzero ( self ):
+ if hasattr ( self, '_MEMBERS' ):
+ for member in self._iter_members():
+ if int ( member ) != 0:
+ return member
+ else:
+ raise MethodNotImplemented ( self, 'has_nonzero' )
+ # --- end of has_nonzero (...) ---
+
def reset_members ( self ):
for member in self._iter_members():
member.reset()
@@ -166,9 +195,29 @@ class TimeStats ( RoverlayStats ):
# --- end of end (...) ---
def get_total ( self ):
- return sum ( v.get_delta() for v in self._timestats.values() )
+ return float (
+ sum ( filter (
+ lambda k: k > 0.0,
+ ( v.get_delta() for v in self._timestats.values() )
+ ) )
+ )
# --- end of get_total (...) ---
+ def get_total_str ( self,
+ unknown_threshold=0.00001, ms_threshold=1.0, min_threshold=300.0,
+ unknown_return=None
+ ):
+ t = self.get_total()
+ if t < unknown_threshold:
+ return unknown_return
+ elif t < ms_threshold:
+ return "{:.2f} ms".format ( t * 1000 )
+ elif t > min_threshold:
+ return "{:.2f} minutes".format ( t / 60.0 )
+ else:
+ return "{:.2f} seconds".format ( t )
+ # --- end of get_total_str (...) ---
+
def gen_str ( self ):
desc = self.get_description_str()
if desc:
@@ -211,6 +260,10 @@ class Counter ( RoverlayStatsBase ):
return self.total_count - int ( other )
# --- end of __sub__ (...) ---
+ def has_details ( self ):
+ return False
+ # --- end of has_details (...) ---
+
def reset ( self ):
self.total_count = 0
self.underflow = False
@@ -256,6 +309,14 @@ class DetailedCounter ( Counter ):
self._detailed_count = collections.defaultdict ( int )
# --- end of __init__ (...) ---
+ def has_details ( self ):
+ return any ( int(v) != 0 for v in self._detailed_count.values() )
+ # --- end of has_details (...) ---
+
+ def iter_details ( self ):
+ return ( kv for kv in self._detailed_count.items() if int(kv[1]) != 0 )
+ # --- end of iter_details (...) ---
+
def __getitem__ ( self, key ):
if key in self._detailed_count:
return self._detailed_count [key]
@@ -350,6 +411,11 @@ class SuccessRatio ( object ):
return float ( self.ebuild_count ) / float ( self.pkg_count )
# --- end of get_ratio (...) ---
+ @property
+ def ratio ( self ):
+ return self.get_ratio()
+ # --- end of ratio (...) ---
+
def __float__ ( self ):
return self.get_ratio()
# --- end of __float__ (...) ---
diff --git a/roverlay/stats/collector.py b/roverlay/stats/collector.py
index 1b122f4..3e3dee7 100644
--- a/roverlay/stats/collector.py
+++ b/roverlay/stats/collector.py
@@ -4,6 +4,8 @@
# Distributed under the terms of the GNU General Public License;
# either version 2 of the License, or (at your option) any later version.
+import collections
+
from . import abstract
from . import base
@@ -48,6 +50,12 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
)
# --- end of get_overall_success_ratio (...) ---
+ def get_net_gain ( self ):
+ return (
+ self.overlay.ebuild_count - self.overlay.ebuilds_scanned
+ )
+ # --- end of get_net_gain (...) ---
+
def __init__ ( self ):
self.time = abstract.TimeStats ( "misc time stats" )
self.distmap = base.DistmapStats()
@@ -68,8 +76,137 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
yield ""
# --- end of gen_str (...) ---
+ def get_creation_str ( self ):
+ return str ( CreationStatsVisualizer ( self ) )
+ # --- end of to_creation_str (...) ---
# --- end of StatsCollector ---
+
+class CreationStatsVisualizer ( abstract.StatsVisualizer ):
+
+ def prepare ( self ):
+ EMPTY_LINE = ""
+
+ pkg_count = self.stats.repo.pkg_count
+ pkg_queued = self.stats.overlay_creation.pkg_queued
+ pkg_fail = self.stats.overlay_creation.pkg_fail
+ pkg_success = self.stats.overlay_creation.pkg_success
+ ebuild_delta = self.stats.get_net_gain()
+ revbumps = self.stats.overlay.revbump_count
+
+ max_number_len = min (
+ len ( str ( int ( k ) ) ) for k in (
+ pkg_queued, pkg_fail, pkg_success
+ )
+ )
+ max_number_len = min ( 5, max_number_len )
+
+ success_ratio = self.stats.get_success_ratio()
+ overall_success_ratio = self.stats.get_overall_success_ratio()
+
+
+ timestats = (
+ ( 'scan_overlay', self.stats.overlay.scan_time.get_total_str() ),
+ ( 'add_packages', self.stats.repo.queue_time.get_total_str() ),
+ (
+ 'ebuild_creation',
+ self.stats.overlay_creation.creation_time.get_total_str()
+ ),
+ ( 'write_overlay', self.stats.overlay.write_time.get_total_str() ),
+ )
+
+ try:
+ max_time_len = max ( len(k) for k, v in timestats if v is not None )
+ except ValueError:
+ # empty sequence -> no timestats
+ max_time_len = -1
+ else:
+ # necessary?
+ max_time_len = min ( 39, max_time_len )
+
+
+ # create lines
+ lines = collections.deque()
+ unshift = lines.appendleft
+ append = lines.append
+
+ numstats = lambda k, s: "{num:<{l}d} {s}".format (
+ num=int ( k ), s=s, l=max_number_len
+ )
+
+
+ append (
+ 'success ratio {s_i:.2%} (overall {s_o:.2%})'.format (
+ s_i = success_ratio.get_ratio(),
+ s_o = overall_success_ratio.get_ratio()
+ )
+ )
+ append ( EMPTY_LINE )
+
+ append (
+ "{e:+d} ebuilds ({r:d} revbumps)".format (
+ e=ebuild_delta, r=int ( revbumps )
+ )
+ )
+ append ( EMPTY_LINE )
+
+ if int ( pkg_count ) != int ( pkg_queued ):
+ append ( numstats (
+ pkg_queued,
+ '/ {n:d} packages added to the ebuild creation queue'.format (
+ n=int ( pkg_count )
+ )
+ ) )
+ else:
+ append ( numstats (
+ pkg_queued, 'packages added to the ebuild creation queue'
+ ) )
+
+ append ( numstats (
+ pkg_success, 'packages passed ebuild creation'
+ ) )
+
+ append ( numstats (
+ pkg_fail, 'packages failed ebuild creation'
+ ) )
+
+ if pkg_fail.has_details() and int ( pkg_fail ) != 0:
+ append ( EMPTY_LINE )
+ append ( "Details for ebuild creation failure:" )
+ details = sorted (
+ ( ( k, int(v) ) for k, v in pkg_fail.iter_details() ),
+ key=lambda kv: kv[1]
+ )
+ dlen = len ( str ( max ( details, key=lambda kv: kv[1] ) [1] ) )
+
+ for key, value in details:
+ append ( "* {v:>{l}d}: {k}".format ( k=key, v=value, l=dlen ) )
+ # -- end if <have pkg_fail details>
+
+ if max_time_len > 0:
+ # or >= 0
+ append ( EMPTY_LINE )
+ for k, v in timestats:
+ if v is not None:
+ append (
+ "time for {0:<{l}} : {1}".format ( k, v, l=max_time_len )
+ )
+ # -- end if timestats
+
+
+ append ( EMPTY_LINE )
+
+ # add header/footer line(s)
+ max_line_len = 2 + min ( 78, max ( len(s) for s in lines ) )
+ unshift (
+ "{0:-^{1}}\n".format ( " Overlay creation stats ", max_line_len )
+ )
+ append ( max_line_len * '-' )
+
+ self.lines = lines
+ # --- end of gen_str (...) ---
+# --- end of CreationStatsVisualizer ---
+
static = StatsCollector()
StatsCollector._instance = static
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-07-26 13:02 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-07-26 13:02 UTC (permalink / raw
To: gentoo-commits
commit: d1ca42185a44d01176d9944e95a112493401f1f6
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jul 26 12:57:41 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jul 26 12:57:41 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d1ca4218
statc collection: data types, time stats
---
roverlay/stats/abstract.py | 125 +++++++++++++++++++++++++++++++++++++++-----
roverlay/stats/base.py | 54 ++++++++++++++-----
roverlay/stats/collector.py | 31 ++++++++---
3 files changed, 177 insertions(+), 33 deletions(-)
diff --git a/roverlay/stats/abstract.py b/roverlay/stats/abstract.py
index 993d48b..36c81ca 100644
--- a/roverlay/stats/abstract.py
+++ b/roverlay/stats/abstract.py
@@ -26,15 +26,31 @@ class RoverlayStatsBase ( object ):
return cls()
# --- end of get_new (...) ---
+ def __init__ ( self, description=None ):
+ super ( RoverlayStatsBase, self ).__init__()
+ if description is not None:
+ self.description = description
+ # --- end of __init__ (...) ---
+
def merge_with ( self, other ):
- if hasattr ( self, '_MEMBERS' ):
- self.merge_members ( other )
+ my_cls = self.__class__
+ their_cls = other.__class__
+
+ if (
+ issubclass ( my_cls, their_cls )
+ and hasattr ( their_cls, '_MEMBERS' )
+ ):
+ self.merge_members ( other, their_cls._MEMBERS )
+
+ elif hasattr ( my_cls, '_MEMBERS' ):
+ self.merge_members ( other, my_cls._MEMBERS )
+
else:
raise MethodNotImplemented ( self, 'merge_with' )
# --- end of merge_with (...) ---
- def merge_members ( self, other ):
- for member in self.__class__._MEMBERS:
+ def merge_members ( self, other, members ):
+ for member in members:
getattr ( self, member ).merge_with ( getattr ( other, member ) )
# --- end of merge_members (...) ---
@@ -84,21 +100,96 @@ class RoverlayStatsBase ( object ):
class RoverlayStats ( RoverlayStatsBase ):
+ pass
+# --- end of RoverlayStats ---
- def get_time ( self ):
- return time.time()
- # --- end of get_time (...) ---
- def get_time_delta ( self, start, stop=None ):
- t_stop = self.get_time() if stop is None else stop
- return ( start - t_stop, t_stop )
- # --- end of get_time_delta (...) ---
+class TimeStatsItem ( RoverlayStatsBase ):
+ # doc TODO: note somewhere that those timestats are just approximate
+ # values
+
+ def __init__ ( self, t_begin=None, t_end=None, description=None ):
+ super ( TimeStatsItem, self ).__init__ ( description=description )
+ self.time_begin = t_begin if t_begin is not None else time.time()
+ self.time_end = t_end
+ # --- end of __init__ (...) ---
+
+ def end ( self, t_end=None ):
+ self.time_end = time.time() if t_end is None else t_end
+ # --- end of end (...) ---
+
+ def get_delta ( self ):
+ if self.time_begin is None:
+ return -1.0
+ elif self.time_end is None:
+ return -2.0
+ else:
+ return float ( self.time_end ) - float ( self.time_begin )
+ # --- end of get_delta (...) ---
+
+ def __str__ ( self ):
+ return "{:.3f}s".format ( self.get_delta() )
+ # --- end of __str__ (...) ---
+
+# --- end of TimeStatsItem ---
+
+
+class TimeStats ( RoverlayStats ):
+
+ def __init__ ( self, description=None ):
+ super ( TimeStats, self ).__init__ ( description=description )
+ self._timestats = collections.OrderedDict()
+ # --- end of __init__ (...) ---
+
+ def merge_with ( self, other ):
+ self._timestats.update ( other._timestats )
+ # --- end of merge_with (...) ---
+
+ def get ( self, key ):
+ return self._timestats.get ( key, -1.0 )
+ # --- end of get (...) ---
+
+ def __getitem__ ( self, key ):
+ return self._timestats [key]
+ # --- end of __getitem__ (...) ---
+
+ def begin ( self, key ):
+ item = TimeStatsItem()
+ self._timestats [key] = item
+ return item
+ # --- end of begin (...) ---
+
+ def end ( self, key ):
+ item = self._timestats [key]
+ item.end()
+ return item
+ # --- end of end (...) ---
+
+ def get_total ( self ):
+ return sum ( v.get_delta() for v in self._timestats.values() )
+ # --- end of get_total (...) ---
+
+ def gen_str ( self ):
+ desc = self.get_description_str()
+ if desc:
+ yield "{} ({:.3f}s)".format ( desc, self.get_total() )
+ else:
+ yield "total time: {:.3f}s".format ( self.get_total() )
+
+ for key, value in self._timestats.items():
+ yield "* {k}: {v}".format ( k=key, v=str ( value ) )
+ # --- end of gen_str (...) ---
+
+ def __str__ ( self ):
+ return '\n'.join ( self.gen_str() )
+ # --- end of __str__ (...) ---
+
+# --- end of TimeStats ---
-# --- end of RoverlayStats ---
class Counter ( RoverlayStatsBase ):
def __init__ ( self, description=None, initial_value=0 ):
- super ( Counter, self ).__init__()
+ super ( Counter, self ).__init__ ( description=description )
self.description = description
self.total_count = initial_value
self.underflow = False
@@ -112,6 +203,14 @@ class Counter ( RoverlayStatsBase ):
return float ( self.total_count )
# --- end of __float__ (...) ---
+ def __add__ ( self, other ):
+ return self.total_count + int ( other )
+ # --- end of __add__ (...) ---
+
+ def __sub__ ( self, other ):
+ return self.total_count - int ( other )
+ # --- end of __sub__ (...) ---
+
def reset ( self ):
self.total_count = 0
self.underflow = False
diff --git a/roverlay/stats/base.py b/roverlay/stats/base.py
index b03092b..2f13e73 100644
--- a/roverlay/stats/base.py
+++ b/roverlay/stats/base.py
@@ -8,11 +8,13 @@ from . import abstract
class RepoStats ( abstract.RoverlayStats ):
- _MEMBERS = frozenset ({ 'pkg_count', })
+ _MEMBERS = ( 'sync_time', 'queue_time', 'pkg_count', )
def __init__ ( self ):
super ( RepoStats, self ).__init__()
- self.pkg_count = abstract.DetailedCounter (
+ self.sync_time = abstract.TimeStats ( 'sync_time' )
+ self.queue_time = abstract.TimeStats ( 'queue_time' )
+ self.pkg_count = abstract.DetailedCounter (
description="package count"
)
# --- end of __init__ (...) ---
@@ -26,7 +28,7 @@ class RepoStats ( abstract.RoverlayStats ):
class DistmapStats ( abstract.RoverlayStats ):
- _MEMBERS = frozenset ({ 'pkg_count', })
+ _MEMBERS = ( 'pkg_count', )
def __init__ ( self ):
super ( DistmapStats, self ).__init__()
@@ -46,31 +48,56 @@ class DistmapStats ( abstract.RoverlayStats ):
# --- end of DistmapStats ---
-class OverlayCreationStats ( abstract.RoverlayStats ):
+class OverlayCreationWorkerStats ( abstract.RoverlayStats ):
- #_MEMBERS = frozenset({})
+ _MEMBERS = ( 'pkg_processed', 'pkg_fail', 'pkg_success', )
+
+ def __init__ ( self ):
+ self.pkg_processed = abstract.Counter ( "processed" )
+ self.pkg_fail = abstract.DetailedCounter ( "fail" )
+ self.pkg_success = abstract.Counter ( "success" )
+ # --- end of __init__ (...) ---
+
+# --- end of OverlayCreationWorkerStats ---
+
+
+class OverlayCreationStats ( OverlayCreationWorkerStats ):
+
+ DESCRIPTION = "overlay creation"
+
+ _MEMBERS = (
+ ( 'creation_time', 'pkg_queued', 'pkg_filtered', )
+ + OverlayCreationWorkerStats._MEMBERS
+ )
def __init__ ( self ):
super ( OverlayCreationStats, self ).__init__()
+ self.pkg_queued = abstract.Counter ( "queued" )
+ self.pkg_filtered = abstract.Counter ( "filtered" )
+ self.creation_time = abstract.TimeStats ( "ebuild creation" )
# --- end of __init__ (...) ---
def get_relevant_package_count ( self ):
- print ( "get_relevant_package_count(): method stub" )
- return 0
+ return self.pkg_queued
+ #return self.pkg_queued - self.pkg_fail.get ( "empty_desc" )
# --- end of get_relevant_package_count (...) ---
- def __str__ ( self ):
- return "*** no overlay creation stats available ***"
- # --- end of __str__ (...) ---
+ @classmethod
+ def get_new ( cls ):
+ return OverlayCreationWorkerStats()
+ # --- end of get_new (...) ---
# --- end of OverlayCreationStats ---
class OverlayStats ( abstract.RoverlayStats ):
- _MEMBERS = frozenset ({
+ DESCRIPTION = "overlay"
+
+ _MEMBERS = (
+ 'scan_time', 'write_time',
'ebuilds_scanned', 'ebuild_count', 'ebuilds_written',
- })
+ )
def __init__ ( self ):
super ( OverlayStats, self ).__init__()
@@ -81,6 +108,9 @@ class OverlayStats ( abstract.RoverlayStats ):
self.ebuild_count = abstract.Counter ( "post" )
self.ebuilds_written = abstract.Counter ( "written" )
+
+ self.write_time = abstract.TimeStats ( "write_time" )
+ self.scan_time = abstract.TimeStats ( "scan_time" )
# --- end of __init__ (...) ---
# --- end of OverlayStats ---
diff --git a/roverlay/stats/collector.py b/roverlay/stats/collector.py
index d3c318e..1b122f4 100644
--- a/roverlay/stats/collector.py
+++ b/roverlay/stats/collector.py
@@ -12,7 +12,7 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
_instance = None
- _MEMBERS = [ 'repo', 'distmap', 'overlay_creation', 'overlay', ]
+ _MEMBERS = ( 'time', 'repo', 'distmap', 'overlay_creation', 'overlay', )
@classmethod
def get_instance ( cls ):
@@ -25,35 +25,50 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
# where unsuitable is e.g. "OS_Type not supported")
#
return abstract.SuccessRatio (
- num_ebuilds = self.overlay.ebuild_count.get ( "new" ),
+ num_ebuilds = self.overlay_creation.pkg_success,
num_pkg = self.overlay_creation.get_relevant_package_count(),
)
# --- end of get_success_ratio (...) ---
def get_overall_success_ratio ( self ):
# overall success ratio:
- # all ebuilds / distmap file count
+ # "relevant ebuild count" / "guessed package count"
+ # ratio := <all ebuilds> / (<all ebuilds> + <failed packages>)
#
- # *Not* accurate as it includes imported ebuilds and assumes that
- # each ebuild has one source file in the distmap.
+ #
+ # *Not* accurate as it includes imported ebuilds
# (Still better than using the repo package count since that may
# not include old package files)
#
- # !!! useless. distmap includes "successful" packages only
- #
return abstract.SuccessRatio (
num_ebuilds = self.overlay.ebuild_count,
- num_pkg = self.distmap.pkg_count,
+ num_pkg = (
+ self.overlay.ebuild_count + self.overlay_creation.pkg_fail
+ ),
)
# --- end of get_overall_success_ratio (...) ---
def __init__ ( self ):
+ self.time = abstract.TimeStats ( "misc time stats" )
self.distmap = base.DistmapStats()
self.overlay = base.OverlayStats()
self.overlay_creation = base.OverlayCreationStats()
self.repo = base.RepoStats()
# --- end of __init__ (...) ---
+ def gen_str ( self ):
+ yield "{success}, overall {osuccess}".format (
+ success = self.get_success_ratio(),
+ osuccess = self.get_overall_success_ratio(),
+ )
+ yield ""
+
+ for s in super ( StatsCollector, self ).gen_str():
+ yield s
+ yield ""
+ # --- end of gen_str (...) ---
+
+
# --- end of StatsCollector ---
static = StatsCollector()
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-07-25 15:20 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-07-25 15:20 UTC (permalink / raw
To: gentoo-commits
commit: 4b9358dbf616678865d53b699e4ba6734b00b6d2
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jul 25 14:31:32 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jul 25 14:31:32 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=4b9358db
stats collection: data types, overlay stats
---
roverlay/stats/abstract.py | 109 ++++++++++++++++++++++++++++++++------------
roverlay/stats/base.py | 24 ++++++----
roverlay/stats/collector.py | 6 +--
3 files changed, 98 insertions(+), 41 deletions(-)
diff --git a/roverlay/stats/abstract.py b/roverlay/stats/abstract.py
index b6a4ee9..a8a2200 100644
--- a/roverlay/stats/abstract.py
+++ b/roverlay/stats/abstract.py
@@ -4,9 +4,21 @@
# Distributed under the terms of the GNU General Public License;
# either version 2 of the License, or (at your option) any later version.
+from __future__ import division
+
import collections
import time
+class MethodNotImplemented ( NotImplementedError ):
+ def __init__ ( self, obj, method ):
+ super ( MethodNotImplemented, self ).__init__ (
+ "{n}.{f}()".format ( n=obj.__class__.__name__, f=method )
+ )
+ # --- end of __init__ (...) ---
+
+# --- end of MethodNotImplemented ---
+
+
class RoverlayStatsBase ( object ):
@classmethod
@@ -15,9 +27,17 @@ class RoverlayStatsBase ( object ):
# --- end of get_new (...) ---
def merge_with ( self, other ):
- raise NotImplementedError()
+ if hasattr ( self, '_MEMBERS' ):
+ self.merge_members ( other )
+ else:
+ raise MethodNotImplemented ( self, 'merge_with' )
# --- end of merge_with (...) ---
+ def merge_members ( self, other ):
+ for member in self.__class__._MEMBERS:
+ getattr ( self, member ).merge_with ( getattr ( other, member ) )
+ # --- end of merge_members (...) ---
+
def _iter_members ( self, nofail=False ):
if not nofail or hasattr ( self, '_MEMBERS' ):
for member in self.__class__._MEMBERS:
@@ -33,7 +53,7 @@ class RoverlayStatsBase ( object ):
if hasattr ( self.__class__, '_MEMBERS' ):
self.reset_members()
else:
- raise NotImplementedError()
+ raise MethodNotImplemented ( self, 'reset' )
# --- end of reset (...) ---
def get_description_str ( self ):
@@ -57,7 +77,7 @@ class RoverlayStatsBase ( object ):
if ret:
return ret
else:
- raise NotImplementedError()
+ raise MethodNotImplemented ( self, '__str__' )
# --- end of __str__ (...) ---
# --- end of RoverlayStatsBase ---
@@ -76,14 +96,61 @@ class RoverlayStats ( RoverlayStatsBase ):
# --- end of RoverlayStats ---
+class Counter ( RoverlayStatsBase ):
+ def __init__ ( self, description=None, initial_value=0 ):
+ super ( Counter, self ).__init__()
+ self.description = description
+ self.total_count = initial_value
+ self.underflow = False
+ # --- end of __init__ (...) ---
+
+ def __int__ ( self ):
+ return self.total_count
+ # --- end of __int__ (...) ---
+
+ def __float__ ( self ):
+ return float ( self.total_count )
+ # --- end of __float__ (...) ---
+
+ def reset ( self ):
+ self.total_count = 0
+ self.underflow = False
+ # --- end of reset (...) ---
+
+ def inc ( self, step=1 ):
+ self.total_count += step
+ # --- end of inc (...) ---
+
+ def dec ( self, step=1 ):
+ self.total_count -= step
+ if self.total_count < 0:
+ self.underflow = True
+ # --- end of dec (...) ---
+
+ def merge_with ( self, other ):
+ self.total_count += other.total_count
+ if other.underflow:
+ self.underflow = True
+ # --- end of merge_with (...) ---
+
+ def gen_str ( self ):
+ desc = self.get_description_str()
+ if desc:
+ yield "{}: {:d}".format ( desc, self.total_count )
+ else:
+ yield str ( self.total_count )
+
+ if self.underflow:
+ yield "*** underflow detected ***"
+ # --- end of gen_str (...) ---
+
+# --- end of Counter ---
+
-class DetailedCounter ( RoverlayStatsBase ):
+class DetailedCounter ( Counter ):
def __init__ ( self, description=None ):
- super ( DetailedCounter, self ).__init__()
- self.description = description
- self.total_count = 0
+ super ( DetailedCounter, self ).__init__ ( description=description )
self._detailed_count = collections.defaultdict ( int )
- self.underflow = False
# --- end of __init__ (...) ---
def __getitem__ ( self, key ):
@@ -93,14 +160,6 @@ class DetailedCounter ( RoverlayStatsBase ):
raise KeyError ( key )
# --- end of __getitem__ (...) ---
- def __int__ ( self ):
- return self.total_count
- # --- end of __int__ (...) ---
-
- def __float__ ( self ):
- return float ( self.total_count )
- # --- end of __float__ (...) ---
-
def get ( self, key=None, fallback=0 ):
if key is None:
return self.total_count
@@ -111,8 +170,7 @@ class DetailedCounter ( RoverlayStatsBase ):
# --- end of get (...) ---
def reset ( self ):
- self.total_count = 0
- self.underflow = False
+ super ( DetailedCounter, self ).reset()
self._detailed_count.clear()
# --- end of reset (...) ---
@@ -121,8 +179,8 @@ class DetailedCounter ( RoverlayStatsBase ):
self._detailed_count [k] += 1
# --- end of inc_details_v (...) ---
- def inc ( self, *details ):
- self.total_count += 1
+ def inc ( self, *details, **kw ):
+ super ( DetailedCounter, self ).inc ( **kw )
self.inc_details_v ( details )
# --- end of inc (...) ---
@@ -139,10 +197,8 @@ class DetailedCounter ( RoverlayStatsBase ):
self.underflow = True
# --- end of dec_details_v (...) ---
- def dec ( self, *details ):
- self.total_count -= 1
- if self.total_count < 0:
- self.underflow = True
+ def dec ( self, *details, **kw ):
+ super ( DetailedCounter, self ).dec ( **kw )
self.dec_details_v ( details )
# --- end of dec (...) ---
@@ -151,12 +207,9 @@ class DetailedCounter ( RoverlayStatsBase ):
# --- end of dec_details (...) ---
def merge_with ( self, other ):
- self.total_count += other.totalcount
+ super ( DetailedCounter, self ).merge_with ( other )
for key, value in other._detailed_count.items():
self._detailed_count [key] += value
-
- if other.underflow:
- self.underflow = True
# --- end of merge_with (...) ---
def gen_str ( self ):
diff --git a/roverlay/stats/base.py b/roverlay/stats/base.py
index 6e37581..b03092b 100644
--- a/roverlay/stats/base.py
+++ b/roverlay/stats/base.py
@@ -59,24 +59,28 @@ class OverlayCreationStats ( abstract.RoverlayStats ):
return 0
# --- end of get_relevant_package_count (...) ---
+ def __str__ ( self ):
+ return "*** no overlay creation stats available ***"
+ # --- end of __str__ (...) ---
+
# --- end of OverlayCreationStats ---
class OverlayStats ( abstract.RoverlayStats ):
- _MEMBERS = frozenset({ 'ebuild_count', })
+ _MEMBERS = frozenset ({
+ 'ebuilds_scanned', 'ebuild_count', 'ebuilds_written',
+ })
def __init__ ( self ):
super ( OverlayStats, self ).__init__()
- # ebuild_count counts *physical* ebuilds
- # number of created ebuilds is part of overlay creation stats
- self.ebuild_count = abstract.DetailedCounter (
- description="ebuild count"
- )
- # --- end of __init__ (...) ---
+ # ebuilds_scanned: ebuild count prior to running overlay creation
+ self.ebuilds_scanned = abstract.Counter ( "pre" )
- def ebuild_added ( self, origin ):
- self.ebuild_count.inc ( origin )
- # --- end of ebuild_added (...) ---
+ # ebuild count: ebuild count after writing the overlay
+ self.ebuild_count = abstract.Counter ( "post" )
+
+ self.ebuilds_written = abstract.Counter ( "written" )
+ # --- end of __init__ (...) ---
# --- end of OverlayStats ---
diff --git a/roverlay/stats/collector.py b/roverlay/stats/collector.py
index fc48d2a..d3c318e 100644
--- a/roverlay/stats/collector.py
+++ b/roverlay/stats/collector.py
@@ -4,8 +4,6 @@
# Distributed under the terms of the GNU General Public License;
# either version 2 of the License, or (at your option) any later version.
-from __future__ import division
-
from . import abstract
from . import base
@@ -14,7 +12,7 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
_instance = None
- _MEMBERS = frozenset ({ 'repo', 'overlay', 'overlay_creation', })
+ _MEMBERS = [ 'repo', 'distmap', 'overlay_creation', 'overlay', ]
@classmethod
def get_instance ( cls ):
@@ -41,6 +39,8 @@ class StatsCollector ( abstract.RoverlayStatsBase ):
# (Still better than using the repo package count since that may
# not include old package files)
#
+ # !!! useless. distmap includes "successful" packages only
+ #
return abstract.SuccessRatio (
num_ebuilds = self.overlay.ebuild_count,
num_pkg = self.distmap.pkg_count,
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
@ 2013-07-24 16:52 André Erdmann
0 siblings, 0 replies; 14+ messages in thread
From: André Erdmann @ 2013-07-24 16:52 UTC (permalink / raw
To: gentoo-commits
commit: a2424732d50d85bfb2bc094bee086af7a79ddd49
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Wed Jul 24 15:54:58 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Wed Jul 24 15:54:58 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=a2424732
stats collection: data types
---
roverlay/stats/abstract.py | 209 ++++++++++++++++++++++++++++++++++++++++++++
roverlay/stats/base.py | 82 +++++++++++++++++
roverlay/stats/collector.py | 60 +++++++++++++
3 files changed, 351 insertions(+)
diff --git a/roverlay/stats/abstract.py b/roverlay/stats/abstract.py
new file mode 100644
index 0000000..b6a4ee9
--- /dev/null
+++ b/roverlay/stats/abstract.py
@@ -0,0 +1,209 @@
+# R overlay -- stats collection, data types
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import collections
+import time
+
+class RoverlayStatsBase ( object ):
+
+ @classmethod
+ def get_new ( cls ):
+ return cls()
+ # --- end of get_new (...) ---
+
+ def merge_with ( self, other ):
+ raise NotImplementedError()
+ # --- end of merge_with (...) ---
+
+ def _iter_members ( self, nofail=False ):
+ if not nofail or hasattr ( self, '_MEMBERS' ):
+ for member in self.__class__._MEMBERS:
+ yield getattr ( self, member )
+ # --- end of _iter_members (...) ---
+
+ def reset_members ( self ):
+ for member in self._iter_members():
+ member.reset()
+ # --- end of reset_members (...) ---
+
+ def reset ( self ):
+ if hasattr ( self.__class__, '_MEMBERS' ):
+ self.reset_members()
+ else:
+ raise NotImplementedError()
+ # --- end of reset (...) ---
+
+ def get_description_str ( self ):
+ return (
+ getattr ( self, 'description', None ) or
+ getattr ( self, 'DESCRIPTION', None )
+ )
+ # --- end of get_description_str (...) ---
+
+ def gen_str ( self ):
+ desc = self.get_description_str()
+ if desc:
+ yield desc
+
+ for member in self._iter_members( nofail=True ):
+ yield str ( member )
+ # --- end of gen_str (...) ---
+
+ def __str__ ( self ):
+ ret = '\n'.join ( self.gen_str() )
+ if ret:
+ return ret
+ else:
+ raise NotImplementedError()
+ # --- end of __str__ (...) ---
+
+# --- end of RoverlayStatsBase ---
+
+
+class RoverlayStats ( RoverlayStatsBase ):
+
+ def get_time ( self ):
+ return time.time()
+ # --- end of get_time (...) ---
+
+ def get_time_delta ( self, start, stop=None ):
+ t_stop = self.get_time() if stop is None else stop
+ return ( start - t_stop, t_stop )
+ # --- end of get_time_delta (...) ---
+
+# --- end of RoverlayStats ---
+
+
+class DetailedCounter ( RoverlayStatsBase ):
+ def __init__ ( self, description=None ):
+ super ( DetailedCounter, self ).__init__()
+ self.description = description
+ self.total_count = 0
+ self._detailed_count = collections.defaultdict ( int )
+ self.underflow = False
+ # --- end of __init__ (...) ---
+
+ def __getitem__ ( self, key ):
+ if key in self._detailed_count:
+ return self._detailed_count [key]
+ else:
+ raise KeyError ( key )
+ # --- end of __getitem__ (...) ---
+
+ def __int__ ( self ):
+ return self.total_count
+ # --- end of __int__ (...) ---
+
+ def __float__ ( self ):
+ return float ( self.total_count )
+ # --- end of __float__ (...) ---
+
+ def get ( self, key=None, fallback=0 ):
+ if key is None:
+ return self.total_count
+ elif key in self._detailed_count:
+ return self._detailed_count [key]
+ else:
+ return fallback
+ # --- end of get (...) ---
+
+ def reset ( self ):
+ self.total_count = 0
+ self.underflow = False
+ self._detailed_count.clear()
+ # --- end of reset (...) ---
+
+ def inc_details_v ( self, details ):
+ for k in details:
+ self._detailed_count [k] += 1
+ # --- end of inc_details_v (...) ---
+
+ def inc ( self, *details ):
+ self.total_count += 1
+ self.inc_details_v ( details )
+ # --- end of inc (...) ---
+
+ def inc_details ( self, *details ):
+ self.inc_details_v ( details )
+ # --- end of inc_details (...) ---
+
+ def dec_details_v ( self, details ):
+ # do not check / fail if self._detailed_count [k] > 0
+ # simply keep the negative value
+ for k in details:
+ self._detailed_count [k] -= 1
+ if self._detailed_count [k] < 0:
+ self.underflow = True
+ # --- end of dec_details_v (...) ---
+
+ def dec ( self, *details ):
+ self.total_count -= 1
+ if self.total_count < 0:
+ self.underflow = True
+ self.dec_details_v ( details )
+ # --- end of dec (...) ---
+
+ def dec_details ( self, *details ):
+ self.dec_details_v ( Details )
+ # --- end of dec_details (...) ---
+
+ def merge_with ( self, other ):
+ self.total_count += other.totalcount
+ for key, value in other._detailed_count.items():
+ self._detailed_count [key] += value
+
+ if other.underflow:
+ self.underflow = True
+ # --- end of merge_with (...) ---
+
+ def gen_str ( self ):
+ desc = self.get_description_str()
+ if desc:
+ yield desc
+
+ yield "total: {:d}".format ( self.total_count )
+ for key, value in self._detailed_count.items():
+ yield "* {k}: {v:d}".format ( k=key, v=value )
+
+ if self.underflow:
+ yield "*** underflow detected ***"
+ # --- end of gen_str (...) ---
+
+# --- end of DetailedCounter ---
+
+
+class SuccessRatio ( object ):
+
+ def __init__ ( self, num_ebuilds, num_pkg ):
+ super ( SuccessRatio, self ).__init__()
+ self.ebuild_count = int ( num_ebuilds )
+ self.pkg_count = int ( num_pkg )
+ # --- end of __init__ (...) ---
+
+ def get_ratio ( self ):
+ if self.pkg_count == self.ebuild_count:
+ # 0/0, ..., K/K: "success" := 1.0
+ return 1.0
+ elif self.pkg_count < 1:
+ # K/0: bad ratio, use fixed value
+ return -1.0
+ else:
+ return float ( self.ebuild_count ) / float ( self.pkg_count )
+ # --- end of get_ratio (...) ---
+
+ def __float__ ( self ):
+ return self.get_ratio()
+ # --- end of __float__ (...) ---
+
+ def __int__ ( self ):
+ return int ( self.get_ratio() )
+ # --- end of __int__ (...) ---
+
+ def __str__ ( self ):
+ return "{:.3%}".format ( self.get_ratio() )
+ # --- end of __str__ (...) ---
+
+# --- end of SuccessRatio ---
diff --git a/roverlay/stats/base.py b/roverlay/stats/base.py
new file mode 100644
index 0000000..6e37581
--- /dev/null
+++ b/roverlay/stats/base.py
@@ -0,0 +1,82 @@
+# R overlay -- stats collection, data types
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+from . import abstract
+
+class RepoStats ( abstract.RoverlayStats ):
+
+ _MEMBERS = frozenset ({ 'pkg_count', })
+
+ def __init__ ( self ):
+ super ( RepoStats, self ).__init__()
+ self.pkg_count = abstract.DetailedCounter (
+ description="package count"
+ )
+ # --- end of __init__ (...) ---
+
+ def package_file_found ( self, repo ):
+ self.pkg_count.inc ( repo.name )
+ # --- end of add_package (...) ---
+
+# --- end of RepoStats ---
+
+
+class DistmapStats ( abstract.RoverlayStats ):
+
+ _MEMBERS = frozenset ({ 'pkg_count', })
+
+ def __init__ ( self ):
+ super ( DistmapStats, self ).__init__()
+ self.pkg_count = abstract.DetailedCounter (
+ description="distmap package count"
+ )
+ # --- end of __init__ (...) ---
+
+ def file_added ( self, *origin ):
+ self.pkg_count.inc ( *origin )
+ # --- end of file_added (...) ---
+
+ def file_removed ( self, *origin ):
+ self.pkg_count.dec ( *origin )
+ # --- end of file_removed (...) ---
+
+# --- end of DistmapStats ---
+
+
+class OverlayCreationStats ( abstract.RoverlayStats ):
+
+ #_MEMBERS = frozenset({})
+
+ def __init__ ( self ):
+ super ( OverlayCreationStats, self ).__init__()
+ # --- end of __init__ (...) ---
+
+ def get_relevant_package_count ( self ):
+ print ( "get_relevant_package_count(): method stub" )
+ return 0
+ # --- end of get_relevant_package_count (...) ---
+
+# --- end of OverlayCreationStats ---
+
+
+class OverlayStats ( abstract.RoverlayStats ):
+
+ _MEMBERS = frozenset({ 'ebuild_count', })
+
+ def __init__ ( self ):
+ super ( OverlayStats, self ).__init__()
+ # ebuild_count counts *physical* ebuilds
+ # number of created ebuilds is part of overlay creation stats
+ self.ebuild_count = abstract.DetailedCounter (
+ description="ebuild count"
+ )
+ # --- end of __init__ (...) ---
+
+ def ebuild_added ( self, origin ):
+ self.ebuild_count.inc ( origin )
+ # --- end of ebuild_added (...) ---
+
+# --- end of OverlayStats ---
diff --git a/roverlay/stats/collector.py b/roverlay/stats/collector.py
new file mode 100644
index 0000000..fc48d2a
--- /dev/null
+++ b/roverlay/stats/collector.py
@@ -0,0 +1,60 @@
+# R overlay -- stats collection, stats collector
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+from __future__ import division
+
+from . import abstract
+from . import base
+
+
+class StatsCollector ( abstract.RoverlayStatsBase ):
+
+ _instance = None
+
+ _MEMBERS = frozenset ({ 'repo', 'overlay', 'overlay_creation', })
+
+ @classmethod
+ def get_instance ( cls ):
+ return cls._instance
+ # --- end of instance (...) ---
+
+ def get_success_ratio ( self ):
+ # success ratio for "this" run:
+ # new ebuilds / relevant package count (new packages - unsuitable,
+ # where unsuitable is e.g. "OS_Type not supported")
+ #
+ return abstract.SuccessRatio (
+ num_ebuilds = self.overlay.ebuild_count.get ( "new" ),
+ num_pkg = self.overlay_creation.get_relevant_package_count(),
+ )
+ # --- end of get_success_ratio (...) ---
+
+ def get_overall_success_ratio ( self ):
+ # overall success ratio:
+ # all ebuilds / distmap file count
+ #
+ # *Not* accurate as it includes imported ebuilds and assumes that
+ # each ebuild has one source file in the distmap.
+ # (Still better than using the repo package count since that may
+ # not include old package files)
+ #
+ return abstract.SuccessRatio (
+ num_ebuilds = self.overlay.ebuild_count,
+ num_pkg = self.distmap.pkg_count,
+ )
+ # --- end of get_overall_success_ratio (...) ---
+
+ def __init__ ( self ):
+ self.distmap = base.DistmapStats()
+ self.overlay = base.OverlayStats()
+ self.overlay_creation = base.OverlayCreationStats()
+ self.repo = base.RepoStats()
+ # --- end of __init__ (...) ---
+
+# --- end of StatsCollector ---
+
+static = StatsCollector()
+StatsCollector._instance = static
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2014-02-21 17:37 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-25 14:28 [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/ André Erdmann
-- strict thread matches above, loose matches on Subject: below --
2014-02-21 17:36 André Erdmann
2013-09-05 10:24 André Erdmann
2013-09-05 9:25 André Erdmann
2013-09-05 9:25 André Erdmann
2013-08-16 12:42 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-15 9:18 André Erdmann
2013-08-02 10:34 André Erdmann
2013-07-29 14:56 André Erdmann
2013-07-29 8:55 André Erdmann
2013-07-26 13:02 André Erdmann
2013-07-25 15:20 André Erdmann
2013-07-24 16:52 André Erdmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox