From 79960e5cba13c1b26c7e513456ae54b0039a7fa5 Mon Sep 17 00:00:00 2001 From: Arvedui Date: Sat, 5 Jul 2014 21:57:10 +0200 Subject: [PATCH 1/5] added multi core support for cpu usage --- i3pystatus/cpu_usage.py | 106 +++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/i3pystatus/cpu_usage.py b/i3pystatus/cpu_usage.py index 96246cd..c49909d 100644 --- a/i3pystatus/cpu_usage.py +++ b/i3pystatus/cpu_usage.py @@ -1,7 +1,15 @@ # -*- coding:utf-8 -*- +from collections import defaultdict +from string import Formatter + from i3pystatus import IntervalModule +try: + from natsort import natsorted as sorted +except ImportError: + pass + class CpuUsage(IntervalModule): """ @@ -11,48 +19,102 @@ class CpuUsage(IntervalModule): Available formatters: - * {usage} + * {usage} usage average of all cores + * {usage_cpu*} usage of one specific core. replace "*" by core number statring at 0 + * {usage_all} usage of all cores separate. usess natsort when available(relevant for more than 10 cores) """ format = "{usage:02}%" + format_all = "{core}:{usage:02}%" + exclude_average = False settings = ( - ("format", "format string"), + ("format", "format string. Default: {usage:02}%"), + ("format_all", ("format string used for {usage_all} per core. " + "Available formaters are {core} and {usage}. " + "Default: {core}:{usage:02}")), + ("exclude_average", ("If True usage average of all cores will " + "not be in format_all. Default: False")) ) def init(self): - self.prev_idle = 0 - self.prev_busy = 0 + self.prev_total = defaultdict(int) + self.prev_busy = defaultdict(int) self.interval = 1 + self.formatter = Formatter() + + def get_cpu_timings(self): + """ + reads and parses /proc/stat + returns dictionary with all available cores invluding global average + """ + timings = {} + with open('/proc/stat', 'r') as file_obj: + for line in file_obj: + if 'cpu' in line: + line = line.strip().split() + timings[line[0]] = [int(x) for x in line[1:]] + + return timings + + def calculate_usage(self, cpu, total, busy): + """ + calculates usage + """ + diff_total = total - self.prev_total[cpu] + diff_busy = busy - self.prev_busy[cpu] + + self.prev_total[cpu] = total + self.prev_busy[cpu] = busy + + return int(diff_busy / diff_total * 100) + + def gen_format_all(self, usage): + """ + generates string for format all + """ + format_string = " " + core_strings = [] + for core, usage in usage.items(): + if core == 'usage_cpu' and self.exclude_average: + continue + elif core == 'usage': + continue + + core = core.replace('usage_', '') + string = self.formatter.format(format_string=self.format_all, + core=core, + usage=usage) + core_strings.append(string) + + core_strings = sorted(core_strings) + + return format_string.join(core_strings) def get_usage(self): """ parses /proc/stat and calcualtes total and busy time (more specific USER_HZ see man 5 proc for further informations ) """ - with open('/proc/stat', 'r') as file_obj: - stats = file_obj.readline().strip().split() + usage = {} - cpu_timings = [int(x) for x in stats[1:]] - cpu_total = sum(cpu_timings) - del cpu_timings[3:5] - cpu_busy = sum(cpu_timings) + for cpu, timings in self.get_cpu_timings().items(): + cpu_total = sum(timings) + del timings[3:5] + cpu_busy = sum(timings) + cpu_usage = self.calculate_usage(cpu, cpu_total, cpu_busy) - return cpu_total, cpu_busy + usage['usage_' + cpu] = cpu_usage + + return usage def run(self): - cpu_total, cpu_busy = self.get_usage() + usage = self.get_usage() + usage['format_all'] = self.gen_format_all(usage) - diff_cpu_total = cpu_total - self.prev_idle - diff_cpu_busy = cpu_busy - self.prev_busy - - self.prev_idle = cpu_total - self.prev_busy = cpu_busy - - cpu_busy_percentage = int(diff_cpu_busy / diff_cpu_total * 100) + # for backward compatibility + usage['usage'] = usage['usage_cpu'] self.output = { - "full_text": self.format.format( - usage=cpu_busy_percentage - ) + "full_text": self.format.format_map(usage) } From 1520b49c9222a3d392e277730d17f55b6db3bb9d Mon Sep 17 00:00:00 2001 From: Arvedui Date: Sat, 5 Jul 2014 22:27:54 +0200 Subject: [PATCH 2/5] fixed typo and updated README --- README.rst | 29 +++++++++++++++++++++++------ i3pystatus/cpu_usage.py | 9 ++++----- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index b0e09bb..84709dd 100644 --- a/README.rst +++ b/README.rst @@ -429,7 +429,7 @@ Settings: :alert_format_title: The title of the notification, all formatters can be used (default: ``Low battery``) :alert_format_body: The body text of the notification, all formatters can be used (default: ``Battery {battery_ident} has only {percentage:.2f}% ({remaining:%E%hh:%Mm}) remaining!``) :path: Override the default-generated path (default: ``None``) -:status: A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: ``{'DIS': 'DIS', 'FULL': 'FULL', 'CHR': 'CHR'}``) +:status: A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: ``{'FULL': 'FULL', 'DIS': 'DIS', 'CHR': 'CHR'}``) :color: The text color (default: ``#ffffff``) :full_color: The full color (default: ``#00ff00``) :charging_color: The charging color (default: ``#00ff00``) @@ -477,7 +477,7 @@ Settings: :leftclick: URL to visit or command to run on left click (default: ``electrum``) :rightclick: URL to visit or command to run on right click (default: ``https://bitcoinaverage.com/``) :interval: Update interval. (default: ``600``) -:status: (default: ``{'price_down': '▼', 'price_up': '▲'}``) +:status: (default: ``{'price_up': '▲', 'price_down': '▼'}``) @@ -506,13 +506,17 @@ Linux only Available formatters: -* {usage} +* {usage} usage average of all cores +* {usage_cpu*} usage of one specific core. replace "*" by core number starting at 0 +* {usage_all} usage of all cores separate. usess natsort when available(relevant for more than 10 cores) Settings: -:format: format string (default: ``{usage:02}%``) +:format: format string. (default: ``{usage:02}%``) +:format_all: format string used for {usage_all} per core. Available formaters are {core} and {usage}. (default: ``{core}:{usage:02}%``) +:exclude_average: If True usage average of all cores will not be in format_all. (default: ``False``) :interval: (default: ``5``) @@ -810,7 +814,7 @@ Settings: :host: (default: ``localhost``) :port: MPD port (default: ``6600``) :format: formatp string (default: ``{title} {status}``) -:status: Dictionary mapping pause, play and stop to output (default: ``{'pause': '▷', 'stop': '◾', 'play': '▶'}``) +:status: Dictionary mapping pause, play and stop to output (default: ``{'play': '▶', 'stop': '◾', 'pause': '▷'}``) :color: The color of the text (default: ``#FFFFFF``) :interval: (default: ``1``) @@ -852,6 +856,19 @@ Settings: +ngb ++++ + + + +Settings: + +:username: (required) +:password: (required) +:interval: (default: ``5``) + + + now_playing +++++++++++ @@ -877,7 +894,7 @@ Requires python-dbus available from every distros' package manager. Settings: :player: Player name (default: ``None``) -:status: Dictionary mapping pause, play and stop to output text (default: ``{'pause': '▷', 'stop': '◾', 'play': '▶'}``) +:status: Dictionary mapping pause, play and stop to output text (default: ``{'play': '▶', 'stop': '◾', 'pause': '▷'}``) :color: Text color (default: ``#FFFFFF``) :format: formatp string (default: ``{title} {status}``) :interval: (default: ``1``) diff --git a/i3pystatus/cpu_usage.py b/i3pystatus/cpu_usage.py index c49909d..fb15264 100644 --- a/i3pystatus/cpu_usage.py +++ b/i3pystatus/cpu_usage.py @@ -20,7 +20,7 @@ class CpuUsage(IntervalModule): Available formatters: * {usage} usage average of all cores - * {usage_cpu*} usage of one specific core. replace "*" by core number statring at 0 + * {usage_cpu*} usage of one specific core. replace "*" by core number starting at 0 * {usage_all} usage of all cores separate. usess natsort when available(relevant for more than 10 cores) """ @@ -29,12 +29,11 @@ class CpuUsage(IntervalModule): format_all = "{core}:{usage:02}%" exclude_average = False settings = ( - ("format", "format string. Default: {usage:02}%"), + ("format", "format string."), ("format_all", ("format string used for {usage_all} per core. " - "Available formaters are {core} and {usage}. " - "Default: {core}:{usage:02}")), + "Available formaters are {core} and {usage}. ")), ("exclude_average", ("If True usage average of all cores will " - "not be in format_all. Default: False")) + "not be in format_all.")) ) def init(self): From 0b060820841c5daa2a1226289997549201c0a5a4 Mon Sep 17 00:00:00 2001 From: Arvedui Date: Sun, 6 Jul 2014 21:36:57 +0200 Subject: [PATCH 3/5] removed unnesecary code duplication in cpu_usage_bar, added multicore support for cpu_bar and fixed typo in cpu_usage --- i3pystatus/cpu_usage.py | 2 +- i3pystatus/cpu_usage_bar.py | 47 +++++++++++-------------------------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/i3pystatus/cpu_usage.py b/i3pystatus/cpu_usage.py index fb15264..12becb1 100644 --- a/i3pystatus/cpu_usage.py +++ b/i3pystatus/cpu_usage.py @@ -45,7 +45,7 @@ class CpuUsage(IntervalModule): def get_cpu_timings(self): """ reads and parses /proc/stat - returns dictionary with all available cores invluding global average + returns dictionary with all available cores including global average """ timings = {} with open('/proc/stat', 'r') as file_obj: diff --git a/i3pystatus/cpu_usage_bar.py b/i3pystatus/cpu_usage_bar.py index c40fe22..0f35bd9 100644 --- a/i3pystatus/cpu_usage_bar.py +++ b/i3pystatus/cpu_usage_bar.py @@ -1,9 +1,9 @@ # -*- coding:utf-8 -*- -from i3pystatus import IntervalModule +from i3pystatus.cpu_usage import CpuUsage from i3pystatus.core.util import make_bar -class CpuUsageBar(IntervalModule): +class CpuUsageBar(CpuUsage): """ Shows CPU usage as a bar (made with unicode box characters). The first output will be inacurate @@ -11,7 +11,8 @@ class CpuUsageBar(IntervalModule): Available formatters: - * {usage_bar} + * {usage_bar} usage average of all cores + * {usage_bar_cpu*} usage of one specific core. replace "*" by core number starting at 0 """ @@ -20,41 +21,21 @@ class CpuUsageBar(IntervalModule): ("format", "format string"), ) - def init(self): - self.prev_idle = 0 - self.prev_busy = 0 - self.interval = 1 - - def get_usage(self): - """ - parses /proc/stat and calcualtes total and busy time - (more specific USER_HZ see man 5 proc for further informations ) - """ - with open('/proc/stat', 'r') as file_obj: - stats = file_obj.readline().strip().split() - - cpu_timings = [int(x) for x in stats[1:]] - cpu_total = sum(cpu_timings) - del cpu_timings[3:5] - cpu_busy = sum(cpu_timings) - - return cpu_total, cpu_busy - def run(self): - cpu_total, cpu_busy = self.get_usage() + cpu_usage = self.get_usage() - diff_cpu_total = cpu_total - self.prev_idle - diff_cpu_busy = cpu_busy - self.prev_busy + cpu_usage_bar = {} - self.prev_idle = cpu_total - self.prev_busy = cpu_busy + for core, usage in cpu_usage.items(): + core = core.replace('usage', 'usage_bar') + cpu_usage_bar[core] = make_bar(usage) - cpu_busy_percentage = diff_cpu_busy / diff_cpu_total * 100 - cpu_busy_bar = make_bar(cpu_busy_percentage) + cpu_usage.update(cpu_usage_bar) + + # for backward compatibility + cpu_usage['usage_bar'] = cpu_usage['usage_bar_cpu'] self.output = { - "full_text": self.format.format( - usage_bar=cpu_busy_bar - ) + "full_text": self.format.format_map(cpu_usage) } From cf110398e4e32e083a6992ff421c8a3c92436ada Mon Sep 17 00:00:00 2001 From: Arvedui Date: Sun, 6 Jul 2014 21:38:35 +0200 Subject: [PATCH 4/5] updated README --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 84709dd..32f3e98 100644 --- a/README.rst +++ b/README.rst @@ -429,7 +429,7 @@ Settings: :alert_format_title: The title of the notification, all formatters can be used (default: ``Low battery``) :alert_format_body: The body text of the notification, all formatters can be used (default: ``Battery {battery_ident} has only {percentage:.2f}% ({remaining:%E%hh:%Mm}) remaining!``) :path: Override the default-generated path (default: ``None``) -:status: A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: ``{'FULL': 'FULL', 'DIS': 'DIS', 'CHR': 'CHR'}``) +:status: A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: ``{'DIS': 'DIS', 'CHR': 'CHR', 'FULL': 'FULL'}``) :color: The text color (default: ``#ffffff``) :full_color: The full color (default: ``#00ff00``) :charging_color: The charging color (default: ``#00ff00``) @@ -531,7 +531,8 @@ Linux only Available formatters: -* {usage_bar} +* {usage_bar} usage average of all cores +* {usage_bar_cpu*} usage of one specific core. replace "*" by core number starting at 0 From b2d25f6367385f707d6c6bd71f807cd9b84c2a4e Mon Sep 17 00:00:00 2001 From: Arvedui Date: Sat, 9 Aug 2014 16:07:46 +0200 Subject: [PATCH 5/5] updated docs --- README.rst | 17 ++++++++++------- i3pystatus/cpu_usage.py | 3 ++- i3pystatus/cpu_usage_bar.py | 6 ++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 32f3e98..ffa1340 100644 --- a/README.rst +++ b/README.rst @@ -429,7 +429,7 @@ Settings: :alert_format_title: The title of the notification, all formatters can be used (default: ``Low battery``) :alert_format_body: The body text of the notification, all formatters can be used (default: ``Battery {battery_ident} has only {percentage:.2f}% ({remaining:%E%hh:%Mm}) remaining!``) :path: Override the default-generated path (default: ``None``) -:status: A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: ``{'DIS': 'DIS', 'CHR': 'CHR', 'FULL': 'FULL'}``) +:status: A dictionary mapping ('DIS', 'CHR', 'FULL') to alternative names (default: ``{'CHR': 'CHR', 'FULL': 'FULL', 'DIS': 'DIS'}``) :color: The text color (default: ``#ffffff``) :full_color: The full color (default: ``#00ff00``) :charging_color: The charging color (default: ``#00ff00``) @@ -477,7 +477,7 @@ Settings: :leftclick: URL to visit or command to run on left click (default: ``electrum``) :rightclick: URL to visit or command to run on right click (default: ``https://bitcoinaverage.com/``) :interval: Update interval. (default: ``600``) -:status: (default: ``{'price_up': '▲', 'price_down': '▼'}``) +:status: (default: ``{'price_down': '▼', 'price_up': '▲'}``) @@ -501,7 +501,8 @@ cpu_usage Shows CPU usage. -The first output will be inacurate +The first output will be inacurate. + Linux only Available formatters: @@ -526,13 +527,15 @@ cpu_usage_bar Shows CPU usage as a bar (made with unicode box characters). -The first output will be inacurate +The first output will be inacurate. + Linux only Available formatters: * {usage_bar} usage average of all cores -* {usage_bar_cpu*} usage of one specific core. replace "*" by core number starting at 0 +* {usage_bar_cpu*} usage of one specific core. replace "*" +by core number starting at 0 @@ -815,7 +818,7 @@ Settings: :host: (default: ``localhost``) :port: MPD port (default: ``6600``) :format: formatp string (default: ``{title} {status}``) -:status: Dictionary mapping pause, play and stop to output (default: ``{'play': '▶', 'stop': '◾', 'pause': '▷'}``) +:status: Dictionary mapping pause, play and stop to output (default: ``{'play': '▶', 'pause': '▷', 'stop': '◾'}``) :color: The color of the text (default: ``#FFFFFF``) :interval: (default: ``1``) @@ -895,7 +898,7 @@ Requires python-dbus available from every distros' package manager. Settings: :player: Player name (default: ``None``) -:status: Dictionary mapping pause, play and stop to output text (default: ``{'play': '▶', 'stop': '◾', 'pause': '▷'}``) +:status: Dictionary mapping pause, play and stop to output text (default: ``{'play': '▶', 'pause': '▷', 'stop': '◾'}``) :color: Text color (default: ``#FFFFFF``) :format: formatp string (default: ``{title} {status}``) :interval: (default: ``1``) diff --git a/i3pystatus/cpu_usage.py b/i3pystatus/cpu_usage.py index 12becb1..a1f8e82 100644 --- a/i3pystatus/cpu_usage.py +++ b/i3pystatus/cpu_usage.py @@ -14,7 +14,8 @@ except ImportError: class CpuUsage(IntervalModule): """ Shows CPU usage. - The first output will be inacurate + The first output will be inacurate. + Linux only Available formatters: diff --git a/i3pystatus/cpu_usage_bar.py b/i3pystatus/cpu_usage_bar.py index 0f35bd9..2c3b037 100644 --- a/i3pystatus/cpu_usage_bar.py +++ b/i3pystatus/cpu_usage_bar.py @@ -6,13 +6,15 @@ from i3pystatus.core.util import make_bar class CpuUsageBar(CpuUsage): """ Shows CPU usage as a bar (made with unicode box characters). - The first output will be inacurate + The first output will be inacurate. + Linux only Available formatters: * {usage_bar} usage average of all cores - * {usage_bar_cpu*} usage of one specific core. replace "*" by core number starting at 0 + * {usage_bar_cpu*} usage of one specific core. replace "*" + by core number starting at 0 """