Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'walles/load-bar' into python
This adds a load bar to ptop. Fixes #13
- Loading branch information
Showing
10 changed files
with
519 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import os | ||
import errno | ||
import subprocess | ||
|
||
|
||
def get_core_count(): | ||
""" | ||
Count the number of cores in the system. | ||
Returns a tuple (physical, logical) with counts of physical and logical | ||
cores. | ||
""" | ||
return_me = get_core_count_from_proc_cpuinfo() | ||
if return_me is not None: | ||
return return_me | ||
|
||
return_me = get_core_count_from_sysctl() | ||
if return_me is not None: | ||
return return_me | ||
|
||
return None | ||
|
||
|
||
def get_core_count_from_proc_cpuinfo(proc_cpuinfo="/proc/cpuinfo"): | ||
""" | ||
Count the number of cores in /proc/cpuinfo. | ||
Returns a tuple (physical, logical) with counts of physical and logical | ||
cores. | ||
""" | ||
# Note the ending spaces, they must be there for number extraction to work! | ||
PROCESSOR_NO_PREFIX = 'processor\t: ' | ||
CORE_ID_PREFIX = 'core id\t\t: ' | ||
|
||
core_ids = set() | ||
max_processor_no = 0 | ||
try: | ||
with open(proc_cpuinfo) as f: | ||
for line in f: | ||
if line.startswith(PROCESSOR_NO_PREFIX): | ||
processor_no = int(line[len(PROCESSOR_NO_PREFIX):]) | ||
max_processor_no = max(processor_no, max_processor_no) | ||
elif line.startswith(CORE_ID_PREFIX): | ||
core_id = int(line[len(CORE_ID_PREFIX)]) | ||
core_ids.add(core_id) | ||
except (IOError, OSError) as e: | ||
if e.errno == errno.ENOENT: | ||
# /proc/cpuinfo not found, we're probably not on Linux | ||
return None | ||
|
||
raise | ||
|
||
physical = len(core_ids) | ||
logical = max_processor_no + 1 | ||
if physical == 0: | ||
# I get this on my cell phone | ||
physical = logical | ||
return (physical, logical) | ||
|
||
|
||
def get_core_count_from_sysctl(): | ||
env = os.environ.copy() | ||
if "LANG" in env: | ||
del env["LANG"] | ||
|
||
try: | ||
sysctl = subprocess.Popen(["sysctl", 'hw'], | ||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, | ||
env=env) | ||
except (IOError, OSError) as e: | ||
if e.errno == errno.ENOENT: | ||
# sysctl not found, we're probably not on OSX | ||
return None | ||
|
||
raise | ||
|
||
sysctl_stdout = sysctl.communicate()[0].decode('utf-8') | ||
sysctl_lines = sysctl_stdout.split('\n') | ||
|
||
# Note the ending spaces, they must be there for number extraction to work! | ||
PHYSICAL_PREFIX = 'hw.physicalcpu: ' | ||
LOGICAL_PREFIX = 'hw.logicalcpu: ' | ||
|
||
physical = None | ||
logical = None | ||
for line in sysctl_lines: | ||
if line.startswith(PHYSICAL_PREFIX): | ||
physical = int(line[len(PHYSICAL_PREFIX):]) | ||
elif line.startswith(LOGICAL_PREFIX): | ||
logical = int(line[len(LOGICAL_PREFIX)]) | ||
|
||
if physical is None or logical is None: | ||
# On Linux, sysctl exists but it doesn't contain the values we want | ||
return None | ||
|
||
return (physical, logical) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
class PxLoadBar(object): | ||
""" | ||
Visualizes system load in a horizontal bar. | ||
Inputs are: | ||
* System load | ||
* Number of physical cores | ||
* Number of logical cores | ||
* How many columns wide the horizontal bar should be | ||
The output is a horizontal bar string. | ||
Load below the number of physical cores is visualized in green. | ||
Load between the number of physical cores and logical cores is visualized in | ||
yellow. | ||
Load above of the number of logical cores is visualized in red. | ||
As long as load is below the number of physical cores, it will use only the | ||
first half of the output string. | ||
Load up to twice the number of physical cores will go up to the end of the | ||
string. | ||
""" | ||
|
||
def __init__(self, physical=None, logical=None): | ||
if physical is None or physical < 1: | ||
raise ValueError("Physical must be a positive integer, was: %r" % (physical,)) | ||
|
||
if logical is None or logical < physical: | ||
raise ValueError("Logical must be >= physical, was: %r (vs %r)" % (logical, physical)) | ||
|
||
self._physical = physical | ||
self._logical = logical | ||
|
||
CSI = b"\x1b[" | ||
self.normal = CSI + b"m" | ||
self.inverse = CSI + b"7m" | ||
self.red = CSI + b"41m" | ||
self.yellow = CSI + b"43m" | ||
self.green = CSI + b"42m" | ||
|
||
def _get_colored_bytes(self, load=None, columns=None): | ||
"Yields pairs, with each pair containing a color and a byte" | ||
|
||
max_value = 2.0 * self._physical | ||
if load > max_value: | ||
max_value = 1.0 * load | ||
|
||
UNUSED = 1000 * max_value | ||
if load < self._physical: | ||
yellow_start = UNUSED | ||
red_start = UNUSED | ||
inverse_start = load | ||
normal_start = self._physical | ||
else: | ||
yellow_start = self._physical | ||
red_start = self._logical | ||
inverse_start = UNUSED | ||
normal_start = load | ||
|
||
# Scale the values to the number of columns | ||
yellow_start = yellow_start * columns / max_value - 0.5 | ||
red_start = red_start * columns / max_value - 0.5 | ||
inverse_start = inverse_start * columns / max_value - 0.5 | ||
normal_start = normal_start * columns / max_value - 0.5 | ||
|
||
for i in range(columns): | ||
# We always start out green | ||
color = self.green | ||
|
||
if i >= yellow_start: | ||
color = self.yellow | ||
if i >= red_start: | ||
color = self.red | ||
if i >= inverse_start: | ||
color = self.inverse | ||
if i >= normal_start: | ||
color = self.normal | ||
|
||
yield (color, b' ') | ||
|
||
def get_bar(self, load=None, columns=None): | ||
if load is None: | ||
raise ValueError("Missing required parameter load=") | ||
|
||
if columns is None: | ||
raise ValueError("Missing required parameter columns=") | ||
|
||
return_me = b'' | ||
color = self.normal | ||
for color_and_byte in self._get_colored_bytes(load=load, columns=columns): | ||
if color_and_byte[0] != color: | ||
return_me += color_and_byte[0] | ||
color = color_and_byte[0] | ||
return_me += color_and_byte[1] | ||
|
||
if color != self.normal: | ||
return_me += self.normal | ||
|
||
return return_me |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
processor : 0 | ||
vendor_id : GenuineIntel | ||
cpu family : 6 | ||
model : 62 | ||
model name : Intel(R) Xeon(R) CPU E5-2670 v2 @ 2.50GHz | ||
stepping : 4 | ||
microcode : 0x428 | ||
cpu MHz : 2500.108 | ||
cache size : 25600 KB | ||
physical id : 0 | ||
siblings : 1 | ||
core id : 1 | ||
cpu cores : 1 | ||
apicid : 3 | ||
initial apicid : 3 | ||
fpu : yes | ||
fpu_exception : yes | ||
cpuid level : 13 | ||
wp : yes | ||
flags : fpu de tsc msr pae cx8 apic sep cmov pat clflush mmx fxsr sse sse2 ss ht syscall nx lm constant_tsc rep_good nopl pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 popcnt tsc_deadline_timer aes rdrand hypervisor lahf_lm ida arat epb pln pts dtherm fsgsbase erms | ||
bogomips : 5000.21 | ||
clflush size : 64 | ||
cache_alignment : 64 | ||
address sizes : 46 bits physical, 48 bits virtual | ||
power management: |
Oops, something went wrong.