可能加快字节解析速度
本文关键字:速度 字节 | 更新日期: 2023-09-27 17:57:43
我们正在项目中进行一些性能优化,使用探查器,我得到了以下方法:
private int CalculateAdcValues(byte lowIndex)
{
byte middleIndex = (byte)(lowIndex + 1);
byte highIndex = (byte)(lowIndex + 2);
// samples is a byte[]
retrun (int)((int)(samples[highIndex] << 24)
+ (int)(samples[middleIndex] << 16) + (int)(samples[lowIndex] << 8));
}
这种方法已经很快了,每次执行约1µs,但每秒调用约100.000次,因此占用约10%的CPU。
有人知道如何进一步改进这种方法吗
编辑:
当前解决方案:
fixed (byte* p = samples)
{
for (; loopIndex < 61; loopIndex += 3)
{
adcValues[k++] = *((int*)(p + loopIndex)) << 8;
}
}
这需要<40%的时间("整个方法"之前每次调用大约需要35µs,现在大约需要13µs)。for
-循环实际花费的时间比现在的计算要长。。。
我强烈怀疑,在转换为byte
之后,您的索引无论如何都会转换回int
,以便在数组索引操作中使用。这将是便宜的,但可能不是完全免费的。因此,去掉强制转换,除非您使用对byte
的转换来有效地获得0..255范围内的索引。在这一点上,您也可以去掉单独的局部变量。
此外,对int
的强制转换没有操作,因为移位操作仅在int
及更高类型上定义。
最后,使用|
可能比+
:更快
private int CalculateAdcValues(byte lowIndex)
{
return (samples[lowIndex + 2] << 24) |
(samples[lowIndex + 1] << 16) |
(samples[lowIndex] << 8);
}
(为什么底部8位中什么都没有?这是故意的吗?请注意,如果samples[lowIndex + 2]
设置了顶部位,结果将为负-可以吗?)
看到您有一个友好的endianes,请转到unsafe
unsafe int CalculateAdcValuesFast1(int lowIndex)
{
fixed (byte* p = &samples[lowIndex])
{
return *(int*)p << 8;
}
}
在x86上大约快30%。没有我希望的那么多收获。在x64上时约为40%。
如@CodeInChaos建议:
var bounds = samples.Length - 3;
fixed (byte* p = samples)
{
for (int i = 0; i < 1000000000; i++)
{
var r = CalculateAdcValuesFast2(p, i % bounds); // about 2x faster
// or inlined:
var r = *((int*)(p + i % bounds)) << 8; // about 3x faster
// do something
}
}
unsafe object CalculateAdcValuesFast2(byte* p1, int p2)
{
return *((int*)(p1 + p2)) << 8;
}
可能跟得快一点。我已将强制转换为integer。
var middleIndex = (byte)(lowIndex + 1);
var highIndex = (byte)(lowIndex + 2);
return (this.samples[highIndex] << 24) + (this.samples[middleIndex] << 16) + (this.samples[lowIndex] << 8);