forked from luck/tmp_suning_uos_patched
642fa448ae
This is a nasty interface and setting the state of a foreign task must
not be done. As of the following commit:
be628be095
("bcache: Make gc wakeup sane, remove set_task_state()")
... everyone in the kernel calls set_task_state() with current, allowing
the helper to be removed.
However, as the comment indicates, it is still around for those archs
where computing current is more expensive than using a pointer, at least
in theory. An important arch that is affected is arm64, however this has
been addressed now [1] and performance is up to par making no difference
with either calls.
Of all the callers, if any, it's the locking bits that would care most
about this -- ie: we end up passing a tsk pointer to a lot of the lock
slowpath, and setting ->state on that. The following numbers are based
on two tests: a custom ad-hoc microbenchmark that just measures
latencies (for ~65 million calls) between get_task_state() vs
get_current_state().
Secondly for a higher overview, an unlink microbenchmark was used,
which pounds on a single file with open, close,unlink combos with
increasing thread counts (up to 4x ncpus). While the workload is quite
unrealistic, it does contend a lot on the inode mutex or now rwsem.
[1] https://lkml.kernel.org/r/1483468021-8237-1-git-send-email-mark.rutland@arm.com
== 1. x86-64 ==
Avg runtime set_task_state(): 601 msecs
Avg runtime set_current_state(): 552 msecs
vanilla dirty
Hmean unlink1-processes-2 36089.26 ( 0.00%) 38977.33 ( 8.00%)
Hmean unlink1-processes-5 28555.01 ( 0.00%) 29832.55 ( 4.28%)
Hmean unlink1-processes-8 37323.75 ( 0.00%) 44974.57 ( 20.50%)
Hmean unlink1-processes-12 43571.88 ( 0.00%) 44283.01 ( 1.63%)
Hmean unlink1-processes-21 34431.52 ( 0.00%) 38284.45 ( 11.19%)
Hmean unlink1-processes-30 34813.26 ( 0.00%) 37975.17 ( 9.08%)
Hmean unlink1-processes-48 37048.90 ( 0.00%) 39862.78 ( 7.59%)
Hmean unlink1-processes-79 35630.01 ( 0.00%) 36855.30 ( 3.44%)
Hmean unlink1-processes-110 36115.85 ( 0.00%) 39843.91 ( 10.32%)
Hmean unlink1-processes-141 32546.96 ( 0.00%) 35418.52 ( 8.82%)
Hmean unlink1-processes-172 34674.79 ( 0.00%) 36899.21 ( 6.42%)
Hmean unlink1-processes-203 37303.11 ( 0.00%) 36393.04 ( -2.44%)
Hmean unlink1-processes-224 35712.13 ( 0.00%) 36685.96 ( 2.73%)
== 2. ppc64le ==
Avg runtime set_task_state(): 938 msecs
Avg runtime set_current_state: 940 msecs
vanilla dirty
Hmean unlink1-processes-2 19269.19 ( 0.00%) 30704.50 ( 59.35%)
Hmean unlink1-processes-5 20106.15 ( 0.00%) 21804.15 ( 8.45%)
Hmean unlink1-processes-8 17496.97 ( 0.00%) 17243.28 ( -1.45%)
Hmean unlink1-processes-12 14224.15 ( 0.00%) 17240.21 ( 21.20%)
Hmean unlink1-processes-21 14155.66 ( 0.00%) 15681.23 ( 10.78%)
Hmean unlink1-processes-30 14450.70 ( 0.00%) 15995.83 ( 10.69%)
Hmean unlink1-processes-48 16945.57 ( 0.00%) 16370.42 ( -3.39%)
Hmean unlink1-processes-79 15788.39 ( 0.00%) 14639.27 ( -7.28%)
Hmean unlink1-processes-110 14268.48 ( 0.00%) 14377.40 ( 0.76%)
Hmean unlink1-processes-141 14023.65 ( 0.00%) 16271.69 ( 16.03%)
Hmean unlink1-processes-172 13417.62 ( 0.00%) 16067.55 ( 19.75%)
Hmean unlink1-processes-203 15293.08 ( 0.00%) 15440.40 ( 0.96%)
Hmean unlink1-processes-234 13719.32 ( 0.00%) 16190.74 ( 18.01%)
Hmean unlink1-processes-265 16400.97 ( 0.00%) 16115.22 ( -1.74%)
Hmean unlink1-processes-296 14388.60 ( 0.00%) 16216.13 ( 12.70%)
Hmean unlink1-processes-320 15771.85 ( 0.00%) 15905.96 ( 0.85%)
x86-64 (known to be fast for get_current()/this_cpu_read_stable() caching)
and ppc64 (with paca) show similar improvements in the unlink microbenches.
The small delta for ppc64 (2ms), does not represent the gains on the unlink
runs. In the case of x86, there was a decent amount of variation in the
latency runs, but always within a 20 to 50ms increase), ppc was more constant.
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: dave@stgolabs.net
Cc: mark.rutland@arm.com
Link: http://lkml.kernel.org/r/1483479794-14013-5-git-send-email-dave@stgolabs.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
168 lines
3.6 KiB
C
168 lines
3.6 KiB
C
/* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */
|
|
|
|
/* Much of this ripped from drivers/char/hw_random.c, see there for other
|
|
* copyright.
|
|
*
|
|
* This software may be used and distributed according to the terms
|
|
* of the GNU General Public License, incorporated herein by reference.
|
|
*/
|
|
#include <linux/sched.h>
|
|
#include <linux/module.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/uaccess.h>
|
|
#include <irq_kern.h>
|
|
#include <os.h>
|
|
|
|
/*
|
|
* core module and version information
|
|
*/
|
|
#define RNG_VERSION "1.0.0"
|
|
#define RNG_MODULE_NAME "hw_random"
|
|
|
|
#define RNG_MISCDEV_MINOR 183 /* official */
|
|
|
|
/* Changed at init time, in the non-modular case, and at module load
|
|
* time, in the module case. Presumably, the module subsystem
|
|
* protects against a module being loaded twice at the same time.
|
|
*/
|
|
static int random_fd = -1;
|
|
static DECLARE_WAIT_QUEUE_HEAD(host_read_wait);
|
|
|
|
static int rng_dev_open (struct inode *inode, struct file *filp)
|
|
{
|
|
/* enforce read-only access to this chrdev */
|
|
if ((filp->f_mode & FMODE_READ) == 0)
|
|
return -EINVAL;
|
|
if ((filp->f_mode & FMODE_WRITE) != 0)
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static atomic_t host_sleep_count = ATOMIC_INIT(0);
|
|
|
|
static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
|
|
loff_t *offp)
|
|
{
|
|
u32 data;
|
|
int n, ret = 0, have_data;
|
|
|
|
while (size) {
|
|
n = os_read_file(random_fd, &data, sizeof(data));
|
|
if (n > 0) {
|
|
have_data = n;
|
|
while (have_data && size) {
|
|
if (put_user((u8) data, buf++)) {
|
|
ret = ret ? : -EFAULT;
|
|
break;
|
|
}
|
|
size--;
|
|
ret++;
|
|
have_data--;
|
|
data >>= 8;
|
|
}
|
|
}
|
|
else if (n == -EAGAIN) {
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
|
if (filp->f_flags & O_NONBLOCK)
|
|
return ret ? : -EAGAIN;
|
|
|
|
atomic_inc(&host_sleep_count);
|
|
reactivate_fd(random_fd, RANDOM_IRQ);
|
|
add_sigio_fd(random_fd);
|
|
|
|
add_wait_queue(&host_read_wait, &wait);
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
|
|
schedule();
|
|
remove_wait_queue(&host_read_wait, &wait);
|
|
|
|
if (atomic_dec_and_test(&host_sleep_count)) {
|
|
ignore_sigio_fd(random_fd);
|
|
deactivate_fd(random_fd, RANDOM_IRQ);
|
|
}
|
|
}
|
|
else
|
|
return n;
|
|
|
|
if (signal_pending (current))
|
|
return ret ? : -ERESTARTSYS;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static const struct file_operations rng_chrdev_ops = {
|
|
.owner = THIS_MODULE,
|
|
.open = rng_dev_open,
|
|
.read = rng_dev_read,
|
|
.llseek = noop_llseek,
|
|
};
|
|
|
|
/* rng_init shouldn't be called more than once at boot time */
|
|
static struct miscdevice rng_miscdev = {
|
|
RNG_MISCDEV_MINOR,
|
|
RNG_MODULE_NAME,
|
|
&rng_chrdev_ops,
|
|
};
|
|
|
|
static irqreturn_t random_interrupt(int irq, void *data)
|
|
{
|
|
wake_up(&host_read_wait);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/*
|
|
* rng_init - initialize RNG module
|
|
*/
|
|
static int __init rng_init (void)
|
|
{
|
|
int err;
|
|
|
|
err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
random_fd = err;
|
|
|
|
err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
|
|
0, "random", NULL);
|
|
if (err)
|
|
goto err_out_cleanup_hw;
|
|
|
|
sigio_broken(random_fd, 1);
|
|
|
|
err = misc_register (&rng_miscdev);
|
|
if (err) {
|
|
printk (KERN_ERR RNG_MODULE_NAME ": misc device register "
|
|
"failed\n");
|
|
goto err_out_cleanup_hw;
|
|
}
|
|
out:
|
|
return err;
|
|
|
|
err_out_cleanup_hw:
|
|
os_close_file(random_fd);
|
|
random_fd = -1;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* rng_cleanup - shutdown RNG module
|
|
*/
|
|
static void __exit rng_cleanup (void)
|
|
{
|
|
os_close_file(random_fd);
|
|
misc_deregister (&rng_miscdev);
|
|
}
|
|
|
|
module_init (rng_init);
|
|
module_exit (rng_cleanup);
|
|
|
|
MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
|
|
MODULE_LICENSE("GPL");
|