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 | ||
