给定以下输入字节:
var cart = [{
"success": false,
"message": "All Items Fetched",
"cartItems": [{
"_id": "5abca75f43b4c21ec482e96d",
"title": "Apples",
"price": 594,
"quantity": 6,
"prodId": "5aadb71792f47742d4e3749b",
"__v": 0
},
{
"_id": "5abca75f43b4c21ec482e96e",
"title": "Red and Mixed Grapes",
"price": 645,
"quantity": 5,
"prodId": "5aac5dac664a9042a44bf787",
"__v": 0
},
{
"_id": "5abca76143b4c21ec482e96f",
"title": "AnanaB",
"price": 445,
"quantity": 5,
"prodId": "5ab1c1a8044a584bdcad6e1d",
"__v": 0
}
]
}];
cart.forEach((data) => {
for (var obj in data.cartItems) {
console.log(data.cartItems[obj].quantity + ' x of ' + data.cartItems[obj].title);
}
});
给定的面具:
var vBytes = new Vector<byte>(new byte[] {72, 101, 55, 08, 108, 111, 55, 87, 111, 114, 108, 55, 100, 55, 55, 20});
如何在输入数组中找到字节var mask = new Vector<byte>(55);
的计数?
我已尝试 xoring 55
与vBytes
:
mask
给出:
&lt; 127,82,0,91,91,88,0,96,88,69,91,0,03,0,0,35&gt;
但不知道我怎么能从中获得数。
为简单起见,我们假设输入字节长度始终等于var xored = Vector.Xor(mask, vBytes);
的大小。
答案 0 :(得分:2)
答案 1 :(得分:2)
在asm中,您希望pcmpeqb
生成0或0xFF的向量。作为有符号整数处理,即0 / -1。
然后将compare-result用作整数值和psubb
,将0/1添加到该元素的计数器。 (减去-1 =加+1)
这可能会在256次迭代后溢出,因此在此之前的某个时间,对psadbw
使用_mm_setzero_si128()
将这些无符号字节(不会过低)水平地加总为64位整数(每组一个64位整数) 8个字节)。然后paddq
累积64位总数。
在溢出之前累积可以使用嵌套循环完成,或者仅在常规展开循环结束时完成。 psadbw
速度很快(因为它是视频编码运动搜索的关键构建块),因此只需每4个比较累积一次,甚至每1个并跳过{{1 }}
有关x86的更多详细信息,请参阅Agner Fog's optimization guides。根据他的指令表,psubb
/ psadbw xmm
在Skylake上以每个时钟周期1个向量运行,具有3个周期延迟。 (只有1 uop的前端带宽。)上面提到的所有指令也是单uop,并且在多个端口上运行(因此不必为了吞吐量而相互冲突)。它们的128位版本只需要SSE2。
如果你真的一次只有一个向量来计数,而不是在内存上循环,那么可能vpsadbw ymm
/ pcmpeqb
/ psadbw
(复制高一半到low)/ pshufd
/ paddd
在整数寄存器中给出255 *匹配数。一个额外的向量指令(如从零减去,或与1减1或movd eax, xmm0
(绝对值)将删除x255比例因子。
IDK如何在C#SIMD中编写,但你肯定不想要一个点积!解包并转换为FP将比上面慢4倍,这是因为固定宽度向量比浮点数多4倍字节,pabsb
(dpps
)不< / em>快。 Skylake上的每1.5个循环吞吐量为4 uops,一个。如果做必须对除无符号字节以外的其他内容进行水平求和,请参阅Fastest way to do horizontal float vector sum on x86(我的答案也包括整数)。
或者如果_mm_dp_ps
对整数向量使用Vector.Dot
/ pmaddubsw
,那么这可能不会那么糟糕,但为每个比较结果向量执行多步水平求和只是与pmaddwd
相比较差,或者特别是偶尔为水平求和的字节累加器。
或者,如果C#使用psadbw
的常量向量优化任何实际乘法。无论如何,这个答案的第一部分是您希望CPU运行的代码。实现这一点,但是你喜欢使用任何源代码来实现它。
答案 2 :(得分:1)
这里是C:
中的快速SSE2实现size_t memcount_sse2(const void *s, int c, size_t n) {
__m128i cv = _mm_set1_epi8(c), sum = _mm_setzero_si128(), acr0,acr1,acr2,acr3;
const char *p,*pe;
for(p = s; p != (char *)s+(n- (n % (252*16)));) {
for(acr0 = acr1 = acr2 = acr3 = _mm_setzero_si128(),pe = p+252*16; p != pe; p += 64) {
acr0 = _mm_add_epi8(acr0, _mm_cmpeq_epi8(cv, _mm_loadu_si128((const __m128i *)p)));
acr1 = _mm_add_epi8(acr1, _mm_cmpeq_epi8(cv, _mm_loadu_si128((const __m128i *)(p+16))));
acr2 = _mm_add_epi8(acr2, _mm_cmpeq_epi8(cv, _mm_loadu_si128((const __m128i *)(p+32))));
acr3 = _mm_add_epi8(acr3, _mm_cmpeq_epi8(cv, _mm_loadu_si128((const __m128i *)(p+48))));
__builtin_prefetch(p+1024);
}
sum = _mm_add_epi64(sum, _mm_sad_epu8(_mm_sub_epi8(_mm_setzero_si128(), acr0), _mm_setzero_si128()));
sum = _mm_add_epi64(sum, _mm_sad_epu8(_mm_sub_epi8(_mm_setzero_si128(), acr1), _mm_setzero_si128()));
sum = _mm_add_epi64(sum, _mm_sad_epu8(_mm_sub_epi8(_mm_setzero_si128(), acr2), _mm_setzero_si128()));
sum = _mm_add_epi64(sum, _mm_sad_epu8(_mm_sub_epi8(_mm_setzero_si128(), acr3), _mm_setzero_si128()));
}
// may require SSE4, rewrite this part for actual SSE2.
size_t count = _mm_extract_epi64(sum, 0) + _mm_extract_epi64(sum, 1);
// scalar cleanup. Could be optimized.
while(p != (char *)s + n) count += *p++ == c;
return count;
}
并查看:https://gist.github.com/powturbo for和avx2 implementation。