有什么方法可以影响编写C#代码的指令级并行性?换句话说,有没有办法可以“帮助”编译器生成最能利用ILP的代码?我问这个是因为我试图从机器架构的一些概念中抽象出来,我需要知道这是否可行。如果没有,那么我将有理由从ILP中抽象出来。
编辑:您会注意到我不想以任何方式使用C#来利用ILP。我的问题恰恰相反。释义:“我希望没有办法从C#中利用ILP”
感谢。
答案 0 :(得分:1)
ILP是CPU的一项功能。你无法控制它。 编译器通过打破依赖链来尽力利用它。
这可能包括.Net JIT编译器,但我没有证据证明这一点。
答案 1 :(得分:0)
在获得指令级并行性时,您将受JIT的支配。 谁知道JIT实际上做了哪些优化?如果我真的需要,我会选择另一种语言,比如C ++。
为了最好地利用ILP,您需要打破依赖链。这应该仍然适用。请参阅此thread。
然而,在所有的抽象中,我怀疑在最极端的情况下仍然可以有效地利用它。你需要什么样的例子?
答案 2 :(得分:0)
没有明确或直接的方法来影响或暗示IL或C#中的.NET编译器来执行此操作。这完全是编译器的工作。
您可以对此进行的唯一影响是构建您的程序,以便更有可能(尽管不能保证)为您执行此操作,并且很难知道它是否甚至对结构起作用或不。这很好地抽象了.NET语言和IL。
答案 3 :(得分:0)
您可以在CLI中使用ILP。所以简短的回答是否。
再长一点:
之前我为一个简单的图像处理任务编写了一个代码,并使用这种优化来使我的代码“更快”。
一个“简短”的例子:
static void Main( string[] args )
{
const int ITERATION_NUMBER = 100;
TimeSpan[] normal = new TimeSpan[ITERATION_NUMBER];
TimeSpan[] ilp = new TimeSpan[ITERATION_NUMBER];
int SIZE = 4000000;
float[] data = new float[SIZE];
float safe = 0.0f;
//Normal for
Stopwatch sw = new Stopwatch();
for (int iteration = 0; iteration < ITERATION_NUMBER; iteration++)
{
//Initialization
for (int i = 0; i < data.Length; i++)
{
data[i] = 1.0f;
}
sw.Start();
for (int index = 0; index < data.Length; index++)
{
data[index] /= 3.0f * data[index] > 2.0f / data[index] ? 2.0f / data[index] : 3.0f * data[index];
}
sw.Stop();
normal[iteration] = sw.Elapsed;
safe = data[0];
//Initialization
for (int i = 0; i < data.Length; i++)
{
data[i] = 1.0f;
}
sw.Reset();
//ILP For
sw.Start();
float ac1, ac2, ac3, ac4;
int length = data.Length / 4;
for (int i = 0; i < length; i++)
{
int index0 = i << 2;
int index1 = index0;
int index2 = index0 + 1;
int index3 = index0 + 2;
int index4 = index0 + 3;
ac1 = 3.0f * data[index1] > 2.0f / data[index1] ? 2.0f / data[index1] : 3.0f * data[index1];
ac2 = 3.0f * data[index2] > 2.0f / data[index2] ? 2.0f / data[index2] : 3.0f * data[index2];
ac3 = 3.0f * data[index3] > 2.0f / data[index3] ? 2.0f / data[index3] : 3.0f * data[index3];
ac4 = 3.0f * data[index4] > 2.0f / data[index4] ? 2.0f / data[index4] : 3.0f * data[index4];
data[index1] /= ac1;
data[index2] /= ac2;
data[index3] /= ac3;
data[index4] /= ac4;
}
sw.Stop();
ilp[iteration] = sw.Elapsed;
sw.Reset();
}
Console.WriteLine(data.All(item => item == data[0]));
Console.WriteLine(data[0] == safe);
Console.WriteLine();
double normalElapsed = normal.Max(time => time.TotalMilliseconds);
Console.WriteLine(String.Format("Normal Max.: {0}", normalElapsed));
double ilpElapsed = ilp.Max(time => time.TotalMilliseconds);
Console.WriteLine(String.Format("ILP Max.: {0}", ilpElapsed));
Console.WriteLine();
normalElapsed = normal.Average(time => time.TotalMilliseconds);
Console.WriteLine(String.Format("Normal Avg.: {0}", normalElapsed));
ilpElapsed = ilp.Average(time => time.TotalMilliseconds);
Console.WriteLine(String.Format("ILP Avg.: {0}", ilpElapsed));
Console.WriteLine();
normalElapsed = normal.Min(time => time.TotalMilliseconds);
Console.WriteLine(String.Format("Normal Min.: {0}", normalElapsed));
ilpElapsed = ilp.Min(time => time.TotalMilliseconds);
Console.WriteLine(String.Format("ILP Min.: {0}", ilpElapsed));
}
结果是(在.Net framework 4.0 Client profile上,发布):
在虚拟机上(我认为没有ILP):
真 真
Nor Max。:111,1894
ILP Max。:106,886
Nor Avg。:78,163619
ILP平均值:77,682513
Nor Min。:58,3035
最近的ILP:56,7672
在氙气上:
真 真
Nor Max。:40,5892
ILP Max。:30,8906
Nor Avg。:35,637308
ILP平均值:25,45341
Nor Min。:34,4247
最近的ILP:23,7888
结果说明:
在Debug中,编译器没有应用opication,但第二个for循环比第一个更优化,因此存在显着差异。
答案似乎是在发布模式构建程序集的执行结果中。 IL编译器/ JIT-er最好尽量减少性能消耗(我认为甚至是ILP)。但是,无论你是否制作类似第二个for循环的代码,你都可以在特殊情况下获得更好的结果,而第二个循环可以在某些架构上超过第一个循环。但是
可悲的是,如上所述。可悲的是,没有提及实现可以定义更多优化,如ILP(可以在规范中放置一个简短的段落)。但是他们无法枚举代码的各种形式的构建验证,而且CLI处于更高层次:你受JIT的支配
这很好地抽象了.NET语言和IL。
这是一个非常复杂的问题,只能以实验方式回答它。我不认为我们可以通过这样的方式得到更精确的回答。我认为这个问题具有误导性,因为它不依赖于C#,它取决于CLI的实现。
可能会有很多影响因素,在我们将其视为黑盒子之前,很难正确回答像JIT这样的问题。
我在第512-513页上找到了关于循环矢量化和自动读取的内容: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf
我认为他们没有明确说明JIT-er在这种情况下需要如何表现,而且必须选择优化方式。所以我认为你可以影响,如果你可以编写更优的代码,JIT将尽可能使用ILP。
我认为,因为他们没有指明,有可能。
所以答案似乎不是。我相信如果规范没有说明,你不能在CLI的情况下从ILP中抽象出来。
<强>更新强>:
之前我发现了一篇博文,但直到现在我才发现它: http://igoro.com/archive/gallery-of-processor-cache-effects/ 示例四包含一个简短但适当的答案。