【问题标题】:How to get `gcc` to generate `bts` instruction for x86-64 from standard C?如何让`gcc`从标准C生成x86-64的`bts`指令?
【发布时间】:2011-01-03 15:14:59
【问题描述】:

recent question的启发,我想知道是否有人知道如何让gcc在Linux x86-64平台上生成x86-64 bts指令(位测试和设置),无需使用内联汇编或非标准编译器内在函数。

相关问题:

可移植性对我来说比bts 更重要,所以我不会使用和asm 指令,如果有其他解决方案,我宁愿不使用编译器内在函数。

EDIT:C 源语言不支持原子操作,所以我对 atomic 测试和设置不是特别感兴趣(即使这是原始的test-and-set 首先存在的原因)。如果我想要一些原子的东西,我知道我没有机会用标准的 C 源代码来做:它必须是内在的、库函数或内联汇编。 (我在支持多线程的编译器中实现了原子操作。)

【问题讨论】:

  • 嗯,好问题。我看到vtst_* 在 ARM+NEON 上进行矢量位测试,但没有更通用的...
  • 如果 bts 真的更快,请发送错误报告。我确信 gcc 程序员已经意识到 bts 的存在。毕竟,编译器不应该 1:1 映射。
  • 更好的是,发送一个补丁以使用 bts 以及可以分析的测试用例,以证明优化是值得的。
  • @jbcreix:您要求的 gcc 错误报告已在此 SO 发布前两年提交(并针对 4.3.0 进行了修复),请参阅:gcc.gnu.org/bugzilla/show_bug.cgi?id=36473

标签: c gcc x86-64


【解决方案1】:

我相信(但不确定)C++ 或 C 标准都没有针对这些类型的同步机制的任何机制。对更高级别同步机制的支持处于各种标准化状态,但我什至认为其中一种不会允许您访问您所追求的原语类型。

您是否正在编写锁不足的无锁数据结构?

您可能只想继续使用 gcc 的非标准扩展和/或操作系统或库提供的同步原语。如果您担心使用编译器内在函数,我敢打赌,有一个库可以提供您正在寻找的可移植性类型。 (虽然说真的,我认为大多数人只是咬紧牙关,在需要时使用 gcc 特定的代码。并不理想,但标准并没有真正跟上。)

【讨论】:

  • OP 不要求同步方法。 OP 询问是否有可移植的方式提示编译器使用bts 而不是shl + or,因为前者更快。
【解决方案2】:

我使用 gcc atomic builtins,例如 __sync_lock_test_and_set( http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html )。更改-march 标志将直接影响生成的内容。我现在将它与i686 一起使用,但http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/i386-and-x86_002d64-Options.html#i386-and-x86_002d64-Options 显示了所有可能性。

我意识到这并不是您所要求的,但是当我在寻找类似的机制时,我发现这两个网页非常有用。

【讨论】:

  • gcc 4.2 on x86-64 __sync_lock_test_and_set 生成 xchg 而不是 bts
  • bts 设置了一点,而我提到的设置了整个变量。我链接到该页面,希望 OP 可能会在那里找到有用的东西。
【解决方案3】:

它在第一个链接的第一个答案中 - 在宏伟的计划中它有多重要。测试位的唯一部分是:

  • 低级驱动程序。但是,如果您正在编写一个您可能知道 ASM 的程序,那么它对系统来说已经足够了,而且可能大多数延迟都发生在 I/O 上
  • 测试标志。它通常是在初始化(仅在开始时一次)或一些共享计算(这需要更多时间)。

即使微基准测试显示出改进,对应用程序和宏基准测试的整体性能影响也可能很小。

Edit 部分 - 单独使用 bts 并不能保证操作的原子性。它所保证的是它将是原子的在这个核心上or 在内存上也是如此)。在多处理器单元(不常见)或多核单元(非常常见)上,您仍然需要与其他处理器同步。

由于同步的成本要高得多,我相信以下之间的区别:

asm("lock bts %0, %1" : "+m" (*array) : "r" (bit));

asm("lock or %0, %1" : "+m" (*array) : "r" (1 << bit));

是最小的。第二种形式:

  • 可以一次设置多个标志
  • 有漂亮的__sync_fetch_and_or (array, 1 &lt;&lt; bit) 表单(据我所知,正在使用 gcc 和 intel 编译器)。

【讨论】:

  • “有多大关系”,嗯,根据 CPU 类型,bts 快 20%。请参阅问题的 cmets 中的 gcc 错误报告。
  • @FrankH.:我已经澄清了。 bts 在微基准测试中快了 20%,但如果它不能提高整体性能,就没有理由仅仅为了提高微基准测试就让编译器变得更复杂。显然它们已经找到了用途——但编译器更经常由宏基准驱动,然后是微基准。
  • @MaciejPiechotka:对于各种类型的软件(例如,在大型位阵列上工作的“命题逻辑引擎”),微基准测试速度提高 20% 可以转化为现实世界软件速度可能提高 19% . bts 的一种情况是分配器(例如,您可以分配/释放的每件事一位),其中 btsbtr 可以是原子的事实(带有 lock 前缀)意味着您最终可以多线程代码中的无块算法。另请注意,这些指令可以很好地处理 20 亿位或更多(在内存中)的数组,而无需额外的“脚手架”。
  • @Brendan 是的,当然-问题是特定领域应用程序的额外速度是否足以扩展-已经很复杂-优化器(显然是这样)。我的猜测是(在 4.3 之前)对于可能过度劳累的 gcc 开发人员来说,可以选择的挂果要少得多——我相信他们有很长的 TODO 列表,他们需要优先考虑。除了这样的引擎之外,无论如何都会“手动优化” - 对于原子操作,你有 __sync_fetch_and_or 和 - 在 2015 年 - 整个 C11 原子(好的 - AFAIK 它仅针对 C++11 实现,但我们不要进入这些细节)。
  • bts 带有内存操作数可以在*array 寻址的双字之外进行索引,因此这是不安全的。您必须告诉 gcc 整个数组是内存操作数,而不仅仅是一个元素。此外,您不会返回旧值,因此它不是fetch_or 或测试和设置,它只是一个原子set。此外,OP 要求非原子bts reg,reg 作为性能优化。由于位串语义,带有内存操作数的bts mem,reg 比加载/bts r,r/存储慢。 (以 Sandybridge 家族为例。agner.org/optimize
猜你喜欢
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2015-06-15
  • 2010-12-31
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
相关资源
最近更新 更多