diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-22 06:08:20 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-22 06:08:23 -0400 |
commit | e98bbaafcd1c47d30f3245517fb585f1aaaca4db (patch) | |
tree | 8c8c88910db0197acc92bf1ddef999816f1a778b /arch/s390 | |
parent | 4f0076f77fb64889d4e5e425b63333e5764b446d (diff) |
[S390] lockless idle time accounting
Replace the spinlock used in the idle time accounting with a sequence
counter mechanism analog to seqlock.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/cputime.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 28 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 22 |
3 files changed, 35 insertions, 17 deletions
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index ec917d42ee6d..7a3817a656df 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h | |||
@@ -178,7 +178,7 @@ cputime64_to_clock_t(cputime64_t cputime) | |||
178 | } | 178 | } |
179 | 179 | ||
180 | struct s390_idle_data { | 180 | struct s390_idle_data { |
181 | spinlock_t lock; | 181 | unsigned int sequence; |
182 | unsigned long long idle_count; | 182 | unsigned long long idle_count; |
183 | unsigned long long idle_enter; | 183 | unsigned long long idle_enter; |
184 | unsigned long long idle_time; | 184 | unsigned long long idle_time; |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index fd8e3111a4e8..2270730f5354 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -856,13 +856,20 @@ static ssize_t show_idle_count(struct sys_device *dev, | |||
856 | { | 856 | { |
857 | struct s390_idle_data *idle; | 857 | struct s390_idle_data *idle; |
858 | unsigned long long idle_count; | 858 | unsigned long long idle_count; |
859 | unsigned int sequence; | ||
859 | 860 | ||
860 | idle = &per_cpu(s390_idle, dev->id); | 861 | idle = &per_cpu(s390_idle, dev->id); |
861 | spin_lock(&idle->lock); | 862 | repeat: |
863 | sequence = idle->sequence; | ||
864 | smp_rmb(); | ||
865 | if (sequence & 1) | ||
866 | goto repeat; | ||
862 | idle_count = idle->idle_count; | 867 | idle_count = idle->idle_count; |
863 | if (idle->idle_enter) | 868 | if (idle->idle_enter) |
864 | idle_count++; | 869 | idle_count++; |
865 | spin_unlock(&idle->lock); | 870 | smp_rmb(); |
871 | if (idle->sequence != sequence) | ||
872 | goto repeat; | ||
866 | return sprintf(buf, "%llu\n", idle_count); | 873 | return sprintf(buf, "%llu\n", idle_count); |
867 | } | 874 | } |
868 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); | 875 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); |
@@ -872,15 +879,22 @@ static ssize_t show_idle_time(struct sys_device *dev, | |||
872 | { | 879 | { |
873 | struct s390_idle_data *idle; | 880 | struct s390_idle_data *idle; |
874 | unsigned long long now, idle_time, idle_enter; | 881 | unsigned long long now, idle_time, idle_enter; |
882 | unsigned int sequence; | ||
875 | 883 | ||
876 | idle = &per_cpu(s390_idle, dev->id); | 884 | idle = &per_cpu(s390_idle, dev->id); |
877 | spin_lock(&idle->lock); | ||
878 | now = get_clock(); | 885 | now = get_clock(); |
886 | repeat: | ||
887 | sequence = idle->sequence; | ||
888 | smp_rmb(); | ||
889 | if (sequence & 1) | ||
890 | goto repeat; | ||
879 | idle_time = idle->idle_time; | 891 | idle_time = idle->idle_time; |
880 | idle_enter = idle->idle_enter; | 892 | idle_enter = idle->idle_enter; |
881 | if (idle_enter != 0ULL && idle_enter < now) | 893 | if (idle_enter != 0ULL && idle_enter < now) |
882 | idle_time += now - idle_enter; | 894 | idle_time += now - idle_enter; |
883 | spin_unlock(&idle->lock); | 895 | smp_rmb(); |
896 | if (idle->sequence != sequence) | ||
897 | goto repeat; | ||
884 | return sprintf(buf, "%llu\n", idle_time >> 12); | 898 | return sprintf(buf, "%llu\n", idle_time >> 12); |
885 | } | 899 | } |
886 | static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); | 900 | static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); |
@@ -908,11 +922,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, | |||
908 | case CPU_ONLINE: | 922 | case CPU_ONLINE: |
909 | case CPU_ONLINE_FROZEN: | 923 | case CPU_ONLINE_FROZEN: |
910 | idle = &per_cpu(s390_idle, cpu); | 924 | idle = &per_cpu(s390_idle, cpu); |
911 | spin_lock_irq(&idle->lock); | 925 | memset(idle, 0, sizeof(struct s390_idle_data)); |
912 | idle->idle_enter = 0; | ||
913 | idle->idle_time = 0; | ||
914 | idle->idle_count = 0; | ||
915 | spin_unlock_irq(&idle->lock); | ||
916 | if (sysfs_create_group(&s->kobj, &cpu_online_attr_group)) | 926 | if (sysfs_create_group(&s->kobj, &cpu_online_attr_group)) |
917 | return NOTIFY_BAD; | 927 | return NOTIFY_BAD; |
918 | break; | 928 | break; |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index ade17e771f05..c41bb0d416e1 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -27,9 +27,7 @@ | |||
27 | 27 | ||
28 | static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); | 28 | static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); |
29 | 29 | ||
30 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle) = { | 30 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle); |
31 | .lock = __SPIN_LOCK_UNLOCKED(s390_idle.lock) | ||
32 | }; | ||
33 | 31 | ||
34 | static inline __u64 get_vtimer(void) | 32 | static inline __u64 get_vtimer(void) |
35 | { | 33 | { |
@@ -151,11 +149,13 @@ void vtime_start_cpu(void) | |||
151 | vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; | 149 | vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; |
152 | } | 150 | } |
153 | 151 | ||
154 | spin_lock(&idle->lock); | 152 | idle->sequence++; |
153 | smp_wmb(); | ||
155 | idle->idle_time += idle_time; | 154 | idle->idle_time += idle_time; |
156 | idle->idle_enter = 0ULL; | 155 | idle->idle_enter = 0ULL; |
157 | idle->idle_count++; | 156 | idle->idle_count++; |
158 | spin_unlock(&idle->lock); | 157 | smp_wmb(); |
158 | idle->sequence++; | ||
159 | } | 159 | } |
160 | 160 | ||
161 | void vtime_stop_cpu(void) | 161 | void vtime_stop_cpu(void) |
@@ -242,15 +242,23 @@ cputime64_t s390_get_idle_time(int cpu) | |||
242 | { | 242 | { |
243 | struct s390_idle_data *idle; | 243 | struct s390_idle_data *idle; |
244 | unsigned long long now, idle_time, idle_enter; | 244 | unsigned long long now, idle_time, idle_enter; |
245 | unsigned int sequence; | ||
245 | 246 | ||
246 | idle = &per_cpu(s390_idle, cpu); | 247 | idle = &per_cpu(s390_idle, cpu); |
247 | spin_lock(&idle->lock); | 248 | |
248 | now = get_clock(); | 249 | now = get_clock(); |
250 | repeat: | ||
251 | sequence = idle->sequence; | ||
252 | smp_rmb(); | ||
253 | if (sequence & 1) | ||
254 | goto repeat; | ||
249 | idle_time = 0; | 255 | idle_time = 0; |
250 | idle_enter = idle->idle_enter; | 256 | idle_enter = idle->idle_enter; |
251 | if (idle_enter != 0ULL && idle_enter < now) | 257 | if (idle_enter != 0ULL && idle_enter < now) |
252 | idle_time = now - idle_enter; | 258 | idle_time = now - idle_enter; |
253 | spin_unlock(&idle->lock); | 259 | smp_rmb(); |
260 | if (idle->sequence != sequence) | ||
261 | goto repeat; | ||
254 | return idle_time; | 262 | return idle_time; |
255 | } | 263 | } |
256 | 264 | ||