Stefan Schuermans commited on 2020-08-16 11:04:25
Showing 6 changed files, with 298 additions and 35 deletions.
... | ... |
@@ -46,6 +46,18 @@ int uptev_proc_end(void **data, size_t *size) { |
46 | 46 |
proc_end.sys_time = &sys_time; |
47 | 47 |
proc_end.has_max_rss_kb = 1; |
48 | 48 |
proc_end.max_rss_kb = usage.ru_maxrss; |
49 |
+ proc_end.has_min_flt = 1; |
|
50 |
+ proc_end.min_flt = usage.ru_minflt; |
|
51 |
+ proc_end.has_maj_flt = 1; |
|
52 |
+ proc_end.maj_flt = usage.ru_majflt; |
|
53 |
+ proc_end.has_in_block = 1; |
|
54 |
+ proc_end.in_block = usage.ru_inblock; |
|
55 |
+ proc_end.has_ou_block = 1; |
|
56 |
+ proc_end.ou_block = usage.ru_oublock; |
|
57 |
+ proc_end.has_n_v_csw = 1; |
|
58 |
+ proc_end.n_v_csw = usage.ru_nvcsw; |
|
59 |
+ proc_end.has_n_iv_csw = 1; |
|
60 |
+ proc_end.n_iv_csw = usage.ru_nivcsw; |
|
49 | 61 |
} |
50 | 62 |
|
51 | 63 |
struct _Uproctrace__Event event = UPROCTRACE__EVENT__INIT; |
... | ... |
@@ -34,6 +34,18 @@ |
34 | 34 |
<column type="gint"/> |
35 | 35 |
<!-- column-name max_rss_kb_text --> |
36 | 36 |
<column type="gchararray"/> |
37 |
+ <!-- column-name page_faults --> |
|
38 |
+ <column type="gint"/> |
|
39 |
+ <!-- column-name page_faults_text --> |
|
40 |
+ <column type="gchararray"/> |
|
41 |
+ <!-- column-name file_sys_ops --> |
|
42 |
+ <column type="gint"/> |
|
43 |
+ <!-- column-name file_sys_ops_text --> |
|
44 |
+ <column type="gchararray"/> |
|
45 |
+ <!-- column-name ctx_sw --> |
|
46 |
+ <column type="gint"/> |
|
47 |
+ <!-- column-name ctx_sw_text --> |
|
48 |
+ <column type="gchararray"/> |
|
37 | 49 |
</columns> |
38 | 50 |
</object> |
39 | 51 |
<object class="GtkWindow" id="Application"> |
... | ... |
@@ -157,6 +169,57 @@ |
157 | 169 |
</child> |
158 | 170 |
</object> |
159 | 171 |
</child> |
172 |
+ <child> |
|
173 |
+ <object class="GtkTreeViewColumn" id="ProcessesPageFaultsCol"> |
|
174 |
+ <property name="resizable">True</property> |
|
175 |
+ <property name="sizing">fixed</property> |
|
176 |
+ <property name="title" translatable="yes">Page Faults</property> |
|
177 |
+ <property name="clickable">True</property> |
|
178 |
+ <property name="reorderable">True</property> |
|
179 |
+ <property name="sort_indicator">True</property> |
|
180 |
+ <property name="sort_column_id">10</property> |
|
181 |
+ <child> |
|
182 |
+ <object class="GtkCellRendererText" id="ProcessesPageFaultsText"/> |
|
183 |
+ <attributes> |
|
184 |
+ <attribute name="text">11</attribute> |
|
185 |
+ </attributes> |
|
186 |
+ </child> |
|
187 |
+ </object> |
|
188 |
+ </child> |
|
189 |
+ <child> |
|
190 |
+ <object class="GtkTreeViewColumn" id="ProcessesFileSysOpsCol"> |
|
191 |
+ <property name="resizable">True</property> |
|
192 |
+ <property name="sizing">fixed</property> |
|
193 |
+ <property name="title" translatable="yes">File System Operations</property> |
|
194 |
+ <property name="clickable">True</property> |
|
195 |
+ <property name="reorderable">True</property> |
|
196 |
+ <property name="sort_indicator">True</property> |
|
197 |
+ <property name="sort_column_id">12</property> |
|
198 |
+ <child> |
|
199 |
+ <object class="GtkCellRendererText" id="ProcessesFileSysOpsText"/> |
|
200 |
+ <attributes> |
|
201 |
+ <attribute name="text">13</attribute> |
|
202 |
+ </attributes> |
|
203 |
+ </child> |
|
204 |
+ </object> |
|
205 |
+ </child> |
|
206 |
+ <child> |
|
207 |
+ <object class="GtkTreeViewColumn" id="ProcessesCtxSwCol"> |
|
208 |
+ <property name="resizable">True</property> |
|
209 |
+ <property name="sizing">fixed</property> |
|
210 |
+ <property name="title" translatable="yes">Context Switches</property> |
|
211 |
+ <property name="clickable">True</property> |
|
212 |
+ <property name="reorderable">True</property> |
|
213 |
+ <property name="sort_indicator">True</property> |
|
214 |
+ <property name="sort_column_id">14</property> |
|
215 |
+ <child> |
|
216 |
+ <object class="GtkCellRendererText" id="ProcessesCtxSwText"/> |
|
217 |
+ <attributes> |
|
218 |
+ <attribute name="text">15</attribute> |
|
219 |
+ </attributes> |
|
220 |
+ </child> |
|
221 |
+ </object> |
|
222 |
+ </child> |
|
160 | 223 |
</object> |
161 | 224 |
</child> |
162 | 225 |
</object> |
... | ... |
@@ -5,6 +5,7 @@ |
5 | 5 |
Graphical user interface of UProcTrace. |
6 | 6 |
""" |
7 | 7 |
|
8 |
+import functools |
|
8 | 9 |
import shlex |
9 | 10 |
import time |
10 | 11 |
|
... | ... |
@@ -19,6 +20,15 @@ gi.require_version('Gtk', '3.0') |
19 | 20 |
from gi.repository import Gdk, Gtk |
20 | 21 |
|
21 | 22 |
|
23 |
+def add_none(val_a: int, val_b: int) -> int: |
|
24 |
+ """ |
|
25 |
+ Integer addition with support for None. |
|
26 |
+ """ |
|
27 |
+ if val_a is None or val_b is None: |
|
28 |
+ return None |
|
29 |
+ return val_a + val_b |
|
30 |
+ |
|
31 |
+ |
|
22 | 32 |
def cmdline2str(cmdline: list) -> str: |
23 | 33 |
""" |
24 | 34 |
Convert command line to string. |
... | ... |
@@ -67,6 +77,15 @@ def duration2str(duration: float) -> str: |
67 | 77 |
return txt |
68 | 78 |
|
69 | 79 |
|
80 |
+def int2str(val: int) -> str: |
|
81 |
+ """ |
|
82 |
+ Convert integer to string, support None. |
|
83 |
+ """ |
|
84 |
+ if val is None: |
|
85 |
+ return '???' |
|
86 |
+ return f'{val:d}' |
|
87 |
+ |
|
88 |
+ |
|
70 | 89 |
def kb2str(size_kb: int) -> str: |
71 | 90 |
""" |
72 | 91 |
Convert size in KiB to string. |
... | ... |
@@ -119,6 +138,12 @@ class UptGui: |
119 | 138 |
PROC_CPU_TIME_TEXT = 7 |
120 | 139 |
PROC_MAX_RSS_KB = 8 |
121 | 140 |
PROC_MAX_RSS_KB_TEXT = 9 |
141 |
+ PROC_PAGE_FAULTS = 10 |
|
142 |
+ PROC_PAGE_FAULTS_TEXT = 11 |
|
143 |
+ PROC_FILE_SYS_OPS = 12 |
|
144 |
+ PROC_FILE_SYS_OPS_TEXT = 13 |
|
145 |
+ PROC_CTX_SW = 14 |
|
146 |
+ PROC_CTX_SW_TEXT = 15 |
|
122 | 147 |
|
123 | 148 |
def __init__(self, proto_filename): |
124 | 149 |
""" |
... | ... |
@@ -140,6 +165,54 @@ class UptGui: |
140 | 165 |
# open trace file |
141 | 166 |
self.openTrace(proto_filename) |
142 | 167 |
|
168 |
+ def fillProcessesEntry(self, proc_iter, |
|
169 |
+ proc: uproctrace.processes.Process): |
|
170 |
+ """ |
|
171 |
+ Fill attributes of processes tree entry. |
|
172 |
+ proc_iter: process tree entry |
|
173 |
+ proc: process object |
|
174 |
+ """ |
|
175 |
+ self.wid_processes_tree.set_value(proc_iter, self.PROC_PROC_ID, |
|
176 |
+ proc.proc_id) |
|
177 |
+ self.fillProcessesEntryAttr(proc_iter, self.PROC_BEGIN_TIMESTAMP, |
|
178 |
+ self.PROC_BEGIN_TIMESTAMP_TEXT, |
|
179 |
+ timestamp2str, proc.begin_timestamp) |
|
180 |
+ self.fillProcessesEntryAttr(proc_iter, self.PROC_END_TIMESTAMP, |
|
181 |
+ self.PROC_END_TIMESTAMP_TEXT, |
|
182 |
+ timestamp2str, proc.end_timestamp) |
|
183 |
+ self.wid_processes_tree.set_value(proc_iter, self.PROC_CMDLINE, |
|
184 |
+ cmdline2str(proc.cmdline)) |
|
185 |
+ self.fillProcessesEntryAttr(proc_iter, self.PROC_CPU_TIME, |
|
186 |
+ self.PROC_CPU_TIME_TEXT, duration2str, |
|
187 |
+ proc.cpu_time) |
|
188 |
+ self.fillProcessesEntryAttr(proc_iter, self.PROC_MAX_RSS_KB, |
|
189 |
+ self.PROC_MAX_RSS_KB_TEXT, kb2str, |
|
190 |
+ proc.max_rss_kb) |
|
191 |
+ self.fillProcessesEntryAttr(proc_iter, self.PROC_PAGE_FAULTS, |
|
192 |
+ self.PROC_PAGE_FAULTS_TEXT, int2str, |
|
193 |
+ add_none(proc.min_flt, proc.maj_flt)) |
|
194 |
+ self.fillProcessesEntryAttr(proc_iter, self.PROC_FILE_SYS_OPS, |
|
195 |
+ self.PROC_FILE_SYS_OPS_TEXT, int2str, |
|
196 |
+ add_none(proc.in_block, proc.ou_block)) |
|
197 |
+ self.fillProcessesEntryAttr(proc_iter, self.PROC_CTX_SW, |
|
198 |
+ self.PROC_CTX_SW_TEXT, int2str, |
|
199 |
+ add_none(proc.n_v_csw, proc.n_iv_csw)) |
|
200 |
+ |
|
201 |
+ def fillProcessesEntryAttr(self, proc_iter, col: int, text_col: int, |
|
202 |
+ val2str_func, val): |
|
203 |
+ """ |
|
204 |
+ Fill attribute of processes tree entry. |
|
205 |
+ proc_iter: process tree entry |
|
206 |
+ col: value column number |
|
207 |
+ text_col: text column number |
|
208 |
+ val2str_func: function to transform value to string |
|
209 |
+ val: value |
|
210 |
+ """ |
|
211 |
+ # pylint: disable=R0913 |
|
212 |
+ self.wid_processes_tree.set_value(proc_iter, col, val) |
|
213 |
+ self.wid_processes_tree.set_value(proc_iter, text_col, |
|
214 |
+ val2str_func(val)) |
|
215 |
+ |
|
143 | 216 |
def onDestroy(self, _widget): |
144 | 217 |
""" |
145 | 218 |
Window will be destroyed. |
... | ... |
@@ -219,32 +292,7 @@ class UptGui: |
219 | 292 |
proc = procs[0] |
220 | 293 |
del procs[0] |
221 | 294 |
proc_iter = self.wid_processes_tree.append(parent_iter) |
222 |
- self.wid_processes_tree.set_value(proc_iter, self.PROC_PROC_ID, |
|
223 |
- proc.proc_id) |
|
224 |
- self.wid_processes_tree.set_value(proc_iter, |
|
225 |
- self.PROC_BEGIN_TIMESTAMP, |
|
226 |
- proc.begin_timestamp) |
|
227 |
- self.wid_processes_tree.set_value( |
|
228 |
- proc_iter, self.PROC_BEGIN_TIMESTAMP_TEXT, |
|
229 |
- timestamp2str(proc.begin_timestamp)) |
|
230 |
- self.wid_processes_tree.set_value(proc_iter, |
|
231 |
- self.PROC_END_TIMESTAMP, |
|
232 |
- proc.end_timestamp) |
|
233 |
- self.wid_processes_tree.set_value( |
|
234 |
- proc_iter, self.PROC_END_TIMESTAMP_TEXT, |
|
235 |
- timestamp2str(proc.end_timestamp)) |
|
236 |
- self.wid_processes_tree.set_value(proc_iter, self.PROC_CMDLINE, |
|
237 |
- cmdline2str(proc.cmdline)) |
|
238 |
- self.wid_processes_tree.set_value(proc_iter, self.PROC_CPU_TIME, |
|
239 |
- proc.cpu_time) |
|
240 |
- self.wid_processes_tree.set_value(proc_iter, |
|
241 |
- self.PROC_CPU_TIME_TEXT, |
|
242 |
- duration2str(proc.cpu_time)) |
|
243 |
- self.wid_processes_tree.set_value(proc_iter, self.PROC_MAX_RSS_KB, |
|
244 |
- proc.max_rss_kb) |
|
245 |
- self.wid_processes_tree.set_value(proc_iter, |
|
246 |
- self.PROC_MAX_RSS_KB_TEXT, |
|
247 |
- kb2str(proc.max_rss_kb)) |
|
295 |
+ self.fillProcessesEntry(proc_iter, proc) |
|
248 | 296 |
to_be_output.append((proc.children, proc_iter)) |
249 | 297 |
# show all processes |
250 | 298 |
self.wid_processes_view.expand_all() |
... | ... |
@@ -317,15 +365,36 @@ class UptGui: |
317 | 365 |
add(f'{key} {i:d}', value, list_iter) |
318 | 366 |
return list_iter |
319 | 367 |
|
368 |
+ def add_sum(key: str, sub_keys: list, values: list, parent_iter=None): |
|
369 |
+ """ |
|
370 |
+ Add a sum of multiple values to a process and include individual |
|
371 |
+ values as subtree. |
|
372 |
+ Add to specified parent (if parent_iter is specified). |
|
373 |
+ Return iterator to added top-level of detail subtree. |
|
374 |
+ """ |
|
375 |
+ sum_val = functools.reduce(add_none, values, 0) |
|
376 |
+ sum_iter = add(key, int2str(sum_val), parent_iter) |
|
377 |
+ for sub_key, val in zip(sub_keys, values): |
|
378 |
+ add(sub_key, int2str(val), sum_iter) |
|
379 |
+ self.wid_details_view.expand_row( |
|
380 |
+ self.wid_details_tree.get_path(sum_iter), True) |
|
381 |
+ return sum_iter |
|
382 |
+ |
|
320 | 383 |
add('begin time', timestamp2str(proc.begin_timestamp)) |
321 | 384 |
cmdline_iter = add_list('command line', proc.cmdline) |
322 | 385 |
self.wid_details_view.expand_row( |
323 | 386 |
self.wid_details_tree.get_path(cmdline_iter), True) |
387 |
+ add_sum('context switches', ['involuntary', 'voluntary'], |
|
388 |
+ [proc.n_iv_csw, proc.n_v_csw]) |
|
324 | 389 |
add('CPU time', duration2str(proc.cpu_time)) |
325 | 390 |
add('end time', timestamp2str(proc.end_timestamp)) |
326 | 391 |
add_list('environment', sorted(proc.environ)) |
327 | 392 |
add('executable', proc.exe) |
393 |
+ add_sum('file system operations', ['input', 'output'], |
|
394 |
+ [proc.in_block, proc.ou_block]) |
|
328 | 395 |
add('max. resident memory', kb2str(proc.max_rss_kb)) |
396 |
+ add_sum('page faults', ['major', 'minor'], |
|
397 |
+ [proc.maj_flt, proc.min_flt]) |
|
329 | 398 |
add('pid', str(proc.pid)) |
330 | 399 |
add('ppid', str(proc.ppid)) |
331 | 400 |
add('system CPU time', duration2str(proc.sys_time)) |
... | ... |
@@ -164,6 +163,9 @@ class ProcEnd(ProcBeginOrEnd): |
164 | 163 |
""" |
165 | 164 |
Process end event. |
166 | 165 |
""" |
166 |
+ |
|
167 |
+ # pylint: disable=R0902 |
|
168 |
+ |
|
167 | 169 |
def __init__(self, pb2_ev: pb2.event): |
168 | 170 |
""" |
169 | 171 |
Initialize process end event from PB2 event. |
... | ... |
@@ -179,6 +181,12 @@ class ProcEnd(ProcBeginOrEnd): |
179 | 181 |
p_e.sys_time) if p_e.HasField('sys_time') else None |
180 | 182 |
self._max_rss_kb = p_e.max_rss_kb if p_e.HasField( |
181 | 183 |
'max_rss_kb') else None |
184 |
+ self._min_flt = p_e.min_flt if p_e.HasField('min_flt') else None |
|
185 |
+ self._maj_flt = p_e.maj_flt if p_e.HasField('maj_flt') else None |
|
186 |
+ self._in_block = p_e.in_block if p_e.HasField('in_block') else None |
|
187 |
+ self._ou_block = p_e.ou_block if p_e.HasField('ou_block') else None |
|
188 |
+ self._n_v_csw = p_e.n_v_csw if p_e.HasField('n_v_csw') else None |
|
189 |
+ self._n_iv_csw = p_e.n_iv_csw if p_e.HasField('n_iv_csw') else None |
|
182 | 190 |
|
183 | 191 |
@property |
184 | 192 |
def pid(self) -> int: |
... | ... |
@@ -215,6 +223,48 @@ class ProcEnd(ProcBeginOrEnd): |
215 | 223 |
""" |
216 | 224 |
return self._max_rss_kb |
217 | 225 |
|
226 |
+ @property |
|
227 |
+ def min_flt(self) -> int: |
|
228 |
+ """ |
|
229 |
+ Minor page fault count (i.e. no I/O). |
|
230 |
+ """ |
|
231 |
+ return self._min_flt |
|
232 |
+ |
|
233 |
+ @property |
|
234 |
+ def maj_flt(self) -> int: |
|
235 |
+ """ |
|
236 |
+ Major page fault count (i.e. I/O needed). |
|
237 |
+ """ |
|
238 |
+ return self._maj_flt |
|
239 |
+ |
|
240 |
+ @property |
|
241 |
+ def in_block(self) -> int: |
|
242 |
+ """ |
|
243 |
+ Number of input operations on file system. |
|
244 |
+ """ |
|
245 |
+ return self._in_block |
|
246 |
+ |
|
247 |
+ @property |
|
248 |
+ def ou_block(self) -> int: |
|
249 |
+ """ |
|
250 |
+ Number of output operations on file system. |
|
251 |
+ """ |
|
252 |
+ return self._ou_block |
|
253 |
+ |
|
254 |
+ @property |
|
255 |
+ def n_v_csw(self) -> int: |
|
256 |
+ """ |
|
257 |
+ Number of voluntary context switches. |
|
258 |
+ """ |
|
259 |
+ return self._n_v_csw |
|
260 |
+ |
|
261 |
+ @property |
|
262 |
+ def n_iv_csw(self) -> int: |
|
263 |
+ """ |
|
264 |
+ Number of involuntary context switches. |
|
265 |
+ """ |
|
266 |
+ return self._n_iv_csw |
|
267 |
+ |
|
218 | 268 |
|
219 | 269 |
class Visitor(abc.ABC): |
220 | 270 |
""" |
... | ... |
@@ -13,6 +12,8 @@ class Process(): |
13 | 12 |
""" |
14 | 13 |
A process parsed from a trace. |
15 | 14 |
""" |
15 |
+ |
|
16 |
+ # pylint: disable=R0904 |
|
16 | 17 |
def __init__(self, proc_id: int, pid: int): |
17 | 18 |
""" |
18 | 19 |
Initialize process. |
... | ... |
@@ -94,6 +95,24 @@ class Process(): |
94 | 95 |
return None |
95 | 96 |
return self._begin.exe |
96 | 97 |
|
98 |
+ @property |
|
99 |
+ def in_block(self) -> int: |
|
100 |
+ """ |
|
101 |
+ Number of input operations on file system. |
|
102 |
+ """ |
|
103 |
+ if self._end is None: |
|
104 |
+ return None |
|
105 |
+ return self._end.in_block |
|
106 |
+ |
|
107 |
+ @property |
|
108 |
+ def maj_flt(self) -> int: |
|
109 |
+ """ |
|
110 |
+ Major page fault count (i.e. I/O needed). |
|
111 |
+ """ |
|
112 |
+ if self._end is None: |
|
113 |
+ return None |
|
114 |
+ return self._end.maj_flt |
|
115 |
+ |
|
97 | 116 |
@property |
98 | 117 |
def max_rss_kb(self) -> int: |
99 | 118 |
""" |
... | ... |
@@ -103,6 +122,42 @@ class Process(): |
103 | 122 |
return None |
104 | 123 |
return self._end.max_rss_kb |
105 | 124 |
|
125 |
+ @property |
|
126 |
+ def min_flt(self) -> int: |
|
127 |
+ """ |
|
128 |
+ Minor page fault count (i.e. no I/O). |
|
129 |
+ """ |
|
130 |
+ if self._end is None: |
|
131 |
+ return None |
|
132 |
+ return self._end.min_flt |
|
133 |
+ |
|
134 |
+ @property |
|
135 |
+ def n_iv_csw(self) -> int: |
|
136 |
+ """ |
|
137 |
+ Number of involuntary context switches. |
|
138 |
+ """ |
|
139 |
+ if self._end is None: |
|
140 |
+ return None |
|
141 |
+ return self._end.n_iv_csw |
|
142 |
+ |
|
143 |
+ @property |
|
144 |
+ def n_v_csw(self) -> int: |
|
145 |
+ """ |
|
146 |
+ Number of voluntary context switches. |
|
147 |
+ """ |
|
148 |
+ if self._end is None: |
|
149 |
+ return None |
|
150 |
+ return self._end.n_v_csw |
|
151 |
+ |
|
152 |
+ @property |
|
153 |
+ def ou_block(self) -> int: |
|
154 |
+ """ |
|
155 |
+ Number of output operations on file system. |
|
156 |
+ """ |
|
157 |
+ if self._end is None: |
|
158 |
+ return None |
|
159 |
+ return self._end.ou_block |
|
160 |
+ |
|
106 | 161 |
@property |
107 | 162 |
def parent(self): |
108 | 163 |
""" |
... | ... |
@@ -13,19 +13,31 @@ message stringlist { |
13 | 13 |
|
14 | 14 |
message proc_begin { |
15 | 15 |
required int32 pid = 1; |
16 |
- optional int32 ppid = 2; |
|
17 |
- optional string exe = 3; |
|
18 |
- optional string cwd = 4; |
|
19 |
- optional stringlist cmdline = 5; |
|
20 |
- optional stringlist environ = 6; |
|
16 |
+ optional int32 ppid = 2; ///< pid of parent process |
|
17 |
+ optional string exe = 3; ///< path to executable |
|
18 |
+ optional string cwd = 4; ///< working directory |
|
19 |
+ optional stringlist cmdline = 5; ///< command line |
|
20 |
+ optional stringlist environ = 6; ///< environment variables |
|
21 | 21 |
} |
22 | 22 |
|
23 | 23 |
message proc_end { |
24 | 24 |
required int32 pid = 1; |
25 |
- optional timespec cpu_time = 2; |
|
26 |
- optional timespec user_time = 3; |
|
27 |
- optional timespec sys_time = 4; |
|
28 |
- optional int64 max_rss_kb = 5; |
|
25 |
+ /// fields from clock_gettime |
|
26 |
+ //@{ |
|
27 |
+ optional timespec cpu_time = 2; ///< CPU time usage |
|
28 |
+ //@} |
|
29 |
+ /// fields from getrusage |
|
30 |
+ //@{ |
|
31 |
+ optional timespec user_time = 3; ///< CPU time spent in user space |
|
32 |
+ optional timespec sys_time = 4; ///< CPU spent in kernel space |
|
33 |
+ optional int64 max_rss_kb = 5; ///< maximum resisent set size in KiB |
|
34 |
+ optional int64 min_flt = 6; ///< minor page fault count (i.e. no I/O) |
|
35 |
+ optional int64 maj_flt = 7; ///< major page fault count (i.e. I/O needed) |
|
36 |
+ optional int64 in_block = 8; ///< number of input operations on file system |
|
37 |
+ optional int64 ou_block = 9; ///< number of output operations on file system |
|
38 |
+ optional int64 n_v_csw = 10; ///< number of voluntary context switches |
|
39 |
+ optional int64 n_iv_csw = 11; ///< number of involuntary context switches |
|
40 |
+ //@} |
|
29 | 41 |
} |
30 | 42 |
|
31 | 43 |
message event { |
32 | 44 |