是否有针对C#28时间内联限制的解决方法?

时间:2011-04-27 07:48:57

标签: c# .net optimization .net-4.0

我正在使用Red Gate的Performance Profiler优化物理模拟程序。处理碰撞检测的代码的一部分有大约52个以下的小检查,在两个案例中处理3维26个方向的细胞。

CollisionPrimitiveList cell = innerGrid[cellIndex + 1];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

cell = innerGrid[cellIndex + grid.XExtent];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

cell = innerGrid[cellIndex + grid.XzLayerSize];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

作为程序的一个非常紧凑的循环,所有这一切都必须采用相同的方法,但是在我将区域从两个维度扩展到三维之后,我突然发现了这一点(将计数从上升到52个16),突然cell.Count不再被内联,即使它是一个简单的吸气剂。 public int Count { get { return count; } } 这引起了巨大的性能损失,我花了相当长的时间才发现,当cell.Count出现在方法中28次或更少时,它每次都被内联,但一旦cell.Count出现在方法中29次或更多次,它没有一次内联(尽管绝大多数调用都是来自极少情况的代码部分很少被执行。)

回到我的问题,是否有人有任何想法绕过这个限制?我认为简单的解决方案只是使计数字段内部而非私密,但我想要一个比这更好的解决方案,或者至少只是更好地了解情况。我希望微软在http://msdn.microsoft.com/en-us/library/ms973858.aspx编写高性能管理应用程序页面上会提到这类事情,但遗憾的是它不是(可能是因为28计数限制有多么武断?)

我使用的是.NET 4.0。

编辑:看起来我误解了我的小测试。我发现内联失败不是因为方法本身被调用了28次以上,而是因为它们应该被内联到的方法被一些标准“太长”了。这仍然让我感到困惑,因为我没有看到一个简单的getter如何理性地没有内联(并且我的分析器清楚地向我显示了内联的性能明显更好),但显然CLI JIT编译器拒绝内联任何东西只是因为这个方法已经很大了(玩了一些细微的变化表明我这个限制是1500的代码大小(来自idasm),超过这个限制没有内联,即使在我的getter的情况下,一些测试显示没有添加额外的代码要内联的开销。)

谢谢。

3 个答案:

答案 0 :(得分:4)

我还没有对此进行过测试,但似乎有一种可能的解决方法是让多个属性都返回相同的东西。可以想象,每个属性可以获得28个内联。

请注意,内联方法的次数很可能取决于该方法的本机代码的大小(请参阅http://blogs.msdn.com/b/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx),数字28特定于该属性。一个简单的属性可能比一个更复杂的方法内联更多次。

答案 1 :(得分:1)

直接关闭,这并不能解释为什么28是神奇数字,但我很好奇如果你将所有候选CollisionListPrimitive实例整理成一个数组,然后调用你的“if count> 0”块会发生什么在数组的循环中?

然后,cell.Count调用再次内联吗?

e.g。

CollisionPrimitiveList[] cells = new CollisionPrimitiveList {
    innerGrid[cellIndex + 1],
    innerGrid[cellIndex + grid.XExtent],
    innerGrid[cellIndex + grid.XzLayerSize]
    // and all the rest
};

// Loop over cells - for demo only. Use for loop or LINQ'ify if faster
foreach (CollisionPrimitiveList cell in cells) 
{
    if (cell.Count > 0)
        contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);  
}

我知道性能是问题,你将有构建数组和循环的开销,但如果cell.Count再次内联,那么整体性能是否仍然更好/更好?

答案 2 :(得分:0)

我猜测(虽然绝不是积极的)这可能与提到的enregistration问题有关 - CLR可能为每个if语句分配一个新变量,而那些是超过总共64个变量。你认为情况可能如此吗?