What are the meanings of each field in /proc/stat file?
Some documents said that each field represented in jiffies, but actually it isn’t. It was true on kernel 2.4, but no more in kernel 2.6. We can easily see the meaning of each field at the kernel source.
http://lxr.linux.no/linux+v2.6.27.10/fs/proc/proc_misc.c
static int show_stat(struct seq_file *p, void *v) 504{ 505 int i; 506 unsigned long jif; 507 cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; 508 cputime64_t guest; 509 u64 sum = 0; 510 struct timespec boottime; 511 unsigned int *per_irq_sum; 512 513 per_irq_sum = kzalloc(sizeof(unsigned int)*NR_IRQS, GFP_KERNEL); 514 if (!per_irq_sum) 515 return -ENOMEM; 516 517 user = nice = system = idle = iowait = 518 irq = softirq = steal = cputime64_zero; 519 guest = cputime64_zero; 520 getboottime(&boottime); 521 jif = boottime.tv_sec; 522 523 for_each_possible_cpu(i) { 524 int j; 525 526 user = cputime64_add(user, kstat_cpu(i).cpustat.user); 527 nice = cputime64_add(nice, kstat_cpu(i).cpustat.nice); 528 system = cputime64_add(system, kstat_cpu(i).cpustat.system); 529 idle = cputime64_add(idle, kstat_cpu(i).cpustat.idle); 530 iowait = cputime64_add(iowait, kstat_cpu(i).cpustat.iowait); 531 irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq); 532 softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); 533 steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); 534 guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); 535 for (j = 0; j < NR_IRQS; j++) { 536 unsigned int temp = kstat_cpu(i).irqs[j]; 537 sum += temp; 538 per_irq_sum[j] += temp; 539 } 540 sum += arch_irq_stat_cpu(i); 541 } 542 sum += arch_irq_stat(); 543 544 seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llun", 545 (unsigned long long)cputime64_to_clock_t(user), 546 (unsigned long long)cputime64_to_clock_t(nice), 547 (unsigned long long)cputime64_to_clock_t(system), 548 (unsigned long long)cputime64_to_clock_t(idle), 549 (unsigned long long)cputime64_to_clock_t(iowait), 550 (unsigned long long)cputime64_to_clock_t(irq), 551 (unsigned long long)cputime64_to_clock_t(softirq), 552 (unsigned long long)cputime64_to_clock_t(steal), 553 (unsigned long long)cputime64_to_clock_t(guest)); 554 for_each_online_cpu(i) { 555 556 /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ 557 user = kstat_cpu(i).cpustat.user; 558 nice = kstat_cpu(i).cpustat.nice; 559 system = kstat_cpu(i).cpustat.system; 560 idle = kstat_cpu(i).cpustat.idle; 561 iowait = kstat_cpu(i).cpustat.iowait; 562 irq = kstat_cpu(i).cpustat.irq; 563 softirq = kstat_cpu(i).cpustat.softirq; 564 steal = kstat_cpu(i).cpustat.steal; 565 guest = kstat_cpu(i).cpustat.guest; 566 seq_printf(p, 567 "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llun", 568 i, 569 (unsigned long long)cputime64_to_clock_t(user), 570 (unsigned long long)cputime64_to_clock_t(nice), 571 (unsigned long long)cputime64_to_clock_t(system), 572 (unsigned long long)cputime64_to_clock_t(idle), 573 (unsigned long long)cputime64_to_clock_t(iowait), 574 (unsigned long long)cputime64_to_clock_t(irq), 575 (unsigned long long)cputime64_to_clock_t(softirq), 576 (unsigned long long)cputime64_to_clock_t(steal), 577 (unsigned long long)cputime64_to_clock_t(guest)); 578 } 579 seq_printf(p, "intr %llu", (unsigned long long)sum); 580 581 for (i = 0; i < NR_IRQS; i++) 582 seq_printf(p, " %u", per_irq_sum[i]); 583 584 seq_printf(p, 585 "nctxt %llun" 586 "btime %lun" 587 "processes %lun" 588 "procs_running %lun" 589 "procs_blocked %lun", 590 nr_context_switches(), 591 (unsigned long)jif, 592 total_forks, 593 nr_running(), 594 nr_iowait()); 595 596 kfree(per_irq_sum); 597 return 0; 598}
From line 544 to 553, you can see the meaning of each field.
One little strange part is that the value which is calculated during the timer interrupt is converted to clock_t type using cputime64_to_clock_t() macro.
http://lxr.linux.no/linux+v2.6.27.10/include/asm-generic/cputime.h#L67
/* 65 * Convert cputime64 to clock. 66 */ 67#define cputime64_to_clock_t(__ct) jiffies_64_to_clock_t(__ct) 68
http://lxr.linux.no/linux+v2.6.27.10/kernel/time.c#L618
618u64 jiffies_64_to_clock_t(u64 x) 619{ 620#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 621# if HZ USER_HZ 624 x = div_u64(x, HZ / USER_HZ); 625# else 626 /* Nothing to do */ 627# endif 628#else 629 /* 630 * There are better ways that don't overflow early, 631 * but even this doesn't overflow in hundreds of years 632 * in 64 bits, so.. 633 */ 634 x = div_u64(x * TICK_NSEC, (NSEC_PER_SEC / USER_HZ)); 635#endif 636 return x; 637} 638EXPORT_SYMBOL(jiffies_64_to_clock_t);
At the end, the internal jiffies value divided by difference between HZ and USER_HZ. The USER_HZ is 100. If HZ is 1000, internal jiffies value will be divided by 10. It means that we see the same result among 2.4 and 2.6, but it does not mean that those values just come from jiffies.
If we want to see the values in seconds, we can divide the value by CLOCKS_PER_SEC macro which is defined in time.h.
Leave a Reply