diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-03-09 12:07:17 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-03-10 14:08:19 -0400 |
commit | 009a82f6437490c262584d65a14094a818bcb747 (patch) | |
tree | b768ab0b1d4b8a102c556f9b3b6fa1052fef933e | |
parent | 03e51d32da995030a16697038232171807eeb0f2 (diff) |
SUNRPC: Micro-optimise when the task is known not to be sleeping
In cases where we know the task is not sleeping, try to optimise
away the indirect call to task->tk_action() by replacing it with
a direct call.
Only change tail calls, to allow gcc to perform tail call
elimination.
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
-rw-r--r-- | include/linux/sunrpc/sched.h | 8 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 99 |
2 files changed, 73 insertions, 34 deletions
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 52d41d0c1ae1..ec861cd0cfe8 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -304,4 +304,12 @@ rpc_clnt_swap_deactivate(struct rpc_clnt *clnt) | |||
304 | } | 304 | } |
305 | #endif /* CONFIG_SUNRPC_SWAP */ | 305 | #endif /* CONFIG_SUNRPC_SWAP */ |
306 | 306 | ||
307 | static inline bool | ||
308 | rpc_task_need_resched(const struct rpc_task *task) | ||
309 | { | ||
310 | if (RPC_IS_QUEUED(task) || task->tk_callback) | ||
311 | return true; | ||
312 | return false; | ||
313 | } | ||
314 | |||
307 | #endif /* _LINUX_SUNRPC_SCHED_H_ */ | 315 | #endif /* _LINUX_SUNRPC_SCHED_H_ */ |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 67c955d8b21b..498dd6ad5bc5 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1540,6 +1540,7 @@ call_start(struct rpc_task *task) | |||
1540 | clnt->cl_stats->rpccnt++; | 1540 | clnt->cl_stats->rpccnt++; |
1541 | task->tk_action = call_reserve; | 1541 | task->tk_action = call_reserve; |
1542 | rpc_task_set_transport(task, clnt); | 1542 | rpc_task_set_transport(task, clnt); |
1543 | call_reserve(task); | ||
1543 | } | 1544 | } |
1544 | 1545 | ||
1545 | /* | 1546 | /* |
@@ -1553,6 +1554,9 @@ call_reserve(struct rpc_task *task) | |||
1553 | task->tk_status = 0; | 1554 | task->tk_status = 0; |
1554 | task->tk_action = call_reserveresult; | 1555 | task->tk_action = call_reserveresult; |
1555 | xprt_reserve(task); | 1556 | xprt_reserve(task); |
1557 | if (rpc_task_need_resched(task)) | ||
1558 | return; | ||
1559 | call_reserveresult(task); | ||
1556 | } | 1560 | } |
1557 | 1561 | ||
1558 | static void call_retry_reserve(struct rpc_task *task); | 1562 | static void call_retry_reserve(struct rpc_task *task); |
@@ -1575,6 +1579,7 @@ call_reserveresult(struct rpc_task *task) | |||
1575 | if (status >= 0) { | 1579 | if (status >= 0) { |
1576 | if (task->tk_rqstp) { | 1580 | if (task->tk_rqstp) { |
1577 | task->tk_action = call_refresh; | 1581 | task->tk_action = call_refresh; |
1582 | call_refresh(task); | ||
1578 | return; | 1583 | return; |
1579 | } | 1584 | } |
1580 | 1585 | ||
@@ -1600,6 +1605,7 @@ call_reserveresult(struct rpc_task *task) | |||
1600 | /* fall through */ | 1605 | /* fall through */ |
1601 | case -EAGAIN: /* woken up; retry */ | 1606 | case -EAGAIN: /* woken up; retry */ |
1602 | task->tk_action = call_retry_reserve; | 1607 | task->tk_action = call_retry_reserve; |
1608 | call_retry_reserve(task); | ||
1603 | return; | 1609 | return; |
1604 | case -EIO: /* probably a shutdown */ | 1610 | case -EIO: /* probably a shutdown */ |
1605 | break; | 1611 | break; |
@@ -1622,6 +1628,9 @@ call_retry_reserve(struct rpc_task *task) | |||
1622 | task->tk_status = 0; | 1628 | task->tk_status = 0; |
1623 | task->tk_action = call_reserveresult; | 1629 | task->tk_action = call_reserveresult; |
1624 | xprt_retry_reserve(task); | 1630 | xprt_retry_reserve(task); |
1631 | if (rpc_task_need_resched(task)) | ||
1632 | return; | ||
1633 | call_reserveresult(task); | ||
1625 | } | 1634 | } |
1626 | 1635 | ||
1627 | /* | 1636 | /* |
@@ -1636,6 +1645,9 @@ call_refresh(struct rpc_task *task) | |||
1636 | task->tk_status = 0; | 1645 | task->tk_status = 0; |
1637 | task->tk_client->cl_stats->rpcauthrefresh++; | 1646 | task->tk_client->cl_stats->rpcauthrefresh++; |
1638 | rpcauth_refreshcred(task); | 1647 | rpcauth_refreshcred(task); |
1648 | if (rpc_task_need_resched(task)) | ||
1649 | return; | ||
1650 | call_refreshresult(task); | ||
1639 | } | 1651 | } |
1640 | 1652 | ||
1641 | /* | 1653 | /* |
@@ -1654,6 +1666,7 @@ call_refreshresult(struct rpc_task *task) | |||
1654 | case 0: | 1666 | case 0: |
1655 | if (rpcauth_uptodatecred(task)) { | 1667 | if (rpcauth_uptodatecred(task)) { |
1656 | task->tk_action = call_allocate; | 1668 | task->tk_action = call_allocate; |
1669 | call_allocate(task); | ||
1657 | return; | 1670 | return; |
1658 | } | 1671 | } |
1659 | /* Use rate-limiting and a max number of retries if refresh | 1672 | /* Use rate-limiting and a max number of retries if refresh |
@@ -1672,6 +1685,7 @@ call_refreshresult(struct rpc_task *task) | |||
1672 | task->tk_cred_retry--; | 1685 | task->tk_cred_retry--; |
1673 | dprintk("RPC: %5u %s: retry refresh creds\n", | 1686 | dprintk("RPC: %5u %s: retry refresh creds\n", |
1674 | task->tk_pid, __func__); | 1687 | task->tk_pid, __func__); |
1688 | call_refresh(task); | ||
1675 | return; | 1689 | return; |
1676 | } | 1690 | } |
1677 | dprintk("RPC: %5u %s: refresh creds failed with error %d\n", | 1691 | dprintk("RPC: %5u %s: refresh creds failed with error %d\n", |
@@ -1697,8 +1711,10 @@ call_allocate(struct rpc_task *task) | |||
1697 | task->tk_status = 0; | 1711 | task->tk_status = 0; |
1698 | task->tk_action = call_encode; | 1712 | task->tk_action = call_encode; |
1699 | 1713 | ||
1700 | if (req->rq_buffer) | 1714 | if (req->rq_buffer) { |
1715 | call_encode(task); | ||
1701 | return; | 1716 | return; |
1717 | } | ||
1702 | 1718 | ||
1703 | if (proc->p_proc != 0) { | 1719 | if (proc->p_proc != 0) { |
1704 | BUG_ON(proc->p_arglen == 0); | 1720 | BUG_ON(proc->p_arglen == 0); |
@@ -1719,8 +1735,12 @@ call_allocate(struct rpc_task *task) | |||
1719 | 1735 | ||
1720 | status = xprt->ops->buf_alloc(task); | 1736 | status = xprt->ops->buf_alloc(task); |
1721 | xprt_inject_disconnect(xprt); | 1737 | xprt_inject_disconnect(xprt); |
1722 | if (status == 0) | 1738 | if (status == 0) { |
1739 | if (rpc_task_need_resched(task)) | ||
1740 | return; | ||
1741 | call_encode(task); | ||
1723 | return; | 1742 | return; |
1743 | } | ||
1724 | if (status != -ENOMEM) { | 1744 | if (status != -ENOMEM) { |
1725 | rpc_exit(task, status); | 1745 | rpc_exit(task, status); |
1726 | return; | 1746 | return; |
@@ -1803,12 +1823,8 @@ call_encode(struct rpc_task *task) | |||
1803 | xprt_request_enqueue_receive(task); | 1823 | xprt_request_enqueue_receive(task); |
1804 | xprt_request_enqueue_transmit(task); | 1824 | xprt_request_enqueue_transmit(task); |
1805 | out: | 1825 | out: |
1806 | task->tk_action = call_transmit; | 1826 | task->tk_action = call_bind; |
1807 | /* Check that the connection is OK */ | 1827 | call_bind(task); |
1808 | if (!xprt_bound(task->tk_xprt)) | ||
1809 | task->tk_action = call_bind; | ||
1810 | else if (!xprt_connected(task->tk_xprt)) | ||
1811 | task->tk_action = call_connect; | ||
1812 | } | 1828 | } |
1813 | 1829 | ||
1814 | /* | 1830 | /* |
@@ -1842,14 +1858,17 @@ call_bind(struct rpc_task *task) | |||
1842 | return; | 1858 | return; |
1843 | } | 1859 | } |
1844 | 1860 | ||
1861 | if (xprt_bound(xprt)) { | ||
1862 | task->tk_action = call_connect; | ||
1863 | call_connect(task); | ||
1864 | return; | ||
1865 | } | ||
1866 | |||
1845 | dprint_status(task); | 1867 | dprint_status(task); |
1846 | 1868 | ||
1847 | task->tk_action = call_connect; | 1869 | task->tk_action = call_bind_status; |
1848 | if (!xprt_bound(xprt)) { | 1870 | task->tk_timeout = xprt->bind_timeout; |
1849 | task->tk_action = call_bind_status; | 1871 | xprt->ops->rpcbind(task); |
1850 | task->tk_timeout = xprt->bind_timeout; | ||
1851 | xprt->ops->rpcbind(task); | ||
1852 | } | ||
1853 | } | 1872 | } |
1854 | 1873 | ||
1855 | /* | 1874 | /* |
@@ -1869,6 +1888,7 @@ call_bind_status(struct rpc_task *task) | |||
1869 | dprint_status(task); | 1888 | dprint_status(task); |
1870 | task->tk_status = 0; | 1889 | task->tk_status = 0; |
1871 | task->tk_action = call_connect; | 1890 | task->tk_action = call_connect; |
1891 | call_connect(task); | ||
1872 | return; | 1892 | return; |
1873 | } | 1893 | } |
1874 | 1894 | ||
@@ -1949,21 +1969,24 @@ call_connect(struct rpc_task *task) | |||
1949 | return; | 1969 | return; |
1950 | } | 1970 | } |
1951 | 1971 | ||
1972 | if (xprt_connected(xprt)) { | ||
1973 | task->tk_action = call_transmit; | ||
1974 | call_transmit(task); | ||
1975 | return; | ||
1976 | } | ||
1977 | |||
1952 | dprintk("RPC: %5u call_connect xprt %p %s connected\n", | 1978 | dprintk("RPC: %5u call_connect xprt %p %s connected\n", |
1953 | task->tk_pid, xprt, | 1979 | task->tk_pid, xprt, |
1954 | (xprt_connected(xprt) ? "is" : "is not")); | 1980 | (xprt_connected(xprt) ? "is" : "is not")); |
1955 | 1981 | ||
1956 | task->tk_action = call_transmit; | 1982 | task->tk_action = call_connect_status; |
1957 | if (!xprt_connected(xprt)) { | 1983 | if (task->tk_status < 0) |
1958 | task->tk_action = call_connect_status; | 1984 | return; |
1959 | if (task->tk_status < 0) | 1985 | if (task->tk_flags & RPC_TASK_NOCONNECT) { |
1960 | return; | 1986 | rpc_exit(task, -ENOTCONN); |
1961 | if (task->tk_flags & RPC_TASK_NOCONNECT) { | 1987 | return; |
1962 | rpc_exit(task, -ENOTCONN); | ||
1963 | return; | ||
1964 | } | ||
1965 | xprt_connect(task); | ||
1966 | } | 1988 | } |
1989 | xprt_connect(task); | ||
1967 | } | 1990 | } |
1968 | 1991 | ||
1969 | /* | 1992 | /* |
@@ -2016,6 +2039,7 @@ call_connect_status(struct rpc_task *task) | |||
2016 | case 0: | 2039 | case 0: |
2017 | clnt->cl_stats->netreconn++; | 2040 | clnt->cl_stats->netreconn++; |
2018 | task->tk_action = call_transmit; | 2041 | task->tk_action = call_transmit; |
2042 | call_transmit(task); | ||
2019 | return; | 2043 | return; |
2020 | } | 2044 | } |
2021 | rpc_exit(task, status); | 2045 | rpc_exit(task, status); |
@@ -2040,19 +2064,20 @@ call_transmit(struct rpc_task *task) | |||
2040 | dprint_status(task); | 2064 | dprint_status(task); |
2041 | 2065 | ||
2042 | task->tk_action = call_transmit_status; | 2066 | task->tk_action = call_transmit_status; |
2067 | if (!xprt_prepare_transmit(task)) | ||
2068 | return; | ||
2069 | task->tk_status = 0; | ||
2043 | if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) { | 2070 | if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) { |
2044 | if (!xprt_prepare_transmit(task)) | 2071 | if (!xprt_connected(task->tk_xprt)) { |
2072 | task->tk_status = -ENOTCONN; | ||
2045 | return; | 2073 | return; |
2046 | task->tk_status = 0; | ||
2047 | if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) { | ||
2048 | if (!xprt_connected(task->tk_xprt)) { | ||
2049 | task->tk_status = -ENOTCONN; | ||
2050 | return; | ||
2051 | } | ||
2052 | xprt_transmit(task); | ||
2053 | } | 2074 | } |
2075 | xprt_transmit(task); | ||
2054 | } | 2076 | } |
2055 | xprt_end_transmit(task); | 2077 | xprt_end_transmit(task); |
2078 | if (rpc_task_need_resched(task)) | ||
2079 | return; | ||
2080 | call_transmit_status(task); | ||
2056 | } | 2081 | } |
2057 | 2082 | ||
2058 | /* | 2083 | /* |
@@ -2067,8 +2092,12 @@ call_transmit_status(struct rpc_task *task) | |||
2067 | * Common case: success. Force the compiler to put this | 2092 | * Common case: success. Force the compiler to put this |
2068 | * test first. | 2093 | * test first. |
2069 | */ | 2094 | */ |
2070 | if (task->tk_status == 0) { | 2095 | if (rpc_task_transmitted(task)) { |
2071 | xprt_request_wait_receive(task); | 2096 | if (task->tk_status == 0) |
2097 | xprt_request_wait_receive(task); | ||
2098 | if (rpc_task_need_resched(task)) | ||
2099 | return; | ||
2100 | call_status(task); | ||
2072 | return; | 2101 | return; |
2073 | } | 2102 | } |
2074 | 2103 | ||
@@ -2129,6 +2158,7 @@ call_bc_encode(struct rpc_task *task) | |||
2129 | { | 2158 | { |
2130 | xprt_request_enqueue_transmit(task); | 2159 | xprt_request_enqueue_transmit(task); |
2131 | task->tk_action = call_bc_transmit; | 2160 | task->tk_action = call_bc_transmit; |
2161 | call_bc_transmit(task); | ||
2132 | } | 2162 | } |
2133 | 2163 | ||
2134 | /* | 2164 | /* |
@@ -2219,6 +2249,7 @@ call_status(struct rpc_task *task) | |||
2219 | status = task->tk_status; | 2249 | status = task->tk_status; |
2220 | if (status >= 0) { | 2250 | if (status >= 0) { |
2221 | task->tk_action = call_decode; | 2251 | task->tk_action = call_decode; |
2252 | call_decode(task); | ||
2222 | return; | 2253 | return; |
2223 | } | 2254 | } |
2224 | 2255 | ||