Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | # This file is part of pybootchartgui. |
| 2 | |
| 3 | # pybootchartgui is free software: you can redistribute it and/or modify |
| 4 | # it under the terms of the GNU General Public License as published by |
| 5 | # the Free Software Foundation, either version 3 of the License, or |
| 6 | # (at your option) any later version. |
| 7 | |
| 8 | # pybootchartgui is distributed in the hope that it will be useful, |
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | # GNU General Public License for more details. |
| 12 | |
| 13 | # You should have received a copy of the GNU General Public License |
| 14 | # along with pybootchartgui. If not, see <http://www.gnu.org/licenses/>. |
| 15 | |
| 16 | |
| 17 | class DiskStatSample: |
| 18 | def __init__(self, time): |
| 19 | self.time = time |
| 20 | self.diskdata = [0, 0, 0] |
| 21 | def add_diskdata(self, new_diskdata): |
| 22 | self.diskdata = [ a + b for a, b in zip(self.diskdata, new_diskdata) ] |
| 23 | |
| 24 | class CPUSample: |
| 25 | def __init__(self, time, user, sys, io = 0.0, swap = 0.0): |
| 26 | self.time = time |
| 27 | self.user = user |
| 28 | self.sys = sys |
| 29 | self.io = io |
| 30 | self.swap = swap |
| 31 | |
| 32 | @property |
| 33 | def cpu(self): |
| 34 | return self.user + self.sys |
| 35 | |
| 36 | def __str__(self): |
| 37 | return str(self.time) + "\t" + str(self.user) + "\t" + \ |
| 38 | str(self.sys) + "\t" + str(self.io) + "\t" + str (self.swap) |
| 39 | |
| 40 | class MemSample: |
| 41 | used_values = ('MemTotal', 'MemFree', 'Buffers', 'Cached', 'SwapTotal', 'SwapFree',) |
| 42 | |
| 43 | def __init__(self, time): |
| 44 | self.time = time |
| 45 | self.records = {} |
| 46 | |
| 47 | def add_value(self, name, value): |
| 48 | if name in MemSample.used_values: |
| 49 | self.records[name] = value |
| 50 | |
| 51 | def valid(self): |
| 52 | keys = self.records.keys() |
| 53 | # discard incomplete samples |
| 54 | return [v for v in MemSample.used_values if v not in keys] == [] |
| 55 | |
| 56 | class ProcessSample: |
| 57 | def __init__(self, time, state, cpu_sample): |
| 58 | self.time = time |
| 59 | self.state = state |
| 60 | self.cpu_sample = cpu_sample |
| 61 | |
| 62 | def __str__(self): |
| 63 | return str(self.time) + "\t" + str(self.state) + "\t" + str(self.cpu_sample) |
| 64 | |
| 65 | class ProcessStats: |
| 66 | def __init__(self, writer, process_map, sample_count, sample_period, start_time, end_time): |
| 67 | self.process_map = process_map |
| 68 | self.sample_count = sample_count |
| 69 | self.sample_period = sample_period |
| 70 | self.start_time = start_time |
| 71 | self.end_time = end_time |
| 72 | writer.info ("%d samples, avg. sample length %f" % (self.sample_count, self.sample_period)) |
| 73 | writer.info ("process list size: %d" % len (self.process_map.values())) |
| 74 | |
| 75 | class Process: |
| 76 | def __init__(self, writer, pid, cmd, ppid, start_time): |
| 77 | self.writer = writer |
| 78 | self.pid = pid |
| 79 | self.cmd = cmd |
| 80 | self.exe = cmd |
| 81 | self.args = [] |
| 82 | self.ppid = ppid |
| 83 | self.start_time = start_time |
| 84 | self.duration = 0 |
| 85 | self.samples = [] |
| 86 | self.parent = None |
| 87 | self.child_list = [] |
| 88 | |
| 89 | self.active = None |
| 90 | self.last_user_cpu_time = None |
| 91 | self.last_sys_cpu_time = None |
| 92 | |
| 93 | self.last_cpu_ns = 0 |
| 94 | self.last_blkio_delay_ns = 0 |
| 95 | self.last_swapin_delay_ns = 0 |
| 96 | |
| 97 | # split this process' run - triggered by a name change |
| 98 | def split(self, writer, pid, cmd, ppid, start_time): |
| 99 | split = Process (writer, pid, cmd, ppid, start_time) |
| 100 | |
| 101 | split.last_cpu_ns = self.last_cpu_ns |
| 102 | split.last_blkio_delay_ns = self.last_blkio_delay_ns |
| 103 | split.last_swapin_delay_ns = self.last_swapin_delay_ns |
| 104 | |
| 105 | return split |
| 106 | |
| 107 | def __str__(self): |
| 108 | return " ".join([str(self.pid), self.cmd, str(self.ppid), '[ ' + str(len(self.samples)) + ' samples ]' ]) |
| 109 | |
| 110 | def calc_stats(self, samplePeriod): |
| 111 | if self.samples: |
| 112 | firstSample = self.samples[0] |
| 113 | lastSample = self.samples[-1] |
| 114 | self.start_time = min(firstSample.time, self.start_time) |
| 115 | self.duration = lastSample.time - self.start_time + samplePeriod |
| 116 | |
| 117 | activeCount = sum( [1 for sample in self.samples if sample.cpu_sample and sample.cpu_sample.sys + sample.cpu_sample.user + sample.cpu_sample.io > 0.0] ) |
| 118 | activeCount = activeCount + sum( [1 for sample in self.samples if sample.state == 'D'] ) |
| 119 | self.active = (activeCount>2) |
| 120 | |
| 121 | def calc_load(self, userCpu, sysCpu, interval): |
| 122 | userCpuLoad = float(userCpu - self.last_user_cpu_time) / interval |
| 123 | sysCpuLoad = float(sysCpu - self.last_sys_cpu_time) / interval |
| 124 | cpuLoad = userCpuLoad + sysCpuLoad |
| 125 | # normalize |
| 126 | if cpuLoad > 1.0: |
| 127 | userCpuLoad = userCpuLoad / cpuLoad |
| 128 | sysCpuLoad = sysCpuLoad / cpuLoad |
| 129 | return (userCpuLoad, sysCpuLoad) |
| 130 | |
| 131 | def set_parent(self, processMap): |
| 132 | if self.ppid != None: |
| 133 | self.parent = processMap.get (self.ppid) |
| 134 | if self.parent == None and self.pid // 1000 > 1 and \ |
| 135 | not (self.ppid == 2000 or self.pid == 2000): # kernel threads: ppid=2 |
| 136 | self.writer.warn("Missing CONFIG_PROC_EVENTS: no parent for pid '%i' ('%s') with ppid '%i'" \ |
| 137 | % (self.pid,self.cmd,self.ppid)) |
| 138 | |
| 139 | def get_end_time(self): |
| 140 | return self.start_time + self.duration |
| 141 | |
| 142 | class DiskSample: |
| 143 | def __init__(self, time, read, write, util): |
| 144 | self.time = time |
| 145 | self.read = read |
| 146 | self.write = write |
| 147 | self.util = util |
| 148 | self.tput = read + write |
| 149 | |
| 150 | def __str__(self): |
| 151 | return "\t".join([str(self.time), str(self.read), str(self.write), str(self.util)]) |