多數時刻,當核心以某個外來值比較一個變數,以檢視特定條件是否滿足時,結果很有可能是可預料的。這是很常見的事,例如,那些實施sanity check的程式碼。核心會分別使用likely和unlikely巨集,把那些可能傳回一個真(1)或假(0)值的比較結果包裹起來。這些巨集會用到gcc編譯器的一項功能;此項功能會根據該項資訊來優化程式碼的編譯。
實例: 假設你必須呼叫do_something函式,但是,如果失敗的話,你必須使用handle_error韓式予以處理。
err = do_something(x, y, z);
if (err)
handle_error(err);
假如do_something很少失敗,則可以將程式改寫成下面這樣:
err = do_something(x, y, z);
if (unlikely(err))
handle_error(err);
likely和unlikely巨集所能進行的優化動作之一就是處理IP header裡面的選項。
IP選項的使用只限於一些特定情況,核心可以安全地假設多數IP封包不會攜帶IP選項。
轉送IP封包的最後一個階段係由ip_forward_finish負責。此函式會使用unlikely巨集把
「用來檢查是否要處理IP選項的條件」包裹起來。
net/ipv4/ip_forward.c
static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct ip_options *opt = &(IPCB(skb)->opt);
__IP_INC_STATS(net, IPSTATS_MIB_OUTFORWDATAGRAMS);
__IP_ADD_STATS(net, IPSTATS_MIB_OUTOCTETS, skb->len);
if (unlikely(opt->optlen))
ip_forward_options(skb);
return dst_output(net, sk, skb);
}
include/linux/compiler.h
/*
* Using __builtin_constant_p(x) to ignore cases where the return
* value is always the same. This idea is taken from a similar patch
* written by Daniel Walker.
*/
# ifndef likely
# define likely(x) (__branch_check__(x, 1, __builtin_constant_p(x)))
# endif
# ifndef unlikely
# define unlikely(x) (__branch_check__(x, 0, __builtin_constant_p(x)))
#else
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#endif
# endif
沒有留言:
張貼留言