Commit 4c746d40 authored by Anton Blanchard's avatar Anton Blanchard Committed by Linus Torvalds

[PATCH] Using get_cycles for add_timer_randomness

I tested how long it took to do a dd from /dev/random on ppc64 before and
after this patch, while doing a ping flood from another machine.

before:
# /usr/bin/time dd if=/dev/random of=/dev/zero count=1k
0+51 records in
Command terminated by signal 2
0.00user 0.00system 19:18.46elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k

I gave up after 19 minutes.

after:
# /usr/bin/time dd if=/dev/random of=/dev/zero count=1k
0+1024 records in
0.00user 0.00system 0:33.38elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k

Just over 33 seconds. Better.

From: Arnd Bergmann <arnd@arndb.de>

I noticed that only i386 and x86-64 are currently using a high resolution
timer source when adding randomness.  Since many architectures have a
working get_cycles() implementation, it seems rather straightforward to use
that.

Has this been discussed before, or can anyone comment on the implementation
below?

This patch attempts to take into account the size of cycles_t, which is
either 32 or 64 bits wide but independent of the architecture's word size.

The behavior should be nearly identical to the old one on i386, x86-64 and
all architectures without a time stamp counter, while finding more entropy
on the other architectures.
Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 60b292ca
...@@ -781,8 +781,8 @@ static void batch_entropy_process(void *private_) ...@@ -781,8 +781,8 @@ static void batch_entropy_process(void *private_)
/* There is one of these per entropy source */ /* There is one of these per entropy source */
struct timer_rand_state { struct timer_rand_state {
__u32 last_time; cycles_t last_time;
__s32 last_delta,last_delta2; long last_delta,last_delta2;
unsigned dont_count_entropy:1; unsigned dont_count_entropy:1;
}; };
...@@ -799,14 +799,12 @@ static struct timer_rand_state *irq_timer_state[NR_IRQS]; ...@@ -799,14 +799,12 @@ static struct timer_rand_state *irq_timer_state[NR_IRQS];
* The number "num" is also added to the pool - it should somehow describe * The number "num" is also added to the pool - it should somehow describe
* the type of event which just happened. This is currently 0-255 for * the type of event which just happened. This is currently 0-255 for
* keyboard scan codes, and 256 upwards for interrupts. * keyboard scan codes, and 256 upwards for interrupts.
* On the i386, this is assumed to be at most 16 bits, and the high bits
* are used for a high-resolution timer.
* *
*/ */
static void add_timer_randomness(struct timer_rand_state *state, unsigned num) static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
{ {
__u32 time; cycles_t time;
__s32 delta, delta2, delta3; long delta, delta2, delta3;
int entropy = 0; int entropy = 0;
/* if over the trickle threshold, use only 1 in 4096 samples */ /* if over the trickle threshold, use only 1 in 4096 samples */
...@@ -814,22 +812,17 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) ...@@ -814,22 +812,17 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
(__get_cpu_var(trickle_count)++ & 0xfff)) (__get_cpu_var(trickle_count)++ & 0xfff))
return; return;
#if defined (__i386__) || defined (__x86_64__) /*
if (cpu_has_tsc) { * Use get_cycles() if implemented, otherwise fall back to
__u32 high; * jiffies.
rdtsc(time, high); */
num ^= high; time = get_cycles();
if (time != 0) {
if (sizeof(time) > 4)
num ^= (u32)(time >> 32);
} else { } else {
time = jiffies; time = jiffies;
} }
#elif defined (__sparc_v9__)
unsigned long tick = tick_ops->get_tick();
time = (unsigned int) tick;
num ^= (tick >> 32UL);
#else
time = jiffies;
#endif
/* /*
* Calculate number of bits of randomness we probably added. * Calculate number of bits of randomness we probably added.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#define _ASMi386_TIMEX_H #define _ASMi386_TIMEX_H
#include <linux/config.h> #include <linux/config.h>
#include <asm/msr.h> #include <asm/processor.h>
#ifdef CONFIG_X86_ELAN #ifdef CONFIG_X86_ELAN
# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ # define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
...@@ -40,14 +40,17 @@ extern cycles_t cacheflush_time; ...@@ -40,14 +40,17 @@ extern cycles_t cacheflush_time;
static inline cycles_t get_cycles (void) static inline cycles_t get_cycles (void)
{ {
unsigned long long ret=0;
#ifndef CONFIG_X86_TSC #ifndef CONFIG_X86_TSC
return 0; if (!cpu_has_tsc)
#else return 0;
unsigned long long ret; #endif
#if defined(CONFIG_X86_GENERIC) || defined(CONFIG_X86_TSC)
rdtscll(ret); rdtscll(ret);
return ret;
#endif #endif
return ret;
} }
extern unsigned long cpu_khz; extern unsigned long cpu_khz;
......
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