~ubuntu-branches/ubuntu/hoary/kdeaddons/hoary

« back to all changes in this revision

Viewing changes to kicker-applets/ktimemon/sample.cc

  • Committer: Bazaar Package Importer
  • Author(s): Ben Burton
  • Date: 2002-04-01 16:42:29 UTC
  • Revision ID: james.westby@ubuntu.com-20020401164229-oxc5htazpgzyqygi
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************/
 
2
/*   TimeMon (c)  1994  Helmut Maierhofer                             */
 
3
/*   KDE-ified M. Maierhofer 1998                                     */
 
4
/**********************************************************************/
 
5
 
 
6
/*
 
7
 * sample.cc
 
8
 *
 
9
 * Definitions for the system dependent sampling class.
 
10
 */
 
11
 
 
12
#include <config.h>
 
13
 
 
14
#include <unistd.h>
 
15
#include <stdlib.h>
 
16
#include <errno.h>
 
17
#include <string.h>
 
18
#include <stdarg.h>
 
19
#include <sys/types.h>
 
20
#include <sys/stat.h>
 
21
#ifdef HAVE_FCNTL_H
 
22
#include <fcntl.h>
 
23
#endif
 
24
#include <fstream.h>
 
25
#include <stdio.h>
 
26
 
 
27
#ifdef __osf__
 
28
#include <sys/table.h>
 
29
#elif defined(__sun__)
 
30
#include <kstat.h>
 
31
#include <sys/sysinfo.h>
 
32
#include <sys/stat.h>
 
33
#include <sys/swap.h>
 
34
#endif
 
35
 
 
36
#include <qwidget.h>
 
37
#include <klocale.h>
 
38
#include <kmessagebox.h>
 
39
 
 
40
#include "timemon.h"
 
41
#include "sample.h"
 
42
 
 
43
// -- global definitions -------------------------------------------------
 
44
 
 
45
#if defined(__osf__) || defined(__sun__)
 
46
extern "C" int getpagesize();   // argh, have to define prototype!
 
47
#endif
 
48
 
 
49
#ifdef __linux__
 
50
// -- global constants ---------------------------------------------------
 
51
static const char *STAT_NAME = "stat";
 
52
static const char *MEMINFO_NAME = "meminfo";
 
53
static const char *MTAB_NAME = "/etc/mtab";
 
54
#endif
 
55
 
 
56
// -- KSample::Sample definition -----------------------------------------
 
57
 
 
58
// Fill sample with some default values (e.g. used in preview widget
 
59
// in configuration)
 
60
void KSample::Sample::fill(unsigned scale)
 
61
{
 
62
  user = scale * 40; user /= 100;
 
63
  nice = scale * 25; user /= 100;
 
64
  kernel = scale * 15; kernel /= 100;
 
65
  cpus = 1;
 
66
  buffers = scale * 20; buffers /= 100;
 
67
  used = scale * 30; used /= 100;
 
68
  cached = scale * 20; cached /= 100;
 
69
  sused = scale * 25; sused /= 100;
 
70
  pout = scale * 10; pout /= 100;
 
71
  pin = scale * 20; pin /= 100;
 
72
  swout = scale * 30; swout /= 100;
 
73
  swin = scale * 15; swin /= 100;
 
74
  cswitches = scale * 75; cswitches /= 100;
 
75
}
 
76
 
 
77
// -- KSample definition -------------------------------------------------
 
78
 
 
79
// Initialise the member variables and try to open the standard files in
 
80
// the proc filesystem; for other platforms perform equivalent initialisation
 
81
KSample::KSample(KTimeMon *t, bool a, unsigned p, unsigned s, unsigned c) :
 
82
  timemon(t),
 
83
#ifdef __linux__
 
84
  memFD(-1), statFD(-1),
 
85
#elif defined (__sun__)
 
86
  kc(0), warned(false),
 
87
#endif
 
88
  pageScale(p), swapScale(s), cxScale(c), autoscale(a)
 
89
{
 
90
#ifdef __linux__
 
91
 
 
92
  parseMtab(proc);
 
93
 
 
94
  char file[512];
 
95
  snprintf(file, sizeof(file), "%s/%s", proc, MEMINFO_NAME);
 
96
 
 
97
  if ((memFD = open(file, O_RDONLY)) == -1) {
 
98
    KMessageBox::error(timemon,
 
99
                       i18n("Sorry, I cannot open the file `%1'.\nThe diagnostics are: %2.\n\n"
 
100
                            "I need this file to determine current memory usage.\n"
 
101
                            "Maybe your proc filesystem is non Linux-standard?").arg(file).arg(strerror(errno)));
 
102
    exit(1);
 
103
  }
 
104
 
 
105
  snprintf(file, sizeof(file), "%s/%s", proc, STAT_NAME);
 
106
  if ((statFD = open(file, O_RDONLY)) == -1) {
 
107
    KMessageBox::error(timemon,
 
108
                       i18n("Sorry, I cannot open the file `%1'.\nThe diagnostics are: %2.\n\n"
 
109
                            "I need this file  to determine current system info.\n"
 
110
                            "Maybe your proc filesystem is non Linux-standard?").arg(file).arg(strerror(errno)));
 
111
    exit(1);
 
112
  }
 
113
 
 
114
#elif defined (__sun__)
 
115
  if ((kc = kstat_open()) == 0) {
 
116
    KMessageBox::error(timemon, i18n("Sorry, I cannot initialise the `kstat' library.\n"
 
117
                                     "This library is used for accessing kernel information.\n"
 
118
                                     "The diagnostics are: `%1'.\n\n"
 
119
                                     "Are you running Solaris at all?\n"
 
120
                                     "You may want to mail me at mueller@kde.org,\n"
 
121
                                     "I will try to figure out what went wrong.").arg(strerror(errno)));
 
122
    exit(1);
 
123
  }
 
124
#endif
 
125
 
 
126
#if defined(__sun__) || defined(__osf__)
 
127
  pagesPerMB = (1024*1024) / getpagesize();
 
128
  if (pagesPerMB == 0) pagesPerMB = 1; // paranoia sanity check
 
129
#endif
 
130
 
 
131
  readSample();
 
132
  updateSample();
 
133
}
 
134
 
 
135
// Get rid of the resources we acquired in the constructor.
 
136
KSample::~KSample()
 
137
{
 
138
#ifdef __linux__
 
139
  close(memFD);
 
140
  close(statFD);
 
141
#elif defined (__sun__)
 
142
  if (kc != 0) kstat_close(kc);
 
143
#endif
 
144
}
 
145
 
 
146
#ifdef __linux__
 
147
// Parse /etc/mtab to determine the proc filesystem mount point.
 
148
void KSample::parseMtab(char *dest)
 
149
{
 
150
    ifstream *mtab = new ifstream(MTAB_NAME);
 
151
    if (!mtab->good()) {
 
152
        KMessageBox::error(timemon, i18n("I cannot open file `%1' to determine where the proc\n"
 
153
                                         "filesystem is mounted. The diagnostics are:\n %2\n\n"
 
154
                                         "Are you running UNIX at all?!?").arg( MTAB_NAME).arg( strerror(errno)));
 
155
        exit(1);
 
156
    }
 
157
 
 
158
    unsigned lineno = 0;
 
159
    char line[1024];
 
160
    QString errormsg;
 
161
 
 
162
    for (;;) {
 
163
        lineno++;
 
164
        mtab->getline(line, sizeof(line));
 
165
 
 
166
        if (mtab->bad()) {
 
167
            errormsg = i18n("I cannot read file `%1' to determine where the proc\n"
 
168
                            "filesystem is mounted. The diagnostics are:\n %2").arg(MTAB_NAME).arg(strerror(errno));
 
169
            break;
 
170
        }
 
171
 
 
172
        if (mtab->eof()) {
 
173
            errormsg = i18n("Hmm, I could not figure out where the proc filesystem\n"
 
174
                            "is mounted (there is no entry in `%1').\n\n"
 
175
                            "I need information from the proc filesystem to determine\n"
 
176
                            "current system usage. Maybe you are not running Linux (I'm\n"
 
177
                            "afraid the proc filesystem is Linux specific)?\n\n"
 
178
                            "If you can provide help with porting KTimeMon to your\n"
 
179
                            "platform, please contact me at <mueller@kde.org>").arg(MTAB_NAME);
 
180
            break;
 
181
        }
 
182
 
 
183
        if (mtab->fail()) {
 
184
            errormsg = i18n("Hmm, I encountered a very long line while reading\n"
 
185
                            "information in `%1' (where \"very long\" is defined\n"
 
186
                            "as > %2). This happened at line %3.\n\n"
 
187
                            "Is %4 the mount table on your platform?\n\n")
 
188
                .arg(MTAB_NAME).arg(sizeof(line)).arg(lineno).arg(MTAB_NAME);
 
189
            break;
 
190
        }
 
191
 
 
192
        char *p, *m;
 
193
 
 
194
        if ((p = m = strchr(line, ' ')) != 0) p = strchr(m+1, ' ');
 
195
        if (p == 0 || strncmp(p+1, "proc ", 5) != 0) continue;
 
196
 
 
197
        *p = '\0';
 
198
        strncpy(dest, m+1, 256);
 
199
        mtab->close();
 
200
        delete mtab;
 
201
        return;
 
202
    }
 
203
 
 
204
    KMessageBox::error(timemon, errormsg);
 
205
    exit(1);
 
206
}
 
207
#endif
 
208
 
 
209
// Set the appropriate scaling parameters
 
210
void KSample::setScaling(bool a, unsigned p, unsigned s, unsigned c)
 
211
{
 
212
    autoscale = a;
 
213
    pageScale = p;
 
214
    swapScale = s;
 
215
    cxScale = c;
 
216
}
 
217
 
 
218
// -----------------------------------------------------------------------------
 
219
// Show a message box with the given message and terminate the application.
 
220
 
 
221
void KSample::fatal(const QString& msg)
 
222
{
 
223
    timemon->stop();
 
224
 
 
225
    KMessageBox::error(timemon, msg);
 
226
    exit(1);
 
227
}
 
228
 
 
229
 
 
230
// -----------------------------------------------------------------------------
 
231
// Show a message box with the given message and don't terminate the app ;-)
 
232
 
 
233
void KSample::nonfatal(const QString& msg)
 
234
{
 
235
    timemon->stop();
 
236
 
 
237
    KMessageBox::sorry(timemon, msg);
 
238
    timemon->cont();
 
239
}
 
240
 
 
241
 
 
242
// -----------------------------------------------------------------------------
 
243
// Read a new sample from the files or whatever resource the OS implements
 
244
 
 
245
void KSample::readSample()
 
246
{
 
247
    sample.cpus = 0;            // just to make sure...
 
248
 
 
249
#ifdef __linux__                // linux makes it simple: use the /proc if
 
250
    int l;
 
251
    char buffer[4096];
 
252
 
 
253
    lseek(memFD, 0, 0);
 
254
    if ((l = read(memFD, buffer, sizeof(buffer) - 1)) < 0)
 
255
        fatal(i18n("Sorry, I cannot read the memory usage file `%1/%2'.\n"
 
256
                   "The diagnostics are: %3").arg(proc).arg(MEMINFO_NAME).arg(strerror(errno)));
 
257
 
 
258
    buffer[l] = '\0';
 
259
    static struct {
 
260
        const char *name;
 
261
        unsigned long *stat;
 
262
    } memstats[] = {
 
263
        { "SwapTotal:", &sample.stotal },
 
264
        { "MemTotal:", &sample.mtotal },
 
265
        { "MemFree:", &sample.free },
 
266
        { "Buffers:", &sample.buffers },
 
267
        { "Cached:", &sample.cached },
 
268
        { "SwapFree:", &sample.sfree },
 
269
        { 0, 0 }
 
270
    };
 
271
 
 
272
    l = 0;
 
273
    char *p;
 
274
    while (memstats[l].name != 0) {
 
275
        p = strstr(buffer, memstats[l].name);
 
276
        if (p == 0 ||
 
277
            sscanf(p + strlen(memstats[l].name), "%lu kB", memstats[l].stat) < 1)
 
278
            fatal(i18n("Sorry, the memory usage file `%1/%2'\nseems to use a "
 
279
                       "different file format than I expect.\n\n"
 
280
                       "Maybe your version of the proc filesystem is\n"
 
281
                       "incompatible with mine. Mail me at\n"
 
282
                       "m.maierhofer@tees.ac.uk and I will try to sort this out.").arg(proc).arg(MEMINFO_NAME));
 
283
        l++;
 
284
    }
 
285
 
 
286
    lseek(statFD, 0, 0);
 
287
    if ((l = read(statFD, buffer, sizeof(buffer)-1)) < 0)
 
288
        fatal(i18n("Sorry, I cannot read the system usage file `%1/%2'.\n"
 
289
                   "The diagnostics are: %3").arg(proc).arg(STAT_NAME).arg(strerror(errno)));
 
290
 
 
291
    buffer[l] = '\0';
 
292
 
 
293
    bool ok = (sscanf(buffer, "cpu %lu %lu %lu %lu\n", &sample.user,
 
294
                      &sample.nice, &sample.kernel, &sample.idle) == 4);
 
295
 
 
296
    if (ok) {
 
297
        for (l = 0; l < MAX_CPU; l++) { // get individual stat for SMP machines
 
298
            char cpuname[10];
 
299
            sprintf(cpuname, "cpu%d", l);
 
300
 
 
301
            if ((p = strstr(buffer, cpuname)) == NULL) break;
 
302
 
 
303
            unsigned long u, n, k, i;
 
304
            ok = sscanf(p, "cpu%*d %lu %lu %lu %lu\n", &u, &n, &k, &i);
 
305
            if (!ok) break;
 
306
 
 
307
            sample.smptotal[l] = u+n+k+i;
 
308
            sample.smpbusy[l] = sample.smptotal[l] - i;
 
309
        }
 
310
    }
 
311
    sample.cpus = l;
 
312
 
 
313
    if (ok) {
 
314
        if ((p = strstr(buffer, "page")) == NULL) ok = false;
 
315
        else ok = (sscanf(p, "page %lu %lu\n", &sample.pin, &sample.pout) == 2);
 
316
    }
 
317
 
 
318
    if (ok) {
 
319
        if ((p = strstr(buffer, "swap")) == NULL) ok = false;
 
320
        else ok = (sscanf(p, "swap %lu %lu\n", &sample.swin, &sample.swout) == 2);
 
321
    }
 
322
 
 
323
    if (ok) {
 
324
        if ((p = strstr(buffer, "ctxt")) == NULL) ok = false;
 
325
        else ok = (sscanf(p, "ctxt %lu\n", &sample.cswitches) == 1);
 
326
    }
 
327
 
 
328
    if (!ok)
 
329
        fatal(i18n("Sorry, the system usage file `%1/%2'\n"
 
330
                   "seems to use a different file format than I expect.\n\n"
 
331
                   "Maybe your version of the proc filesystem is\n"
 
332
                   "incompatible with mine. Mail me at\n"
 
333
                   "mueller@kde.org and I will try to sort this out.").arg(proc).arg(STAT_NAME));
 
334
 
 
335
#elif defined(__osf__)          // in OSF/2, we can use table()
 
336
 
 
337
    QString msg = i18n("Sorry, I cannot get system information.\n\n"
 
338
                       "The table(2) system call returned an error\n"
 
339
                       "for table %1.\n\n"
 
340
                       "You may want to mail me at mueller@kde.org, "
 
341
                       "I will try to figure out what went wrong.");
 
342
 
 
343
    struct tbl_sysinfo sysinfo;
 
344
    if (table(TBL_SYSINFO, 0, &sysinfo, 1, sizeof(sysinfo)) != 1)
 
345
        fatal(msg.arg("TBL_SYSINFO"));
 
346
 
 
347
    sample.user = sysinfo.si_user;
 
348
    sample.nice = sysinfo.si_nice;
 
349
    sample.kernel = sysinfo.si_sys;
 
350
    sample.idle = sysinfo.si_idle + sysinfo.wait;
 
351
 
 
352
    struct tbl_vmstats vmstats;
 
353
    if (table(TBL_VMSTATS, 0, &vmstats, 1, sizeof(vmstats)) != 1)
 
354
        fatal(msg.arg("TBL_VMSTATS"));
 
355
 
 
356
    sample.mtotal = vmstats.free_count + vmstats.active_count +
 
357
        vmstats.inactive_count + vmstats.wire_count;
 
358
    sample.free = vmstats.free_count;
 
359
    sample.buffers = vmstats.inactive_count; // pages not used for some time
 
360
    sample.cached = vmstats.wire_count; // kernel/driver memory
 
361
 
 
362
    struct tbl_swapinfo swapinfo;
 
363
    if (table(TBL_SWAPINFO, -1, &swapinfo, 1, sizeof(swapinfo)) != 1)
 
364
        fatal(msg.arg("TBL_SWAPINFO"));
 
365
 
 
366
    sample.stotal = swapinfo.size;
 
367
    sample.sfree = swapinfo.free;
 
368
 
 
369
    struct tbl_paging paging;
 
370
    if (table(TBL_PAGING, 0, &paging, 1, sizeof(paging)) != 1)
 
371
        fatal(msg.arg("TBL_PAGING"));
 
372
 
 
373
    sample.pin = sample.swin = paging.v_pgpgin; // MM no separate swap
 
374
    sample.pout = sample.swout = paging.v_pgout;
 
375
 
 
376
    struct tbl_intr intr;
 
377
    if (table(TBL_INTR, 0, &intr, 1, sizeof(intr)) != 1)
 
378
        fatal(msg.arg("TBL_INTR"));
 
379
 
 
380
    sample.cswitches = intr.in_context;
 
381
 
 
382
#elif defined(__sun__)
 
383
    kstat_t *ksp;
 
384
 
 
385
    sample.cpus = 0;
 
386
    for (ksp = kc->kc_chain; ksp != 0; ksp = ksp->ks_next) {
 
387
        if (strncmp(ksp->ks_name, "cpu_stat", 8) != 0) continue;
 
388
        sample.cpus++;
 
389
    }
 
390
 
 
391
    if (sample.cpus == 0)
 
392
        fatal(i18n("Sorry, I cannot find any entries for CPU statistics\n"
 
393
                   "in the `kstat' library. Are you running a non-standard\n"
 
394
                   "version of Solaris?\n\n"
 
395
                   "Please contact me at mueller@kde.org and I will try to sort this out."));
 
396
 
 
397
    sample.user = sample.nice = sample.kernel = sample.idle = 0;
 
398
    sample.pin = sample.pout = sample.swin = sample.swout = 0;
 
399
    sample.cswitches = 0;
 
400
    sample.stotal = sample.sfree = 0;
 
401
 
 
402
    int cpus = 0;
 
403
    for (ksp = kc->kc_chain; ksp != 0; ksp = ksp->ks_next) {
 
404
        if (strncmp(ksp->ks_name, "cpu_stat", 8) != 0) continue;
 
405
        cpus++;
 
406
 
 
407
        cpu_stat_t cstat;
 
408
        if (kstat_read(kc, ksp, 0) == -1 || // update from kernel
 
409
            kstat_read(kc, ksp, &cstat) == -1) // and read into buffer
 
410
            fatal(i18n("Sorry, I cannot read the CPU statistics entry\n"
 
411
                       "from the `kstat' library. The diagnostics are `%1'.\n\n"
 
412
                       "You might want to contact me at\n"
 
413
                       "mueller@kde.org and I will try to sort this out.").arg(strerror(errno)));
 
414
 
 
415
        // fields are: idle user kernel iowait
 
416
        sample.user += cstat.cpu_sysinfo.cpu[1] / sample.cpus;
 
417
        sample.nice += cstat.cpu_sysinfo.cpu[3] / sample.cpus;
 
418
        sample.kernel += cstat.cpu_sysinfo.cpu[2] / sample.cpus;
 
419
        sample.idle += cstat.cpu_sysinfo.cpu[0] / sample.cpus;
 
420
 
 
421
        sample.pin += cstat.cpu_vminfo.pgin / sample.cpus;
 
422
        sample.pout += cstat.cpu_vminfo.pgout / sample.cpus;
 
423
        sample.swin += cstat.cpu_vminfo.swapin / sample.cpus;
 
424
        sample.swout += cstat.cpu_vminfo.swapout / sample.cpus;
 
425
 
 
426
        sample.cswitches += cstat.cpu_sysinfo.pswitch / sample.cpus;
 
427
    }
 
428
 
 
429
    if (cpus != sample.cpus)
 
430
        fatal(i18n("Huhh, now this is very strange.\n"
 
431
                   "The number of CPUs seems to have changed at\n"
 
432
                   "very short notice. Or the `kstat' library returns\n"
 
433
                   "inconsistent results (%1 vs. %2 CPUs).\n"
 
434
                   "Please contact me at mueller@kde.org and I will try to sort this out.").arg(sample.cpus).arg(cpus));
 
435
 
 
436
    // availrmem = pages of core for user-proc ( == physmem - kernelmem)
 
437
    // freemem = no of free pages
 
438
    // physmem == total mem in 4KB blocks
 
439
 
 
440
    errno = 0;
 
441
    if ((ksp = kstat_lookup(kc, "unix", -1, "system_pages")) == 0 ||
 
442
        kstat_read(kc, ksp, 0) == -1)
 
443
        fatal(i18n("Sorry, I cannot read the memory statistics entry\n"
 
444
                   "from the `kstat' library. The diagnostics are `%1'\n\n"
 
445
                   "You might want to contact me at\n"
 
446
                   "mueller@kde.org and I will try to sort this out.").arg(strerror(errno)));
 
447
 
 
448
    int i;
 
449
    unsigned long physmem = 0, freemem = 0, availrmem = 0;
 
450
 
 
451
    kstat_named_t *kn = (kstat_named_t *)ksp->ks_data;
 
452
    for (i = 0; i < (int) ksp->ks_ndata; i++) {
 
453
        if (strcmp(kn->name, "physmem") == 0) physmem = kn->value.ul;
 
454
        else if (strcmp(kn->name, "freemem") == 0) freemem = kn->value.ul;
 
455
        else if (strcmp(kn->name, "availrmem") == 0) availrmem = kn->value.ul;
 
456
        kn++;
 
457
    }
 
458
 
 
459
    if (physmem == 0)           // sanity check, this should always be > 0
 
460
        fatal(i18n("Uh uh, there seems to be a problem with my handling\n"
 
461
                   "of the `kstat' library: I determined 0 physical memory!\n"
 
462
                   "(Free memory is %1, available memory is %2.\n\n"
 
463
                   "Please contact me at mueller@kde.org and I will try to sort this out.").arg(freemem).arg(availrmem));
 
464
 
 
465
    sample.mtotal = physmem;
 
466
    sample.free = freemem;
 
467
    sample.buffers = 0;
 
468
    sample.cached = physmem - availrmem; // memory used by the kernel
 
469
 
 
470
    int swapentries;
 
471
    if ((swapentries = swapctl(SC_GETNSWP, 0)) == -1)
 
472
        fatal(i18n("Sorry, cannot determine the number of\n"
 
473
                   "swap spaces. The diagnostics are `%1'.\n\n"
 
474
                   "Please contact me at mueller@kde.org and I will try to sort this out.").arg(strerror(errno)));
 
475
 
 
476
    if (swapentries != 0) {
 
477
                                // 2* to get some space for padding??
 
478
        swaptbl_t *stbl = (swaptbl_t *) malloc(2*sizeof(int) + swapentries *
 
479
                                               sizeof(struct swapent));
 
480
        if (stbl == 0)
 
481
            fatal(i18n("Sorry, I ran out of memory while\n"
 
482
                       "trying to determine the swap usage.\n"
 
483
                       "I tried to allocate %1 bytes of memory (2 * %2 + %3 * %4).\n\n"
 
484
                       "Please contact me at mueller@kde.org and I will try to sort this out.")
 
485
                  .arg(2 * sizeof(int) + swapentries * sizeof(struct swapent))
 
486
                  .arg(sizeof(int)).arg(swapentries).arg(sizeof(struct swapent)));
 
487
 
 
488
        char path[1024];
 
489
        stbl->swt_n = swapentries;
 
490
        for (i = 0; i < swapentries; i++) stbl->swt_ent[i].ste_path = path;
 
491
 
 
492
        if ((swapentries = swapctl(SC_LIST, stbl)) == -1)
 
493
            fatal(i18n("Sorry, I cannot determine the swap usage.\n"
 
494
                       "The diagnostics are `%1'.\n\n"
 
495
                       "Please contact me at mueller@kde.org and I will try to sort this out.").arg(strerror(errno)));
 
496
 
 
497
 
 
498
        if (!warned && swapentries != stbl->swt_n) {
 
499
            warned = true;
 
500
            nonfatal(i18n("Strange, I requested information for\n"
 
501
                          "%1 swap spaces, but only got %2 swap entries back.\n"
 
502
                          "I am a bit confused now, but I will try to continue.\n\n"
 
503
                          "Please contact me at mueller@kde.org and I will try to sort this out.").arg(stbl->swt_n).arg(swapentries));
 
504
        }
 
505
 
 
506
        for (i = 0; i < swapentries; i++) {
 
507
            sample.stotal += stbl->swt_ent[i].ste_pages;
 
508
            sample.sfree += stbl->swt_ent[i].ste_free;
 
509
        }
 
510
 
 
511
        free(stbl);
 
512
    }
 
513
 
 
514
#endif
 
515
 
 
516
    sample.cputotal = sample.user + sample.nice + sample.kernel + sample.idle;
 
517
    sample.used = sample.mtotal - sample.free - sample.buffers - sample.cached;
 
518
    sample.sused = sample.stotal - sample.sfree;
 
519
}
 
520
 
 
521
// Read a new sample after copying the old one.
 
522
void KSample::updateSample()
 
523
{
 
524
    oldSample = sample;
 
525
    readSample();
 
526
}
 
527
 
 
528
// Convert v to a value representing megabytes.
 
529
inline void KSample::makeMBytes(unsigned long &v)
 
530
{
 
531
#ifdef __linux__
 
532
    v /= 1024;                  // can it be simpler ;-)
 
533
#elif defined (__osf__) || defined(__sun__)
 
534
    v /= pagesPerMB;
 
535
#endif
 
536
}
 
537
 
 
538
// Return unscaled sample
 
539
KSample::Sample KSample::getRawSample()
 
540
{
 
541
    Sample diff = sample;
 
542
 
 
543
    diff.cputotal -= oldSample.cputotal;
 
544
 
 
545
    diff.user -= oldSample.user;
 
546
    diff.nice -= oldSample.nice;
 
547
    diff.kernel -= oldSample.kernel;
 
548
 
 
549
    for (int i = 0; i < diff.cpus; i++) {
 
550
        diff.smptotal[i] -= oldSample.smptotal[i];
 
551
        diff.smpbusy[i] -= oldSample.smpbusy[i];
 
552
    }
 
553
 
 
554
    diff.pin -= oldSample.pin;
 
555
    diff.pout -= oldSample.pout;
 
556
 
 
557
    diff.swin -= oldSample.swin;
 
558
    diff.swout -= oldSample.swout;
 
559
 
 
560
    diff.cswitches -= oldSample.cswitches;
 
561
 
 
562
    return diff;
 
563
}
 
564
 
 
565
// Better scaling, round according to first decimal
 
566
inline unsigned long KSample::doScale(unsigned long value, unsigned scale1,
 
567
                                      unsigned long scale2)
 
568
{
 
569
    if (scale2 == 0) scale2 = (unsigned long)~0; // avoid SEGVs
 
570
 
 
571
    unsigned long v = value * scale1 * 10;
 
572
    v /= scale2;
 
573
    unsigned r = v % 10;
 
574
    v /= 10;
 
575
    if (r > 4) v++;
 
576
    return v;
 
577
}
 
578
 
 
579
// Provide the difference from the last to the current sample, scale it
 
580
// and return it.
 
581
KSample::Sample KSample::getSample(unsigned scale)
 
582
{
 
583
    Sample s = getRawSample();
 
584
 
 
585
    s.user = doScale(s.user, scale, s.cputotal);
 
586
    s.nice = doScale(s.nice, scale, s.cputotal);
 
587
    s.kernel = doScale(s.kernel, scale, s.cputotal);
 
588
 
 
589
    for (int i = 0; i < s.cpus; i++)
 
590
        s.smpbusy[i] = doScale(s.smpbusy[i], scale, s.smptotal[i]);
 
591
 
 
592
    s.cached = doScale(s.cached, scale, s.mtotal);
 
593
    s.buffers = doScale(s.buffers, scale, s.mtotal);
 
594
    s.used = doScale(s.used, scale, s.mtotal);
 
595
    makeMBytes(s.mtotal);
 
596
 
 
597
    s.sused = doScale(s.sused, scale, s.stotal);
 
598
    makeMBytes(s.stotal);
 
599
 
 
600
    s.pin *= scale;
 
601
    s.pout *= scale;
 
602
    unsigned page = (s.pin + s.pout) / 2;
 
603
 
 
604
    if (autoscale && page > 0 &&                // autoscale
 
605
        (page / pageScale > scale / 2 || page / pageScale < 1)) {
 
606
        pageScale = page / (scale/4);
 
607
    }
 
608
    s.pin = doScale(s.pin, 1, pageScale);
 
609
    s.pout = doScale(s.pout, 1, pageScale);
 
610
 
 
611
    s.swin *= scale;
 
612
    s.swout *= scale;
 
613
    unsigned swap = (s.swin + s.swout) / 2;
 
614
 
 
615
    if (autoscale && swap > 0 &&                // autoscale
 
616
        (swap / swapScale > scale / 2 || swap / swapScale < 1)) {
 
617
        swapScale = swap / (scale/4);
 
618
    }
 
619
    s.swin = doScale(s.swin, 1, swapScale);
 
620
    s.swout = doScale(s.swout, 1, swapScale);
 
621
 
 
622
    s.cswitches *= scale;
 
623
    if (autoscale && s.cswitches > 0 && // auto scale
 
624
        (s.cswitches / cxScale > scale || s.cswitches / cxScale < 2)) {
 
625
        cxScale = s.cswitches/(scale/2);
 
626
    }
 
627
    s.cswitches = doScale(s.cswitches, 1, cxScale);
 
628
 
 
629
    return s;
 
630
}
 
631