Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e98bbaaf authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

[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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -178,7 +178,7 @@ cputime64_to_clock_t(cputime64_t cputime)
}

struct s390_idle_data {
	spinlock_t lock;
	unsigned int sequence;
	unsigned long long idle_count;
	unsigned long long idle_enter;
	unsigned long long idle_time;
+19 −9
Original line number Diff line number Diff line
@@ -856,13 +856,20 @@ static ssize_t show_idle_count(struct sys_device *dev,
{
	struct s390_idle_data *idle;
	unsigned long long idle_count;
	unsigned int sequence;

	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;
	if (idle->idle_enter)
		idle_count++;
	spin_unlock(&idle->lock);
	smp_rmb();
	if (idle->sequence != sequence)
		goto repeat;
	return sprintf(buf, "%llu\n", idle_count);
}
static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL);
@@ -872,15 +879,22 @@ static ssize_t show_idle_time(struct sys_device *dev,
{
	struct s390_idle_data *idle;
	unsigned long long now, idle_time, idle_enter;
	unsigned int sequence;

	idle = &per_cpu(s390_idle, dev->id);
	spin_lock(&idle->lock);
	now = get_clock();
repeat:
	sequence = idle->sequence;
	smp_rmb();
	if (sequence & 1)
		goto repeat;
	idle_time = idle->idle_time;
	idle_enter = idle->idle_enter;
	if (idle_enter != 0ULL && idle_enter < now)
		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);
}
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,
	case CPU_ONLINE:
	case CPU_ONLINE_FROZEN:
		idle = &per_cpu(s390_idle, cpu);
		spin_lock_irq(&idle->lock);
		idle->idle_enter = 0;
		idle->idle_time = 0;
		idle->idle_count = 0;
		spin_unlock_irq(&idle->lock);
		memset(idle, 0, sizeof(struct s390_idle_data));
		if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
			return NOTIFY_BAD;
		break;
+15 −7
Original line number Diff line number Diff line
@@ -27,9 +27,7 @@

static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);

DEFINE_PER_CPU(struct s390_idle_data, s390_idle) = {
	.lock = __SPIN_LOCK_UNLOCKED(s390_idle.lock)
};
DEFINE_PER_CPU(struct s390_idle_data, s390_idle);

static inline __u64 get_vtimer(void)
{
@@ -151,11 +149,13 @@ void vtime_start_cpu(void)
		vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer;
	}

	spin_lock(&idle->lock);
	idle->sequence++;
	smp_wmb();
	idle->idle_time += idle_time;
	idle->idle_enter = 0ULL;
	idle->idle_count++;
	spin_unlock(&idle->lock);
	smp_wmb();
	idle->sequence++;
}

void vtime_stop_cpu(void)
@@ -242,15 +242,23 @@ cputime64_t s390_get_idle_time(int cpu)
{
	struct s390_idle_data *idle;
	unsigned long long now, idle_time, idle_enter;
	unsigned int sequence;

	idle = &per_cpu(s390_idle, cpu);
	spin_lock(&idle->lock);

	now = get_clock();
repeat:
	sequence = idle->sequence;
	smp_rmb();
	if (sequence & 1)
		goto repeat;
	idle_time = 0;
	idle_enter = idle->idle_enter;
	if (idle_enter != 0ULL && idle_enter < now)
		idle_time = now - idle_enter;
	spin_unlock(&idle->lock);
	smp_rmb();
	if (idle->sequence != sequence)
		goto repeat;
	return idle_time;
}