Commit b508cfda authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Linus Torvalds

[PATCH] use seq_lock for monotonic time

Monotonic clock code uses reader/writer lock which is prone to same
starvation problems as we saw with xtime.  This patch changes it to seq_lock
which is faster and won't starve writers in face of lots of readers.
parent 6a91801c
...@@ -39,7 +39,7 @@ static int delay_at_last_interrupt; ...@@ -39,7 +39,7 @@ static int delay_at_last_interrupt;
static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
static unsigned long last_tsc_high; /* msb 32 bits of Time Stamp Counter */ static unsigned long last_tsc_high; /* msb 32 bits of Time Stamp Counter */
static unsigned long long monotonic_base; static unsigned long long monotonic_base;
static rwlock_t monotonic_lock = RW_LOCK_UNLOCKED; static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
/* convert from cycles(64bits) => nanoseconds (64bits) /* convert from cycles(64bits) => nanoseconds (64bits)
* basic equation: * basic equation:
...@@ -111,12 +111,14 @@ static unsigned long get_offset_tsc(void) ...@@ -111,12 +111,14 @@ static unsigned long get_offset_tsc(void)
static unsigned long long monotonic_clock_tsc(void) static unsigned long long monotonic_clock_tsc(void)
{ {
unsigned long long last_offset, this_offset, base; unsigned long long last_offset, this_offset, base;
unsigned seq;
/* atomically read monotonic base & last_offset */ /* atomically read monotonic base & last_offset */
read_lock_irq(&monotonic_lock); do {
last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; seq = read_seqbegin(&monotonic_lock);
base = monotonic_base; last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
read_unlock_irq(&monotonic_lock); base = monotonic_base;
} while (read_seqretry(&monotonic_lock, seq));
/* Read the Time Stamp Counter */ /* Read the Time Stamp Counter */
rdtscll(this_offset); rdtscll(this_offset);
...@@ -135,7 +137,7 @@ static void mark_offset_tsc(void) ...@@ -135,7 +137,7 @@ static void mark_offset_tsc(void)
unsigned long long this_offset, last_offset; unsigned long long this_offset, last_offset;
static int lost_count = 0; static int lost_count = 0;
write_lock(&monotonic_lock); write_seqlock(&monotonic_lock);
last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
/* /*
* It is important that these two operations happen almost at * It is important that these two operations happen almost at
...@@ -204,7 +206,7 @@ static void mark_offset_tsc(void) ...@@ -204,7 +206,7 @@ static void mark_offset_tsc(void)
/* update the monotonic base value */ /* update the monotonic base value */
this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
monotonic_base += cycles_2_ns(this_offset - last_offset); monotonic_base += cycles_2_ns(this_offset - last_offset);
write_unlock(&monotonic_lock); write_sequnlock(&monotonic_lock);
/* calculate delay_at_last_interrupt */ /* calculate delay_at_last_interrupt */
count = ((LATCH-1) - count) * TICK_SIZE; count = ((LATCH-1) - count) * TICK_SIZE;
...@@ -236,7 +238,7 @@ static void mark_offset_tsc_hpet(void) ...@@ -236,7 +238,7 @@ static void mark_offset_tsc_hpet(void)
unsigned long long this_offset, last_offset; unsigned long long this_offset, last_offset;
unsigned long offset, temp, hpet_current; unsigned long offset, temp, hpet_current;
write_lock(&monotonic_lock); write_seqlock(&monotonic_lock);
last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
/* /*
* It is important that these two operations happen almost at * It is important that these two operations happen almost at
...@@ -264,7 +266,7 @@ static void mark_offset_tsc_hpet(void) ...@@ -264,7 +266,7 @@ static void mark_offset_tsc_hpet(void)
/* update the monotonic base value */ /* update the monotonic base value */
this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
monotonic_base += cycles_2_ns(this_offset - last_offset); monotonic_base += cycles_2_ns(this_offset - last_offset);
write_unlock(&monotonic_lock); write_sequnlock(&monotonic_lock);
/* calculate delay_at_last_interrupt */ /* calculate delay_at_last_interrupt */
/* /*
......
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