CPUMeter.c 10.2 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
/*
htop - CPUMeter.c
Hisham Muhammad's avatar
Hisham Muhammad committed
3
(C) 2004-2011 Hisham H. Muhammad
Hisham Muhammad's avatar
Hisham Muhammad committed
4
5
6
7
8
9
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "CPUMeter.h"

Hisham Muhammad's avatar
Hisham Muhammad committed
10
#include "CRT.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
11
12
#include "ProcessList.h"

Hisham Muhammad's avatar
Hisham Muhammad committed
13
#include <assert.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
14
15
16
17
18
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <math.h>

Hisham Muhammad's avatar
Hisham Muhammad committed
19
20
21
/*{
#include "Meter.h"
}*/
Hisham Muhammad's avatar
Hisham Muhammad committed
22

23
int CPUMeter_attributes[] = {
24
   CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_IOWAIT, CPU_STEAL, CPU_GUEST
25
};
Hisham Muhammad's avatar
Hisham Muhammad committed
26
27
28
29
30
31
32
33

#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif

34
static void CPUMeter_init(Meter* this) {
35
36
   int cpu = this->param;
   if (this->pl->cpuCount > 1) {
37
      char caption[10];
38
      sprintf(caption, "%-3d", ProcessList_cpuId(this->pl, cpu - 1));
39
      Meter_setCaption(this, caption);
Hisham Muhammad's avatar
Hisham Muhammad committed
40
   }
41
42
   if (this->param == 0)
      Meter_setCaption(this, "Avg");
Hisham Muhammad's avatar
Hisham Muhammad committed
43
44
}

45
static void CPUMeter_setValues(Meter* this, char* buffer, int size) {
46
   ProcessList* pl = this->pl;
47
48
   int cpu = this->param;
   if (cpu > this->pl->cpuCount) {
Hisham Muhammad's avatar
Hisham Muhammad committed
49
50
51
      snprintf(buffer, size, "absent");
      return;
   }
52
53
54
55
56
   CPUData* cpuData = &(pl->cpus[cpu]);
   double total = (double) ( cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod);
   double percent;
   this->values[0] = cpuData->nicePeriod / total * 100.0;
   this->values[1] = cpuData->userPeriod / total * 100.0;
57
   if (pl->detailedCPUTime) {
58
59
60
61
62
63
      this->values[2] = cpuData->systemPeriod / total * 100.0;
      this->values[3] = cpuData->irqPeriod / total * 100.0;
      this->values[4] = cpuData->softIrqPeriod / total * 100.0;
      this->values[5] = cpuData->ioWaitPeriod / total * 100.0;
      this->values[6] = cpuData->stealPeriod / total * 100.0;
      this->values[7] = cpuData->guestPeriod / total * 100.0;
64
      Meter_setItems(this, 8);
65
      percent = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+
66
                       this->values[3]+this->values[4])));
67
   } else {
68
69
      this->values[2] = cpuData->systemAllPeriod / total * 100.0;
      this->values[3] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0;
70
      Meter_setItems(this, 4);
71
      percent = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+this->values[3])));
72
   }
73
74
   if (isnan(percent)) percent = 0.0;
   snprintf(buffer, size, "%5.1f%%", percent);
Hisham Muhammad's avatar
Hisham Muhammad committed
75
76
}

77
static void CPUMeter_display(Object* cast, RichString* out) {
Hisham Muhammad's avatar
Hisham Muhammad committed
78
79
   char buffer[50];
   Meter* this = (Meter*)cast;
80
   RichString_prune(out);
81
   if (this->param > this->pl->cpuCount) {
Hisham Muhammad's avatar
Hisham Muhammad committed
82
83
84
      RichString_append(out, CRT_colors[METER_TEXT], "absent");
      return;
   }
85
   sprintf(buffer, "%5.1f%% ", this->values[1]);
Hisham Muhammad's avatar
Hisham Muhammad committed
86
87
   RichString_append(out, CRT_colors[METER_TEXT], ":");
   RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
88
   if (this->pl->detailedCPUTime) {
89
90
91
92
93
94
95
96
97
98
99
100
      sprintf(buffer, "%5.1f%% ", this->values[2]);
      RichString_append(out, CRT_colors[METER_TEXT], "sy:");
      RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
      sprintf(buffer, "%5.1f%% ", this->values[0]);
      RichString_append(out, CRT_colors[METER_TEXT], "ni:");
      RichString_append(out, CRT_colors[CPU_NICE], buffer);
      sprintf(buffer, "%5.1f%% ", this->values[3]);
      RichString_append(out, CRT_colors[METER_TEXT], "hi:");
      RichString_append(out, CRT_colors[CPU_IRQ], buffer);
      sprintf(buffer, "%5.1f%% ", this->values[4]);
      RichString_append(out, CRT_colors[METER_TEXT], "si:");
      RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
101
102
103
      sprintf(buffer, "%5.1f%% ", this->values[5]);
      RichString_append(out, CRT_colors[METER_TEXT], "wa:");
      RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
104
105
106
107
108
109
110
111
      sprintf(buffer, "%5.1f%% ", this->values[6]);
      RichString_append(out, CRT_colors[METER_TEXT], "st:");
      RichString_append(out, CRT_colors[CPU_STEAL], buffer);
      if (this->values[7]) {
         sprintf(buffer, "%5.1f%% ", this->values[7]);
         RichString_append(out, CRT_colors[METER_TEXT], "gu:");
         RichString_append(out, CRT_colors[CPU_GUEST], buffer);
      }
112
113
114
115
116
117
118
   } else {
      sprintf(buffer, "%5.1f%% ", this->values[2]);
      RichString_append(out, CRT_colors[METER_TEXT], "sys:");
      RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
      sprintf(buffer, "%5.1f%% ", this->values[0]);
      RichString_append(out, CRT_colors[METER_TEXT], "low:");
      RichString_append(out, CRT_colors[CPU_NICE], buffer);
119
120
121
122
123
      if (this->values[3]) {
         sprintf(buffer, "%5.1f%% ", this->values[3]);
         RichString_append(out, CRT_colors[METER_TEXT], "vir:");
         RichString_append(out, CRT_colors[CPU_GUEST], buffer);
      }
124
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
125
}
126

127
128
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
   int cpus = this->pl->cpuCount;
129
   switch(Meter_name(this)[0]) {
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
      default:
      case 'A': // All
         *start = 0;
         *count = cpus;
         break;
      case 'L': // First Half
         *start = 0;
         *count = (cpus+1) / 2;
         break;
      case 'R': // Second Half
         *start = (cpus+1) / 2;
         *count = cpus / 2;
         break;
   }
}

146
static void AllCPUsMeter_init(Meter* this) {
147
   int cpus = this->pl->cpuCount;
148
149
   if (!this->drawData)
      this->drawData = calloc(sizeof(Meter*), cpus);
150
   Meter** meters = (Meter**) this->drawData;
151
152
153
   int start, count;
   AllCPUsMeter_getRange(this, &start, &count);
   for (int i = 0; i < count; i++) {
154
      if (!meters[i])
155
156
         meters[i] = Meter_new(this->pl, start+i+1, (MeterClass*) Class(CPUMeter));
      Meter_init(meters[i]);
157
   }
158
159
160
   if (this->mode == 0)
      this->mode = BAR_METERMODE;
   int h = Meter_modes[this->mode]->h;
161
   if (strchr(Meter_name(this), '2'))
162
163
164
      this->h = h * ((count+1) / 2);
   else
      this->h = h * count;
165
166
}

167
static void AllCPUsMeter_done(Meter* this) {
168
   Meter** meters = (Meter**) this->drawData;
169
170
171
   int start, count;
   AllCPUsMeter_getRange(this, &start, &count);
   for (int i = 0; i < count; i++)
172
173
174
      Meter_delete((Object*)meters[i]);
}

175
static void AllCPUsMeter_updateMode(Meter* this, int mode) {
176
   Meter** meters = (Meter**) this->drawData;
177
   this->mode = mode;
178
179
180
181
182
183
   int h = Meter_modes[mode]->h;
   int start, count;
   AllCPUsMeter_getRange(this, &start, &count);
   for (int i = 0; i < count; i++) {
      Meter_setMode(meters[i], mode);
   }
184
   if (strchr(Meter_name(this), '2'))
185
186
187
      this->h = h * ((count+1) / 2);
   else
      this->h = h * count;
188
189
}

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
   Meter** meters = (Meter**) this->drawData;
   int start, count;
   AllCPUsMeter_getRange(this, &start, &count);
   int height = (count+1)/2;
   int startY = y;
   for (int i = 0; i < height; i++) {
      meters[i]->draw(meters[i], x, y, (w-2)/2);
      y += meters[i]->h;
   }
   y = startY;
   for (int i = height; i < count; i++) {
      meters[i]->draw(meters[i], x+(w-1)/2+2, y, (w-2)/2);
      y += meters[i]->h;
   }
}

static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
208
   Meter** meters = (Meter**) this->drawData;
209
210
211
   int start, count;
   AllCPUsMeter_getRange(this, &start, &count);
   for (int i = 0; i < count; i++) {
212
213
      meters[i]->draw(meters[i], x, y, w);
      y += meters[i]->h;
214
215
   }
}
216

217
218
219
220
221
222
MeterClass CPUMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
223
   .setValues = CPUMeter_setValues, 
224
   .defaultMode = BAR_METERMODE,
225
   .items = 8,
226
227
228
229
230
231
232
233
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "CPU",
   .uiName = "CPU",
   .caption = "CPU",
   .init = CPUMeter_init
};

234
235
236
237
238
239
240
MeterClass AllCPUsMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
241
242
243
244
   .items = 1,
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "AllCPUs",
245
   .uiName = "CPUs (1/1)",
246
   .caption = "CPU",
247
   .draw = SingleColCPUsMeter_draw,
248
   .init = AllCPUsMeter_init,
249
   .updateMode = AllCPUsMeter_updateMode,
250
251
   .done = AllCPUsMeter_done
};
252

253
254
255
256
257
258
259
MeterClass AllCPUs2Meter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
260
261
262
263
264
265
266
267
   .items = 1,
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "AllCPUs2",
   .uiName = "CPUs (1&2/2)",
   .caption = "CPU",
   .draw = DualColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
268
   .updateMode = AllCPUsMeter_updateMode,
269
270
271
   .done = AllCPUsMeter_done
};

272
273
274
275
276
277
278
MeterClass LeftCPUsMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
279
280
281
282
283
284
285
286
   .items = 1,
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "LeftCPUs",
   .uiName = "CPUs (1/2)",
   .caption = "CPU",
   .draw = SingleColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
287
   .updateMode = AllCPUsMeter_updateMode,
288
289
290
   .done = AllCPUsMeter_done
};

291
292
293
294
295
296
297
MeterClass RightCPUsMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
298
299
300
301
302
303
304
305
   .items = 1,
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "RightCPUs",
   .uiName = "CPUs (2/2)",
   .caption = "CPU",
   .draw = SingleColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
306
   .updateMode = AllCPUsMeter_updateMode,
307
308
309
   .done = AllCPUsMeter_done
};

310
311
312
313
314
315
316
MeterClass LeftCPUs2Meter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
317
318
319
320
321
322
323
324
   .items = 1,
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "LeftCPUs2",
   .uiName = "CPUs (1&2/4)",
   .caption = "CPU",
   .draw = DualColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
325
   .updateMode = AllCPUsMeter_updateMode,
326
327
328
   .done = AllCPUsMeter_done
};

329
330
331
332
333
334
335
MeterClass RightCPUs2Meter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
336
337
338
339
340
341
342
343
   .items = 1,
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "RightCPUs2",
   .uiName = "CPUs (3&4/4)",
   .caption = "CPU",
   .draw = DualColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
344
   .updateMode = AllCPUsMeter_updateMode,
345
346
347
   .done = AllCPUsMeter_done
};