カーネルのlikelyとunlikely
4196 ワード
1.概念
命令周期とは、1つの命令を実行するのに要する時間を指し、一般的にはいくつかの機械周期からなり、命令を取り、命令を分析してから命令を実行するまでに必要なすべてである.
プリフェッチ命令の具体的な方法は,ヒットしない場合には,メインメモリからデータを取り出してCPUに送るとともに,メインメモリの隣接するいくつかのセルのデータ(1つのデータブロックと呼ぶ)をCacheに取り出すことである.プリフェッチ命令はcpuリソースをよりよく利用することができる.簡単に言えば、メモリから命令を取るのが遅いので、cpuはこのプロセスを待っています.実行可能な命令を事前に予測できれば、メモリからcacheに読み込むことができます.cacheのアクセス速度がメモリより速いため、cpuが実行するのに長い時間待たなくてもいいです.
具体的には、CPUプリフェッチ指は、一般的には順番に送られていますが、頻繁にジャンプが発生すると、CPUの流水線の操作が中断され、指を取り直す必要がありますが、より周波数の高いイベントが発生した場合は、likelyを通じてコンパイラに伝え、判断命令の後にコードを追従させることで、ジャンプを減らし、プリフェッチ指の操作の命中率を高めることができます.
開発者がコンパイラに、どのブランチがより発生する可能性が高いか(likely)または非常に発生しないか(unlikely)を伝えることができる場合は、コンパイラのコードコンパイルを支援できます.
linuxカーネルではlikelyとunlikelyの2つのオプションがあり、以下の決定によって決定されます.
この3つの値のチェックは、likelyとunlikelyがbranch tracerトラッキングを使用する必要があるかどうかを確認します.branch tracerはftraceのtrace機能である.主にlikely予測の正確率を追跡するために使用されます.この機能を実現するためにbranch tracerはlikelyとunlikelyを再定義した.
CONFIG_TRACE_BRANCH_PROFILINGマクロは、カーネルの構成時にオンになります.DISABLE_BRANCH_PROFILINGマクロは、低レベルコードのみで各ファイルベースのブランチトレースをオフにします.defined(__CHECKER__)説明Sparseツールを使用していない場合に有効です.
struct ftrace_branch_Data構造体はftrace branchのtrace記録を記録するために用いられる.
likely_notraceとunlikely_notraceマクロ使用_builtin_expect関数,_builtin_expectは、コンパイラがコードを最適化し、アセンブリコードの判断ジャンプ文を変更するために、コンパイラ設計者に所望の比較結果を伝える.
__branch_check__マクロ、現在のtraceポイントを記録し、ftrace_を使用likely_updateはlikely判定の正しさを記録し、結果をring bufferに保存した後、ユーザはftraceのdebugfsインタフェースを通じてブランチ予測に関する情報を読み取ることができる.コードを最適化し、パフォーマンスを最適化します.
likelyとunlikelyマクロの再定義にはGCCのbuild-in関数が使用されています.builtin_constant_pは、1つの式がコンパイル時に定数であるか否かを判断する.定数の場合、likelyとunlikely式の値を直接返し、予測の記録をする必要はありません.式が非常数の場合は、マクロ__を使用します.branch_check__ブランチをチェックし、likelyが判断した予測情報を記録します.
CONFIGが設定されている場合PROFILE_ALL_BRANCHESマクロ、if()を_に再定義trace_if.__trace_if ifのすべてのブランチをチェックし、ブランチの追跡情報を記録します.
上記の2つのペアの開発者は、コンパイラの最適化を促すことができます.デバッグインタフェースを使用するとif()とelse()の差が大きくない場合は、デバッグインタフェースでその可能性が高いことを知ってからソフトウェアを調整することができます.
具体的なコードは、公式に与えられたドキュメントを参照して検索します.builtin_expect
https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Other-Builtins.html#Other-Builtins
命令周期とは、1つの命令を実行するのに要する時間を指し、一般的にはいくつかの機械周期からなり、命令を取り、命令を分析してから命令を実行するまでに必要なすべてである.
プリフェッチ命令の具体的な方法は,ヒットしない場合には,メインメモリからデータを取り出してCPUに送るとともに,メインメモリの隣接するいくつかのセルのデータ(1つのデータブロックと呼ぶ)をCacheに取り出すことである.プリフェッチ命令はcpuリソースをよりよく利用することができる.簡単に言えば、メモリから命令を取るのが遅いので、cpuはこのプロセスを待っています.実行可能な命令を事前に予測できれば、メモリからcacheに読み込むことができます.cacheのアクセス速度がメモリより速いため、cpuが実行するのに長い時間待たなくてもいいです.
具体的には、CPUプリフェッチ指は、一般的には順番に送られていますが、頻繁にジャンプが発生すると、CPUの流水線の操作が中断され、指を取り直す必要がありますが、より周波数の高いイベントが発生した場合は、likelyを通じてコンパイラに伝え、判断命令の後にコードを追従させることで、ジャンプを減らし、プリフェッチ指の操作の命中率を高めることができます.
開発者がコンパイラに、どのブランチがより発生する可能性が高いか(likely)または非常に発生しないか(unlikely)を伝えることができる場合は、コンパイラのコードコンパイルを支援できます.
linuxカーネルではlikelyとunlikelyの2つのオプションがあり、以下の決定によって決定されます.
#if defined(CONFIG_TRACE_BRANCH_PROFILING) \
&& !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__)
void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
#define likely_notrace(x) __builtin_expect(!!(x), 1)
#define unlikely_notrace(x) __builtin_expect(!!(x), 0)
#define __branch_check__(x, expect) ({ \
int ______r; \
static struct ftrace_branch_data \
__attribute__((__aligned__(4))) \
__attribute__((section("_ftrace_annotated_branch"))) \
______f = { \
.func = __func__, \
.file = __FILE__, \
.line = __LINE__, \
}; \
______r = likely_notrace(x); \
ftrace_likely_update(&______f, ______r, expect); \
______r; \
})
/*
* 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) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))
# endif
# ifndef unlikely
# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
# endif
#ifdef CONFIG_PROFILE_ALL_BRANCHES
/*
* "Define 'is'", Bill Clinton
* "Define 'if'", Steven Rostedt
*/
#define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
#define __trace_if(cond) \
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
({ \
int ______r; \
static struct ftrace_branch_data \
__attribute__((__aligned__(4))) \
__attribute__((section("_ftrace_branch"))) \
______f = { \
.func = __func__, \
.file = __FILE__, \
.line = __LINE__, \
}; \
______r = !!(cond); \
______f.miss_hit[______r]++; \
______r; \
}))
#endif /* CONFIG_PROFILE_ALL_BRANCHES */
#else
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#if defined(CONFIG_TRACE_BRANCH_PROFILING) \
&& !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__)
この3つの値のチェックは、likelyとunlikelyがbranch tracerトラッキングを使用する必要があるかどうかを確認します.branch tracerはftraceのtrace機能である.主にlikely予測の正確率を追跡するために使用されます.この機能を実現するためにbranch tracerはlikelyとunlikelyを再定義した.
CONFIG_TRACE_BRANCH_PROFILINGマクロは、カーネルの構成時にオンになります.DISABLE_BRANCH_PROFILINGマクロは、低レベルコードのみで各ファイルベースのブランチトレースをオフにします.defined(__CHECKER__)説明Sparseツールを使用していない場合に有効です.
struct ftrace_branch_Data構造体はftrace branchのtrace記録を記録するために用いられる.
likely_notraceとunlikely_notraceマクロ使用_builtin_expect関数,_builtin_expectは、コンパイラがコードを最適化し、アセンブリコードの判断ジャンプ文を変更するために、コンパイラ設計者に所望の比較結果を伝える.
__branch_check__マクロ、現在のtraceポイントを記録し、ftrace_を使用likely_updateはlikely判定の正しさを記録し、結果をring bufferに保存した後、ユーザはftraceのdebugfsインタフェースを通じてブランチ予測に関する情報を読み取ることができる.コードを最適化し、パフォーマンスを最適化します.
likelyとunlikelyマクロの再定義にはGCCのbuild-in関数が使用されています.builtin_constant_pは、1つの式がコンパイル時に定数であるか否かを判断する.定数の場合、likelyとunlikely式の値を直接返し、予測の記録をする必要はありません.式が非常数の場合は、マクロ__を使用します.branch_check__ブランチをチェックし、likelyが判断した予測情報を記録します.
CONFIGが設定されている場合PROFILE_ALL_BRANCHESマクロ、if()を_に再定義trace_if.__trace_if ifのすべてのブランチをチェックし、ブランチの追跡情報を記録します.
上記の2つのペアの開発者は、コンパイラの最適化を促すことができます.デバッグインタフェースを使用するとif()とelse()の差が大きくない場合は、デバッグインタフェースでその可能性が高いことを知ってからソフトウェアを調整することができます.
具体的なコードは、公式に与えられたドキュメントを参照して検索します.builtin_expect
https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Other-Builtins.html#Other-Builtins