2017年9月12日 星期二

likely / unlikely 編譯期間優化條件檢查

多數時刻,當核心以某個外來值比較一個變數,以檢視特定條件是否滿足時,結果很有可能是可預料的。這是很常見的事,例如,那些實施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

沒有留言:

張貼留言