- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是我的代码的汇编器
您可以将其嵌入c ++并针对SSE4进行检查吗?以速度
我非常想看看如何步入SSE4的开发。还是根本不担心他?让我们检查一下(我在SSSE3以上没有支持)
{ sse2 strcmp WideChar 32 bit }
function CmpSee2(const P1, P2: Pointer; len: Integer): Boolean;
asm
push ebx // Create ebx
cmp EAX, EDX // Str = Str2
je @@true // to exit true
test eax, eax // not Str
je @@false // to exit false
test edx, edx // not Str2
je @@false // to exit false
sub edx, eax // Str2 := Str2 - Str;
mov ebx, [eax] // get Str 4 byte
xor ebx, [eax + edx] // Cmp Str2 4 byte
jnz @@false // Str <> Str2 to exit false
sub ecx, 2 // dec 4
{ AnsiChar : sub ecx, 4 }
jbe @@true // ecx <= 0 to exit true
lea eax, [eax + 4] // Next 4 byte
@@To1:
movdqa xmm0, DQWORD PTR [eax] // Load Str 16 byte
pcmpeqw xmm0, DQWORD PTR [eax+edx] // Load Str2 16 byte and cmp
pmovmskb ebx, xmm0 // Mask cmp
cmp ebx, 65535 // Cmp mask
jne @@Final // ebx <> 65535 to goto final
add eax, 16 // Next 16 byte
sub ecx, 8 // Skip 8 byte (16 wide)
{ AnsiChar : sub ecx, 16 }
ja @@To1 // ecx > 0
@@true: // Result true
mov eax, 1 // Set true
pop ebx // Remove ebx
ret // Return
@@false: // Result false
mov eax, 0 // Set false
pop ebx // Remove ebx
ret // Return
@@Final:
cmp ecx, 7 // (ebx <> 65535) and (ecx > 7)
{ AnsiChar : cmp ecx, 15 }
jae @@false // to exit false
movzx ecx, word ptr @@mask[ecx * 2 - 2] // ecx = mask[ecx]
and ebx, ecx // ebx = ebx & ecx
cmp ebx, ecx // ebx = ecx
sete al // Equal / Set if Zero
pop ebx // Remove ebx
ret // Return
@@mask: // array Mersenne numbers
dw $000F, $003F, $00FF, $03FF, $0FFF, $3FFF
{ AnsiChar
dw 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383
}
end;
最佳答案
您调用了函数strcmp
,但实际上实现的是需要对齐的memcmp(const void *a, const void *b, size_t words)
。如果指针未与16B对齐,则movdqa
和pcmpeqw xmm0, [mem]
都将出错。 (实际上,如果a+4
不是16B对齐的,因为您要执行前4个标量并增加4个字节。)
使用正确的启动代码和movdqu
,您可以处理任意对齐(达到要用作pcmpeqw
的内存操作数的指针的对齐边界)。为了方便起见,您可能需要两个指针都以宽字符对齐开头,但您不需要这样做(尤其是因为您只是返回true / false,而不是negative / 0 /
作为排序顺序。)
positive
您是在问SSE2 pcmpeqw
与pcmpistrm
的性能,对吗? (显式长度SSE4.2指令类似于pcmpestrm
have worse throughput than the implicit-length versions,因此当您不靠近字符串的结尾时,请在主循环中使用隐式长度版本。请参见Agner Fog's instruction tables和microarch指南)。
对于memcmp(或精心实现的strcmp),在大多数CPU上,使用SSE4.2可以做到的最好比使用SSE2(或SSSE3)可以做到的最好。可能对非常短的字符串有用,但对memcmp的主循环却没有作用。
在Nehalem上:pcmpistri
是4 uops,2c吞吐量(带有内存操作数),因此没有其他循环开销,它可以跟上内存的速度。 (Nehalem仅具有1个加载端口)。 pcmpestri
的吞吐量为6c:慢3倍。
在通过Skylake的Sandybridge上,pcmpistri xmm0, [eax]
的吞吐量为3c,因此,要使每个时钟保持1个矢量(2个加载端口)的速度太慢,就要加倍3倍。 pcmpestri
在大多数情况下具有4c吞吐量,因此也没有那么糟糕。 (对于最后的部分矢量可能有用,但在主循环中无效)。
在Silvermont / KNL上,pcmpistrm
是最快的,并且每14个循环吞吐量运行一次,因此它是简单事物的总垃圾。
在AMD Jaguar上,pcmpistri
为2c吞吐量,因此它实际上可能是可用的(仅一个加载端口)。 pcmpestri
是5c吞吐量,因此很糟糕。
在AMD Ryzen上,pcmpistri
的吞吐量也为2c,因此很糟糕。 (2个加载端口和每个时钟前端吞吐量5 uop(或6 uop,如果有(或全部?)来自多uup指令)则意味着您可以提高速度。
在AMD Bulldozer系列中,pcmpistri
的吞吐量为3c,直到Steamroller的吞吐量为5c。 pcmpestri
的吞吐量为10c。它们被微编码为7或27 m-op,因此AMD并没有在它们上花费很多硅。
在大多数CPU上,仅当您充分利用它们来处理pcmpeq
/ pmovmskb
不能做到的事情时,才值得这样做。但是,如果您可以使用AVX2或尤其是AVX512BW,则在更宽的向量上使用更多的指令,即使执行复杂的操作也可能更快。 (没有SSE4.2字符串指令的较宽版本。)也许SSE4.2字符串指令对于通常处理短字符串的函数仍然有用,因为宽向量循环通常需要更多的启动/清除开销。同样,在一个不需要花费太多时间在SIMD循环中的程序中,在一个小的功能中使用AVX或AVX512仍然会在下一毫秒左右降低您的最大Turbo时钟速度,并且很容易造成净损失。
良好的内部循环应成为负载吞吐量的瓶颈,或者尽可能接近。 movqdu
/ pcmpeqw [one-register]
/ pmovmskb
/ macro-fused-cmp + jcc仅有4个融合域uops,因此在Sandybridge系列CPU上几乎可以实现
有关实现和一些基准,请参见https://www.strchr.com/strcmp_and_strlen_using_sse_4.2,但这是针对C样式的隐式长度字符串的,您必须在其中检查0
字节。看起来您正在使用显式长度的字符串,因此在检查长度相等之后,它只是memcmp
。 (或者,我想如果您需要查找排序顺序而不是仅等于/不等于,那么您必须将memcmp移到较短的字符串的末尾。)
对于具有8位字符串的strcmp,在大多数CPU上,最好不使用SSE4.2字符串指令。请参阅strchr.com文章上的评论以获取一些基准测试(该隐式长度字符串版本的基准测试)。例如,glibc不使用strcmp
的SSE4.2字符串指令,因为它们在大多数CPU上都不快。他们可能是strstr
的胜利。
glibc有几个SSE2 / SSSE3 asm strcmp
和memcmp
implementations。 (它是LGPL格式的,因此您不能将其复制到非GPL项目中,而要看看它们的作用。)一些字符串函数(如strlen)仅每64个字节分支一次,然后返回进行排序缓存行中的哪个字节被命中。但是他们的memcmp实现只是通过movdqu / pcmpeqb
展开。您可以使用pcmpeqw
,因为您想知道第一个16位元素的位置,而不是第一个字节的位置。
您的SSE2实现可能更快。您应该对movdqa使用索引寻址模式,因为它不会与pcmpeqw微融合(在Intel Sandybridge / Ivybridge上;在Nehalem或Haswell +上很好),但是pcmpeqw xmm0, [eax]
将保持微融合而不分层。
您应该展开几次以减少循环开销。您应该将指针增量与循环计数器结合使用,以便在更多CPU上使用cmp/jb
而不是sub/ja
:宏融合,并避免写入寄存器(减少寄存器重新命名所需的物理寄存器数量)。
您在Intel Sandybridge / Ivybridge上的内部循环将运行
@@To1:
movdqa xmm0, DQWORD PTR [eax] // 1 uop
pcmpeqw xmm0, DQWORD PTR [eax+edx] // 2 uops on Intel SnB/IvB, 1 on Nehalem and earlier or Haswell and later.
pmovmskb ebx, xmm0 // 1 uop
cmp ebx, 65535
jne @@Final // 1 uop (macro-fused with cmp)
add eax, 16 // 1 uop
sub ecx, 8
{ AnsiChar : sub ecx, 16 }
ja @@To1 // 1 uop (macro-fused with sub on SnB and later, otherwise 2)
pcmpeqw
)保持微融合,但不能与其他任何内容(如
pabsw xmm0, [eax+edx]
(不会读取目标) )或AVX
vpcmpeqw xmm0, xmm0, [eax+edx]
(3个操作数))。请参见
Micro fusion and addressing modes。
cmp
。您可以
sub
/
jne
用相同的宏融合比较和分支减去并检查两者是否相等。 (它只能在Intel Sandybridge系列上进行宏熔断,并且只有Haswell可以在单个解码块中进行2次宏熔断。但是Haswell / Broadwell / Skylake CPU很常见,并且变得越来越普遍,这对其他处理器没有不利影响CPU,除非等号指针如此普遍,以至于首先进行检查很重要。)
xor eax,eax
to zero a register,而不要使用
mov eax, 0
。
xor ebx, [eax + edx]
与
cmp
相比具有零优势。
cmp/jnz
可以与jcc宏融合,但
xor
不能。
bsf
在位图中找到第一个差异。我想用
not
反转它以找到不相等的第一个位置,并检查它是否小于剩余的字符串长度。
mov eax, -1
和
shr
动态生成蒙版。或为了加载它,有时可以使用滑动窗口到
...,0,0,0,-1,-1,-1,...
数组中,但是需要亚字节偏移量,以使其不起作用。 (如果要蒙版并重做
pmovmskb
。
Vectorizing with unaligned buffers: using VMASKMOVPS: generating a mask from a misalignment count? Or not using that insn at all,则它对于矢量蒙版非常有效)。
count % 8
,所以屏蔽生成可以与循环并行进行。
关于assembly - 对于memcmp,SSE4.2字符串指令比SSE2快多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46762813/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!