C# 我如何充分了解CLR,以便对性能问题做出有根据的猜测?
是的,我使用的是分析器(ANTS)。但在微观层面,它无法告诉你如何解决问题。我现在正处于微观优化阶段。例如,我分析了以下内容:C# 我如何充分了解CLR,以便对性能问题做出有根据的猜测?,c#,.net,performance,optimization,clr,C#,.net,Performance,Optimization,Clr,是的,我使用的是分析器(ANTS)。但在微观层面,它无法告诉你如何解决问题。我现在正处于微观优化阶段。例如,我分析了以下内容: for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { packedCells.Add(Data[x, y].HasCar); packedCells.Add(Data[x, y].RoadState); pack
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
packedCells.Add(Data[x, y].HasCar);
packedCells.Add(Data[x, y].RoadState);
packedCells.Add(Data[x, y].Population);
}
}
for(int x=0;x
ANTS显示y型环线需要花费大量时间。我认为这是因为它必须不断地称之为“高度获得者”。所以我创建了一个本地intheight=height
在循环之前,并进行内循环检查,查看是否有y
。这实际上使性能更差!蚂蚁现在告诉我x环线是个问题。嗯?这应该是无关紧要的,这是外环
最终我得到了一个启示——可能使用一个属性作为外部循环边界,使用一个本地属性作为内部循环边界,使得CLR经常在“本地”缓存和“这个指针”缓存之间跳转(我习惯于从CPU缓存的角度来思考)。所以我也做了一个局部的宽度,这就解决了它
从那以后,很明显,我也应该为数据创建一个local,即使数据甚至不是一个属性(它是一个字段)。事实上,这给我带来了更多的表现
然而,令人困惑的是,重新排列x和y循环(以提高缓存使用率)并没有带来任何区别,即使阵列很大(3000x3000)
现在,我想了解为什么我所做的事情提高了性能你建议我读什么书?杰弗里·里克特(Jeffrey Richter)
这是一本很棒的书,有人在我的图书馆里偷走了它。这里根本不涉及CLR,这本书应该被翻译成直接的机器代码,而不需要调用CLR。JIT编译器负责生成机器代码,它有一个优化器,试图产生最有效的代码。它有局限性,不能在上面花费大量时间 它所做的一件重要的事情是弄清楚哪些局部变量应该存储在CPU寄存器中。当你把Height属性放在一个局部变量中时,情况发生了变化。它可能决定将该变量存储在寄存器中。但现在,存储另一个变量的可用性减少了一个。就像x或y变量一样,对速度至关重要。是的,那会减慢速度 你对外环的诊断很差。这可能是由JIT优化器重新安排循环代码造成的,这使得分析器很难将机器代码映射回相应的C#语句 类似地,优化器可能会认为您使用数组效率低下,并将索引顺序切换回原处。不太确定它是否真的做到了,但也不是不可能 不管怎样,在这里你能获得一些洞察力的唯一方法就是查看生成的机器代码。关于x86汇编代码有很多不错的书,尽管现在可能有点难找到。您的起点是调试+Windows+反汇编 但是请记住,即使是机器代码也不能很好地预测代码的运行效率。现代CPU内核极其复杂,机器代码不再代表内核中实际发生的事情。唯一行之有效的方法就是你已经在做的事情:反复尝试
阿尔宾-不。老实说,我不认为在剖析器外运行会改变性能差异,所以我没有费心。你认为我应该这么做?你以前有过这样的问题吗?(不过,我在编译时对其进行了优化) 在调试器下运行会改变性能:在调试器下运行时,即时编译器会自动禁用优化(以使调试更容易)
如果必须,请使用调试器附加到已经运行的JITted进程。Hm,我认为循环注册不是真正的问题。 1.我尽量避免每个内部循环访问数组
数据三次。
2.我还建议,重新考虑三条Add
语句:显然,您要访问一个集合三次,以添加一些无关紧要的数据。使每次迭代只进行一次访问,并添加包含三个条目的数据类型:
for (int y = 0; ... {
tTemp = Data[x, y];
packedCells.Add(new {
tTemp.HasCar, tTemp.RoadState, tTemp.Population
});
}
从另一个角度来看,您基本上是通过将矩阵复制到数组(或其他顺序集合)来对矩阵进行矢量化。。。有必要吗?为什么不定义一个专门的索引器来模拟线性访问呢?更好的是,如果您只需要枚举条目(在该示例中,不需要随机访问),为什么不使用适当的LINQ表达式呢?关于使用数组,您应该知道的一点是,CLR将始终确保数组索引不超出范围。它对一维数组进行了优化,但对2+维数组没有优化
知道了这一点,您可能希望基准测试MyCell数据[][]
,而不是MyCell数据[],]
,因为注释可能会被监督,我重复我自己的话:优化代码本身就很麻烦。您根本不需要显式地线性化矩阵,请参见上面的注释:定义一个实现IEnumerable
的线性化适配器,并将其输入格式化程序
当我尝试添加另一个答案时,会收到警告,因此我将回收此答案:)在阅读了Steve的评论并思考了一会儿之后,我提出以下建议:
如果序列化多维数组的速度太慢(我还没有尝试过,我只是相信你…),就不要使用它!看起来,您的矩阵不是稀疏的,并且具有固定的维度。因此,将容纳单元格的结构定义为简单的线性阵列
[Serializable()]
class CellMatrix {
Cell [] mCells;
public int Rows { get; }
public int Columns { get; }
public Cell this (int i, int j) {
get {
return mCells[i + Rows * j];
}
// setter...
}
// constructor taking rows/cols...
}