パフォーマンスが重要なアプリケーションを開発しています。GCCで、memset()への特定の呼び出しを、「rep stos QWORD PTR es:[rdi]、rax」のような繰り返しプレフィックスを持つ命令として変換したいと思います。サイズが既知で小さい場合、GCCはこれを自動的に行います。
ただし、GCCは、PLTを介したmemset()の呼び出しを通じて、ランダムな長さのmemset()の呼び出しをマップします。これにより、分岐予測キャッシュがコールドであるため、分岐の予測ミスが発生します。
GCCに(インラインアセンブリ以外で)私が望むことを強制する方法はありますか?プログラム全体でこの動作を望まないことに注意してください。特定のmemset()呼び出しに対してのみです。
関連するトピックでは、cmovcc命令がジョブを実行するときにGCCが分岐するのを防ぐハックにも興味があります(&&の代わりに&、+などを使用することについて知っています)。
助けてくれてありがとう。
@FrankH:
それは基本的に私がやったことです。これが私のコードです:
static finline void app_zero(void *dst, uint32_t size, uint32_t count)
{
// Warning: we tell gcc to use 'dst' both as source and destination here.
// This does not cause problems because we don't reuse 'dst'.
#ifdef APP_ARCH_X86
#define STOS(X,Y) do { \
int c = (size/Y)*count; \
__asm__ __volatile__("cld; xor %%eax, %%eax; rep stos"X"\n\n" \
: "+D"(dst), "+c"(c) :: "rax", "flags"); \
} while (0)
if (size % 8 == 0) STOS("q", 8);
else if (size % 4 == 0) STOS("l", 4);
else if (size % 2 == 0) STOS("w", 2);
else STOS("b", 1);
#undef STOS
#else
memset(dst, 0, size*count);
#endif
}
この例はテストセットアップで機能しますが、一般的には機能しないことに注意してください。GCCは方向フラグを変更できるため、cld
指示が必要です。さらに、命令によって変更されること%rdi
をgccに通知する必要があります。また、gccではレジスタが入力とクローバーの両方であることを指定できないため、厄介な構文を使用する必要があります(これにより入力値も破損します) 。%rcx
stos
"+"
Nehalemで4サイクルのレイテンシーを持つ「cld」命令のため、これは最適ではありません。GCCはフラグレジスタの状態を内部で追跡するため(AFAICT)、毎回その命令を発行する必要はありません。