stat.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/cpumask.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/interrupt.h>
  6. #include <linux/kernel_stat.h>
  7. #include <linux/proc_fs.h>
  8. #include <linux/sched.h>
  9. #include <linux/sched/stat.h>
  10. #include <linux/seq_file.h>
  11. #include <linux/slab.h>
  12. #include <linux/time.h>
  13. #include <linux/time_namespace.h>
  14. #include <linux/irqnr.h>
  15. #include <linux/sched/cputime.h>
  16. #include <linux/tick.h>
  17. #ifndef arch_irq_stat_cpu
  18. #define arch_irq_stat_cpu(cpu) 0
  19. #endif
  20. #ifndef arch_irq_stat
  21. #define arch_irq_stat() 0
  22. #endif
  23. u64 get_idle_time(struct kernel_cpustat *kcs, int cpu)
  24. {
  25. u64 idle, idle_usecs = -1ULL;
  26. if (cpu_online(cpu))
  27. idle_usecs = get_cpu_idle_time_us(cpu, NULL);
  28. if (idle_usecs == -1ULL)
  29. /* !NO_HZ or cpu offline so we can rely on cpustat.idle */
  30. idle = kcs->cpustat[CPUTIME_IDLE];
  31. else
  32. idle = idle_usecs * NSEC_PER_USEC;
  33. return idle;
  34. }
  35. static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu)
  36. {
  37. u64 iowait, iowait_usecs = -1ULL;
  38. if (cpu_online(cpu))
  39. iowait_usecs = get_cpu_iowait_time_us(cpu, NULL);
  40. if (iowait_usecs == -1ULL)
  41. /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
  42. iowait = kcs->cpustat[CPUTIME_IOWAIT];
  43. else
  44. iowait = iowait_usecs * NSEC_PER_USEC;
  45. return iowait;
  46. }
  47. static void show_irq_gap(struct seq_file *p, unsigned int gap)
  48. {
  49. static const char zeros[] = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0";
  50. while (gap > 0) {
  51. unsigned int inc;
  52. inc = min_t(unsigned int, gap, ARRAY_SIZE(zeros) / 2);
  53. seq_write(p, zeros, 2 * inc);
  54. gap -= inc;
  55. }
  56. }
  57. static void show_all_irqs(struct seq_file *p)
  58. {
  59. unsigned int i, next = 0;
  60. for_each_active_irq(i) {
  61. show_irq_gap(p, i - next);
  62. seq_put_decimal_ull(p, " ", kstat_irqs_usr(i));
  63. next = i + 1;
  64. }
  65. show_irq_gap(p, irq_get_nr_irqs() - next);
  66. }
  67. static int show_stat(struct seq_file *p, void *v)
  68. {
  69. int i, j;
  70. u64 user, nice, system, idle, iowait, irq, softirq, steal;
  71. u64 guest, guest_nice;
  72. u64 sum = 0;
  73. u64 sum_softirq = 0;
  74. unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
  75. struct timespec64 boottime;
  76. user = nice = system = idle = iowait =
  77. irq = softirq = steal = 0;
  78. guest = guest_nice = 0;
  79. getboottime64(&boottime);
  80. /* shift boot timestamp according to the timens offset */
  81. timens_sub_boottime(&boottime);
  82. for_each_possible_cpu(i) {
  83. struct kernel_cpustat kcpustat;
  84. u64 *cpustat = kcpustat.cpustat;
  85. kcpustat_cpu_fetch(&kcpustat, i);
  86. user += cpustat[CPUTIME_USER];
  87. nice += cpustat[CPUTIME_NICE];
  88. system += cpustat[CPUTIME_SYSTEM];
  89. idle += get_idle_time(&kcpustat, i);
  90. iowait += get_iowait_time(&kcpustat, i);
  91. irq += cpustat[CPUTIME_IRQ];
  92. softirq += cpustat[CPUTIME_SOFTIRQ];
  93. steal += cpustat[CPUTIME_STEAL];
  94. guest += cpustat[CPUTIME_GUEST];
  95. guest_nice += cpustat[CPUTIME_GUEST_NICE];
  96. sum += kstat_cpu_irqs_sum(i);
  97. sum += arch_irq_stat_cpu(i);
  98. for (j = 0; j < NR_SOFTIRQS; j++) {
  99. unsigned int softirq_stat = kstat_softirqs_cpu(j, i);
  100. per_softirq_sums[j] += softirq_stat;
  101. sum_softirq += softirq_stat;
  102. }
  103. }
  104. sum += arch_irq_stat();
  105. seq_put_decimal_ull(p, "cpu ", nsec_to_clock_t(user));
  106. seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
  107. seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
  108. seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
  109. seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
  110. seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
  111. seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
  112. seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
  113. seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
  114. seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
  115. seq_putc(p, '\n');
  116. for_each_online_cpu(i) {
  117. struct kernel_cpustat kcpustat;
  118. u64 *cpustat = kcpustat.cpustat;
  119. kcpustat_cpu_fetch(&kcpustat, i);
  120. /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
  121. user = cpustat[CPUTIME_USER];
  122. nice = cpustat[CPUTIME_NICE];
  123. system = cpustat[CPUTIME_SYSTEM];
  124. idle = get_idle_time(&kcpustat, i);
  125. iowait = get_iowait_time(&kcpustat, i);
  126. irq = cpustat[CPUTIME_IRQ];
  127. softirq = cpustat[CPUTIME_SOFTIRQ];
  128. steal = cpustat[CPUTIME_STEAL];
  129. guest = cpustat[CPUTIME_GUEST];
  130. guest_nice = cpustat[CPUTIME_GUEST_NICE];
  131. seq_printf(p, "cpu%d", i);
  132. seq_put_decimal_ull(p, " ", nsec_to_clock_t(user));
  133. seq_put_decimal_ull(p, " ", nsec_to_clock_t(nice));
  134. seq_put_decimal_ull(p, " ", nsec_to_clock_t(system));
  135. seq_put_decimal_ull(p, " ", nsec_to_clock_t(idle));
  136. seq_put_decimal_ull(p, " ", nsec_to_clock_t(iowait));
  137. seq_put_decimal_ull(p, " ", nsec_to_clock_t(irq));
  138. seq_put_decimal_ull(p, " ", nsec_to_clock_t(softirq));
  139. seq_put_decimal_ull(p, " ", nsec_to_clock_t(steal));
  140. seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest));
  141. seq_put_decimal_ull(p, " ", nsec_to_clock_t(guest_nice));
  142. seq_putc(p, '\n');
  143. }
  144. seq_put_decimal_ull(p, "intr ", (unsigned long long)sum);
  145. show_all_irqs(p);
  146. seq_printf(p,
  147. "\nctxt %llu\n"
  148. "btime %llu\n"
  149. "processes %lu\n"
  150. "procs_running %u\n"
  151. "procs_blocked %u\n",
  152. nr_context_switches(),
  153. (unsigned long long)boottime.tv_sec,
  154. total_forks,
  155. nr_running(),
  156. nr_iowait());
  157. seq_put_decimal_ull(p, "softirq ", (unsigned long long)sum_softirq);
  158. for (i = 0; i < NR_SOFTIRQS; i++)
  159. seq_put_decimal_ull(p, " ", per_softirq_sums[i]);
  160. seq_putc(p, '\n');
  161. return 0;
  162. }
  163. static int stat_open(struct inode *inode, struct file *file)
  164. {
  165. unsigned int size = 1024 + 128 * num_online_cpus();
  166. /* minimum size to display an interrupt count : 2 bytes */
  167. size += 2 * irq_get_nr_irqs();
  168. return single_open_size(file, show_stat, NULL, size);
  169. }
  170. static const struct proc_ops stat_proc_ops = {
  171. .proc_flags = PROC_ENTRY_PERMANENT,
  172. .proc_open = stat_open,
  173. .proc_read_iter = seq_read_iter,
  174. .proc_lseek = seq_lseek,
  175. .proc_release = single_release,
  176. };
  177. static int __init proc_stat_init(void)
  178. {
  179. proc_create("stat", 0, NULL, &stat_proc_ops);
  180. return 0;
  181. }
  182. fs_initcall(proc_stat_init);