diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2007-10-22 06:52:39 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-10-22 06:52:47 -0400 |
commit | fae8b22d3e3e3a3d317a7746493997af02a3f35c (patch) | |
tree | 871aa91c51d713d7842ba1eb8661bde54d102842 /arch/s390/kernel | |
parent | 32346f47dd46bed291464e194a6c47da6fdd1bc3 (diff) |
[S390] Add per-cpu idle time / idle count sysfs attributes.
Add two new sysfs entries per cpu: idle_count and idle_time.
idle_count contains the number of times a cpu went into idle state.
idle_time contains the time a cpu spent in idle state in microseconds.
This can be used e.g. by powertop to tell how often idle state is
entered and left.
# cat /sys/devices/system/cpu/cpu0/idle_count
504
# cat /sys/devices/system/cpu/cpu0/idle_time
469734037 us
Cc: Arjan van de Ven <arjan@infradead.org>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/process.c | 16 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 63 |
2 files changed, 76 insertions, 3 deletions
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 70c57378f426..cc7c4ba0774d 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <asm/processor.h> | 44 | #include <asm/processor.h> |
45 | #include <asm/irq.h> | 45 | #include <asm/irq.h> |
46 | #include <asm/timer.h> | 46 | #include <asm/timer.h> |
47 | #include <asm/cpu.h> | ||
47 | 48 | ||
48 | asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); | 49 | asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); |
49 | 50 | ||
@@ -91,6 +92,14 @@ EXPORT_SYMBOL(unregister_idle_notifier); | |||
91 | 92 | ||
92 | void do_monitor_call(struct pt_regs *regs, long interruption_code) | 93 | void do_monitor_call(struct pt_regs *regs, long interruption_code) |
93 | { | 94 | { |
95 | struct s390_idle_data *idle; | ||
96 | |||
97 | idle = &__get_cpu_var(s390_idle); | ||
98 | spin_lock(&idle->lock); | ||
99 | idle->idle_time += get_clock() - idle->idle_enter; | ||
100 | idle->in_idle = 0; | ||
101 | spin_unlock(&idle->lock); | ||
102 | |||
94 | /* disable monitor call class 0 */ | 103 | /* disable monitor call class 0 */ |
95 | __ctl_clear_bit(8, 15); | 104 | __ctl_clear_bit(8, 15); |
96 | 105 | ||
@@ -105,6 +114,7 @@ extern void s390_handle_mcck(void); | |||
105 | static void default_idle(void) | 114 | static void default_idle(void) |
106 | { | 115 | { |
107 | int cpu, rc; | 116 | int cpu, rc; |
117 | struct s390_idle_data *idle; | ||
108 | 118 | ||
109 | /* CPU is going idle. */ | 119 | /* CPU is going idle. */ |
110 | cpu = smp_processor_id(); | 120 | cpu = smp_processor_id(); |
@@ -142,6 +152,12 @@ static void default_idle(void) | |||
142 | return; | 152 | return; |
143 | } | 153 | } |
144 | 154 | ||
155 | idle = &__get_cpu_var(s390_idle); | ||
156 | spin_lock(&idle->lock); | ||
157 | idle->idle_count++; | ||
158 | idle->in_idle = 1; | ||
159 | idle->idle_enter = get_clock(); | ||
160 | spin_unlock(&idle->lock); | ||
145 | trace_hardirqs_on(); | 161 | trace_hardirqs_on(); |
146 | /* Wait for external, I/O or machine check interrupt. */ | 162 | /* Wait for external, I/O or machine check interrupt. */ |
147 | __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | | 163 | __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 35edbef1d222..ba3fff06fad1 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/tlbflush.h> | 42 | #include <asm/tlbflush.h> |
43 | #include <asm/timer.h> | 43 | #include <asm/timer.h> |
44 | #include <asm/lowcore.h> | 44 | #include <asm/lowcore.h> |
45 | #include <asm/cpu.h> | ||
45 | 46 | ||
46 | /* | 47 | /* |
47 | * An array with a pointer the lowcore of every CPU. | 48 | * An array with a pointer the lowcore of every CPU. |
@@ -494,6 +495,8 @@ int __cpuinit start_secondary(void *cpuvoid) | |||
494 | return 0; | 495 | return 0; |
495 | } | 496 | } |
496 | 497 | ||
498 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle); | ||
499 | |||
497 | static void __init smp_create_idle(unsigned int cpu) | 500 | static void __init smp_create_idle(unsigned int cpu) |
498 | { | 501 | { |
499 | struct task_struct *p; | 502 | struct task_struct *p; |
@@ -506,6 +509,7 @@ static void __init smp_create_idle(unsigned int cpu) | |||
506 | if (IS_ERR(p)) | 509 | if (IS_ERR(p)) |
507 | panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); | 510 | panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); |
508 | current_set[cpu] = p; | 511 | current_set[cpu] = p; |
512 | spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock); | ||
509 | } | 513 | } |
510 | 514 | ||
511 | static int cpu_stopped(int cpu) | 515 | static int cpu_stopped(int cpu) |
@@ -724,6 +728,7 @@ void __init smp_prepare_boot_cpu(void) | |||
724 | cpu_set(0, cpu_online_map); | 728 | cpu_set(0, cpu_online_map); |
725 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 729 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
726 | current_set[0] = current; | 730 | current_set[0] = current; |
731 | spin_lock_init(&(&__get_cpu_var(s390_idle))->lock); | ||
727 | } | 732 | } |
728 | 733 | ||
729 | void __init smp_cpus_done(unsigned int max_cpus) | 734 | void __init smp_cpus_done(unsigned int max_cpus) |
@@ -756,22 +761,71 @@ static ssize_t show_capability(struct sys_device *dev, char *buf) | |||
756 | } | 761 | } |
757 | static SYSDEV_ATTR(capability, 0444, show_capability, NULL); | 762 | static SYSDEV_ATTR(capability, 0444, show_capability, NULL); |
758 | 763 | ||
764 | static ssize_t show_idle_count(struct sys_device *dev, char *buf) | ||
765 | { | ||
766 | struct s390_idle_data *idle; | ||
767 | unsigned long long idle_count; | ||
768 | |||
769 | idle = &per_cpu(s390_idle, dev->id); | ||
770 | spin_lock_irq(&idle->lock); | ||
771 | idle_count = idle->idle_count; | ||
772 | spin_unlock_irq(&idle->lock); | ||
773 | return sprintf(buf, "%llu\n", idle_count); | ||
774 | } | ||
775 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); | ||
776 | |||
777 | static ssize_t show_idle_time(struct sys_device *dev, char *buf) | ||
778 | { | ||
779 | struct s390_idle_data *idle; | ||
780 | unsigned long long new_time; | ||
781 | |||
782 | idle = &per_cpu(s390_idle, dev->id); | ||
783 | spin_lock_irq(&idle->lock); | ||
784 | if (idle->in_idle) { | ||
785 | new_time = get_clock(); | ||
786 | idle->idle_time += new_time - idle->idle_enter; | ||
787 | idle->idle_enter = new_time; | ||
788 | } | ||
789 | new_time = idle->idle_time; | ||
790 | spin_unlock_irq(&idle->lock); | ||
791 | return sprintf(buf, "%llu us\n", new_time >> 12); | ||
792 | } | ||
793 | static SYSDEV_ATTR(idle_time, 0444, show_idle_time, NULL); | ||
794 | |||
795 | static struct attribute *cpu_attrs[] = { | ||
796 | &attr_capability.attr, | ||
797 | &attr_idle_count.attr, | ||
798 | &attr_idle_time.attr, | ||
799 | NULL, | ||
800 | }; | ||
801 | |||
802 | static struct attribute_group cpu_attr_group = { | ||
803 | .attrs = cpu_attrs, | ||
804 | }; | ||
805 | |||
759 | static int __cpuinit smp_cpu_notify(struct notifier_block *self, | 806 | static int __cpuinit smp_cpu_notify(struct notifier_block *self, |
760 | unsigned long action, void *hcpu) | 807 | unsigned long action, void *hcpu) |
761 | { | 808 | { |
762 | unsigned int cpu = (unsigned int)(long)hcpu; | 809 | unsigned int cpu = (unsigned int)(long)hcpu; |
763 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 810 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
764 | struct sys_device *s = &c->sysdev; | 811 | struct sys_device *s = &c->sysdev; |
812 | struct s390_idle_data *idle; | ||
765 | 813 | ||
766 | switch (action) { | 814 | switch (action) { |
767 | case CPU_ONLINE: | 815 | case CPU_ONLINE: |
768 | case CPU_ONLINE_FROZEN: | 816 | case CPU_ONLINE_FROZEN: |
769 | if (sysdev_create_file(s, &attr_capability)) | 817 | idle = &per_cpu(s390_idle, cpu); |
818 | spin_lock_irq(&idle->lock); | ||
819 | idle->idle_enter = 0; | ||
820 | idle->idle_time = 0; | ||
821 | idle->idle_count = 0; | ||
822 | spin_unlock_irq(&idle->lock); | ||
823 | if (sysfs_create_group(&s->kobj, &cpu_attr_group)) | ||
770 | return NOTIFY_BAD; | 824 | return NOTIFY_BAD; |
771 | break; | 825 | break; |
772 | case CPU_DEAD: | 826 | case CPU_DEAD: |
773 | case CPU_DEAD_FROZEN: | 827 | case CPU_DEAD_FROZEN: |
774 | sysdev_remove_file(s, &attr_capability); | 828 | sysfs_remove_group(&s->kobj, &cpu_attr_group); |
775 | break; | 829 | break; |
776 | } | 830 | } |
777 | return NOTIFY_OK; | 831 | return NOTIFY_OK; |
@@ -784,6 +838,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = { | |||
784 | static int __init topology_init(void) | 838 | static int __init topology_init(void) |
785 | { | 839 | { |
786 | int cpu; | 840 | int cpu; |
841 | int rc; | ||
787 | 842 | ||
788 | register_cpu_notifier(&smp_cpu_nb); | 843 | register_cpu_notifier(&smp_cpu_nb); |
789 | 844 | ||
@@ -796,7 +851,9 @@ static int __init topology_init(void) | |||
796 | if (!cpu_online(cpu)) | 851 | if (!cpu_online(cpu)) |
797 | continue; | 852 | continue; |
798 | s = &c->sysdev; | 853 | s = &c->sysdev; |
799 | sysdev_create_file(s, &attr_capability); | 854 | rc = sysfs_create_group(&s->kobj, &cpu_attr_group); |
855 | if (rc) | ||
856 | return rc; | ||
800 | } | 857 | } |
801 | return 0; | 858 | return 0; |
802 | } | 859 | } |