From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
Date: Mon, 29 Jul 2013 08:55:52 +0000 (UTC) [thread overview]
Message-ID: <1375088075.55537b3dd0f8f1624f882af50f5dc9ea0de65678.dywi@gentoo> (raw)
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
next reply other threads:[~2013-07-29 8:55 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-29 8:55 André Erdmann [this message]
-- strict thread matches above, loose matches on Subject: below --
2014-02-21 17:36 [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/ 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-26 13:02 André Erdmann
2013-07-25 15:20 André Erdmann
2013-07-25 14:28 André Erdmann
2013-07-24 16:52 André Erdmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1375088075.55537b3dd0f8f1624f882af50f5dc9ea0de65678.dywi@gentoo \
--to=dywi@mailerd.de \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox