Commit e98bbaaf authored by Martin Schwidefsky's avatar Martin Schwidefsky

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 4f0076f7
...@@ -178,7 +178,7 @@ cputime64_to_clock_t(cputime64_t cputime) ...@@ -178,7 +178,7 @@ cputime64_to_clock_t(cputime64_t cputime)
} }
struct s390_idle_data { struct s390_idle_data {
spinlock_t lock; unsigned int sequence;
unsigned long long idle_count; unsigned long long idle_count;
unsigned long long idle_enter; unsigned long long idle_enter;
unsigned long long idle_time; unsigned long long idle_time;
......
...@@ -856,13 +856,20 @@ static ssize_t show_idle_count(struct sys_device *dev, ...@@ -856,13 +856,20 @@ static ssize_t show_idle_count(struct sys_device *dev,
{ {
struct s390_idle_data *idle; struct s390_idle_data *idle;
unsigned long long idle_count; unsigned long long idle_count;
unsigned int sequence;
idle = &per_cpu(s390_idle, dev->id); idle = &per_cpu(s390_idle, dev->id);
spin_lock(&idle->lock); repeat:
sequence = idle->sequence;
smp_rmb();
if (sequence & 1)
goto repeat;
idle_count = idle->idle_count; idle_count = idle->idle_count;
if (idle->idle_enter) if (idle->idle_enter)
idle_count++; idle_count++;
spin_unlock(&idle->lock); smp_rmb();
if (idle->sequence != sequence)
goto repeat;
return sprintf(buf, "%llu\n", idle_count); return sprintf(buf, "%llu\n", idle_count);
} }
static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); 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,15 +879,22 @@ static ssize_t show_idle_time(struct sys_device *dev,
{ {
struct s390_idle_data *idle; struct s390_idle_data *idle;
unsigned long long now, idle_time, idle_enter; unsigned long long now, idle_time, idle_enter;
unsigned int sequence;
idle = &per_cpu(s390_idle, dev->id); idle = &per_cpu(s390_idle, dev->id);
spin_lock(&idle->lock);
now = get_clock(); now = get_clock();
repeat:
sequence = idle->sequence;
smp_rmb();
if (sequence & 1)
goto repeat;
idle_time = idle->idle_time; idle_time = idle->idle_time;
idle_enter = idle->idle_enter; idle_enter = idle->idle_enter;
if (idle_enter != 0ULL && idle_enter < now) if (idle_enter != 0ULL && idle_enter < now)
idle_time += now - idle_enter; idle_time += now - idle_enter;
spin_unlock(&idle->lock); smp_rmb();
if (idle->sequence != sequence)
goto repeat;
return sprintf(buf, "%llu\n", idle_time >> 12); return sprintf(buf, "%llu\n", idle_time >> 12);
} }
static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); 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,11 +922,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
case CPU_ONLINE: case CPU_ONLINE:
case CPU_ONLINE_FROZEN: case CPU_ONLINE_FROZEN:
idle = &per_cpu(s390_idle, cpu); idle = &per_cpu(s390_idle, cpu);
spin_lock_irq(&idle->lock); memset(idle, 0, sizeof(struct s390_idle_data));
idle->idle_enter = 0;
idle->idle_time = 0;
idle->idle_count = 0;
spin_unlock_irq(&idle->lock);
if (sysfs_create_group(&s->kobj, &cpu_online_attr_group)) if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
return NOTIFY_BAD; return NOTIFY_BAD;
break; break;
......
...@@ -27,9 +27,7 @@ ...@@ -27,9 +27,7 @@
static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
DEFINE_PER_CPU(struct s390_idle_data, s390_idle) = { DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
.lock = __SPIN_LOCK_UNLOCKED(s390_idle.lock)
};
static inline __u64 get_vtimer(void) static inline __u64 get_vtimer(void)
{ {
...@@ -151,11 +149,13 @@ void vtime_start_cpu(void) ...@@ -151,11 +149,13 @@ void vtime_start_cpu(void)
vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer;
} }
spin_lock(&idle->lock); idle->sequence++;
smp_wmb();
idle->idle_time += idle_time; idle->idle_time += idle_time;
idle->idle_enter = 0ULL; idle->idle_enter = 0ULL;
idle->idle_count++; idle->idle_count++;
spin_unlock(&idle->lock); smp_wmb();
idle->sequence++;
} }
void vtime_stop_cpu(void) void vtime_stop_cpu(void)
...@@ -242,15 +242,23 @@ cputime64_t s390_get_idle_time(int cpu) ...@@ -242,15 +242,23 @@ cputime64_t s390_get_idle_time(int cpu)
{ {
struct s390_idle_data *idle; struct s390_idle_data *idle;
unsigned long long now, idle_time, idle_enter; unsigned long long now, idle_time, idle_enter;
unsigned int sequence;
idle = &per_cpu(s390_idle, cpu); idle = &per_cpu(s390_idle, cpu);
spin_lock(&idle->lock);
now = get_clock(); now = get_clock();
repeat:
sequence = idle->sequence;
smp_rmb();
if (sequence & 1)
goto repeat;
idle_time = 0; idle_time = 0;
idle_enter = idle->idle_enter; idle_enter = idle->idle_enter;
if (idle_enter != 0ULL && idle_enter < now) if (idle_enter != 0ULL && idle_enter < now)
idle_time = now - idle_enter; idle_time = now - idle_enter;
spin_unlock(&idle->lock); smp_rmb();
if (idle->sequence != sequence)
goto repeat;
return idle_time; return idle_time;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment