CPUMeter.c 10 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 "Settings.h"
#include "Platform.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
13

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

Hisham Muhammad's avatar
Hisham Muhammad committed
19
20
/*{
#include "Meter.h"
21
22
23
24
25
26
27
28
29
30
31
32
33

typedef enum {
   CPU_METER_NICE = 0,
   CPU_METER_NORMAL = 1,
   CPU_METER_KERNEL = 2,
   CPU_METER_IRQ = 3,
   CPU_METER_SOFTIRQ = 4,
   CPU_METER_STEAL = 5,
   CPU_METER_GUEST = 6,
   CPU_METER_IOWAIT = 7,
   CPU_METER_ITEMCOUNT = 8, // number of entries in this enum
} CPUMeterValues;

Hisham Muhammad's avatar
Hisham Muhammad committed
34
}*/
Hisham Muhammad's avatar
Hisham Muhammad committed
35

36
int CPUMeter_attributes[] = {
37
   CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, CPU_IOWAIT
38
};
Hisham Muhammad's avatar
Hisham Muhammad committed
39
40
41
42
43
44
45
46

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

47
static void CPUMeter_init(Meter* this) {
48
49
   int cpu = this->param;
   if (this->pl->cpuCount > 1) {
50
      char caption[10];
Hisham Muhammad's avatar
Hisham Muhammad committed
51
      sprintf(caption, "%-3d", Settings_cpuId(this->pl->settings, cpu - 1));
52
      Meter_setCaption(this, caption);
Hisham Muhammad's avatar
Hisham Muhammad committed
53
   }
54
55
   if (this->param == 0)
      Meter_setCaption(this, "Avg");
Hisham Muhammad's avatar
Hisham Muhammad committed
56
57
}

58
static void CPUMeter_setValues(Meter* this, char* buffer, int size) {
59
60
   int cpu = this->param;
   if (cpu > this->pl->cpuCount) {
Hisham Muhammad's avatar
Hisham Muhammad committed
61
62
63
      snprintf(buffer, size, "absent");
      return;
   }
64
   memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
Hisham Muhammad's avatar
Hisham Muhammad committed
65
   double percent = Platform_setCPUValues(this, cpu);
66
   snprintf(buffer, size, "%5.1f%%", percent);
Hisham Muhammad's avatar
Hisham Muhammad committed
67
68
}

69
static void CPUMeter_display(Object* cast, RichString* out) {
Hisham Muhammad's avatar
Hisham Muhammad committed
70
71
   char buffer[50];
   Meter* this = (Meter*)cast;
72
   RichString_prune(out);
73
   if (this->param > this->pl->cpuCount) {
Hisham Muhammad's avatar
Hisham Muhammad committed
74
75
76
      RichString_append(out, CRT_colors[METER_TEXT], "absent");
      return;
   }
77
   sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_NORMAL]);
Hisham Muhammad's avatar
Hisham Muhammad committed
78
79
   RichString_append(out, CRT_colors[METER_TEXT], ":");
   RichString_append(out, CRT_colors[CPU_NORMAL], buffer);
Hisham Muhammad's avatar
Hisham Muhammad committed
80
   if (this->pl->settings->detailedCPUTime) {
81
      sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_KERNEL]);
82
83
      RichString_append(out, CRT_colors[METER_TEXT], "sy:");
      RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
84
      sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_NICE]);
85
      RichString_append(out, CRT_colors[METER_TEXT], "ni:");
86
      RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
87
      sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_IRQ]);
88
89
      RichString_append(out, CRT_colors[METER_TEXT], "hi:");
      RichString_append(out, CRT_colors[CPU_IRQ], buffer);
90
      sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]);
91
92
      RichString_append(out, CRT_colors[METER_TEXT], "si:");
      RichString_append(out, CRT_colors[CPU_SOFTIRQ], buffer);
93
94
      if (this->values[CPU_METER_STEAL]) {
         sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_STEAL]);
95
96
97
         RichString_append(out, CRT_colors[METER_TEXT], "st:");
         RichString_append(out, CRT_colors[CPU_STEAL], buffer);
      }
98
99
      if (this->values[CPU_METER_GUEST]) {
         sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_GUEST]);
100
101
102
         RichString_append(out, CRT_colors[METER_TEXT], "gu:");
         RichString_append(out, CRT_colors[CPU_GUEST], buffer);
      }
103
      sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_IOWAIT]);
104
105
      RichString_append(out, CRT_colors[METER_TEXT], "wa:");
      RichString_append(out, CRT_colors[CPU_IOWAIT], buffer);
106
   } else {
107
      sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_KERNEL]);
108
109
      RichString_append(out, CRT_colors[METER_TEXT], "sys:");
      RichString_append(out, CRT_colors[CPU_KERNEL], buffer);
110
      sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_NICE]);
111
      RichString_append(out, CRT_colors[METER_TEXT], "low:");
112
      RichString_append(out, CRT_colors[CPU_NICE_TEXT], buffer);
113
114
      if (this->values[CPU_METER_IRQ]) {
         sprintf(buffer, "%5.1f%% ", this->values[CPU_METER_IRQ]);
115
116
117
         RichString_append(out, CRT_colors[METER_TEXT], "vir:");
         RichString_append(out, CRT_colors[CPU_GUEST], buffer);
      }
118
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
119
}
120

121
122
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
   int cpus = this->pl->cpuCount;
123
   switch(Meter_name(this)[0]) {
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
      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;
   }
}

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

161
static void AllCPUsMeter_done(Meter* this) {
162
   Meter** meters = (Meter**) this->drawData;
163
164
165
   int start, count;
   AllCPUsMeter_getRange(this, &start, &count);
   for (int i = 0; i < count; i++)
166
167
168
      Meter_delete((Object*)meters[i]);
}

169
static void AllCPUsMeter_updateMode(Meter* this, int mode) {
170
   Meter** meters = (Meter**) this->drawData;
171
   this->mode = mode;
172
173
174
175
176
177
   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);
   }
178
   if (strchr(Meter_name(this), '2'))
179
180
181
      this->h = h * ((count+1) / 2);
   else
      this->h = h * count;
182
183
}

184
185
186
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
   Meter** meters = (Meter**) this->drawData;
   int start, count;
187
   int pad = this->pl->settings->headerMargin ? 2 : 0;
188
189
190
191
   AllCPUsMeter_getRange(this, &start, &count);
   int height = (count+1)/2;
   int startY = y;
   for (int i = 0; i < height; i++) {
192
      meters[i]->draw(meters[i], x, y, (w-pad)/2);
193
194
195
196
      y += meters[i]->h;
   }
   y = startY;
   for (int i = height; i < count; i++) {
197
      meters[i]->draw(meters[i], x+(w-1)/2+1+(pad/2), y, (w-pad)/2);
198
199
200
201
202
      y += meters[i]->h;
   }
}

static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
203
   Meter** meters = (Meter**) this->drawData;
204
205
206
   int start, count;
   AllCPUsMeter_getRange(this, &start, &count);
   for (int i = 0; i < count; i++) {
207
208
      meters[i]->draw(meters[i], x, y, w);
      y += meters[i]->h;
209
210
   }
}
211

212
213
214
215
216
217
MeterClass CPUMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
218
   .setValues = CPUMeter_setValues, 
219
   .defaultMode = BAR_METERMODE,
220
   .maxItems = CPU_METER_ITEMCOUNT,
221
222
223
224
225
226
227
228
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "CPU",
   .uiName = "CPU",
   .caption = "CPU",
   .init = CPUMeter_init
};

229
230
231
232
233
234
235
MeterClass AllCPUsMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
236
237
238
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "AllCPUs",
239
   .uiName = "CPUs (1/1)",
240
   .description = "CPUs (1/1): all CPUs",
241
   .caption = "CPU",
242
   .draw = SingleColCPUsMeter_draw,
243
   .init = AllCPUsMeter_init,
244
   .updateMode = AllCPUsMeter_updateMode,
245
246
   .done = AllCPUsMeter_done
};
247

248
249
250
251
252
253
254
MeterClass AllCPUs2Meter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
255
256
257
258
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "AllCPUs2",
   .uiName = "CPUs (1&2/2)",
259
   .description = "CPUs (1&2/2): all CPUs in 2 shorter columns",
260
261
262
   .caption = "CPU",
   .draw = DualColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
263
   .updateMode = AllCPUsMeter_updateMode,
264
265
266
   .done = AllCPUsMeter_done
};

267
268
269
270
271
272
273
MeterClass LeftCPUsMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
274
275
276
277
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "LeftCPUs",
   .uiName = "CPUs (1/2)",
278
   .description = "CPUs (1/2): first half of list",
279
280
281
   .caption = "CPU",
   .draw = SingleColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
282
   .updateMode = AllCPUsMeter_updateMode,
283
284
285
   .done = AllCPUsMeter_done
};

286
287
288
289
290
291
292
MeterClass RightCPUsMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
293
294
295
296
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "RightCPUs",
   .uiName = "CPUs (2/2)",
297
   .description = "CPUs (2/2): second half of list",
298
299
300
   .caption = "CPU",
   .draw = SingleColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
301
   .updateMode = AllCPUsMeter_updateMode,
302
303
304
   .done = AllCPUsMeter_done
};

305
306
307
308
309
310
311
MeterClass LeftCPUs2Meter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
312
313
314
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "LeftCPUs2",
315
   .description = "CPUs (1&2/4): first half in 2 shorter columns",
316
317
318
319
   .uiName = "CPUs (1&2/4)",
   .caption = "CPU",
   .draw = DualColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
320
   .updateMode = AllCPUsMeter_updateMode,
321
322
323
   .done = AllCPUsMeter_done
};

324
325
326
327
328
329
330
MeterClass RightCPUs2Meter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = CPUMeter_display
   },
   .defaultMode = CUSTOM_METERMODE,
331
332
333
334
   .total = 100.0,
   .attributes = CPUMeter_attributes, 
   .name = "RightCPUs2",
   .uiName = "CPUs (3&4/4)",
335
   .description = "CPUs (3&4/4): second half in 2 shorter columns",
336
337
338
   .caption = "CPU",
   .draw = DualColCPUsMeter_draw,
   .init = AllCPUsMeter_init,
339
   .updateMode = AllCPUsMeter_updateMode,
340
341
342
   .done = AllCPUsMeter_done
};