From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/
Date: Wed, 24 Jul 2013 16:52:34 +0000 (UTC) [thread overview]
Message-ID: <1374681298.a2424732d50d85bfb2bc094bee086af7a79ddd49.dywi@gentoo> (raw)
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
next reply other threads:[~2013-07-24 16:52 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-24 16:52 André Erdmann [this message]
-- strict thread matches above, loose matches on Subject: below --
2013-07-25 14:28 [gentoo-commits] proj/R_overlay:master commit in: roverlay/stats/ André Erdmann
2013-07-25 15:20 André Erdmann
2013-07-26 13:02 André Erdmann
2013-07-29 8:55 André Erdmann
2013-07-29 14:56 André Erdmann
2013-08-02 10:34 André Erdmann
2013-08-15 9:18 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-16 12:42 André Erdmann
2013-09-05 9:25 André Erdmann
2013-09-05 9:25 André Erdmann
2013-09-05 10:24 André Erdmann
2014-02-21 17:36 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=1374681298.a2424732d50d85bfb2bc094bee086af7a79ddd49.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