ভূমিকা: আমি সি # তে উচ্চ-সম্পাদন কোড লিখি write হ্যাঁ, আমি জানি সি ++ আমাকে আরও ভাল অপ্টিমাইজেশন দেবে, তবে আমি এখনও সি # ব্যবহার করতে পছন্দ করি। আমি সেই পছন্দটি নিয়ে বিতর্ক করতে চাই না। পরিবর্তে, আমি তাদের কাছ থেকে শুনতে চাই যারা আমার মতো,। নেট ফ্রেমওয়ার্কে উচ্চ-পারফরম্যান্স কোড লেখার চেষ্টা করছেন।
প্রশ্নসমূহ:
- কোডে অপারেটর কেন সমতুল্য পদ্ধতি কলের চেয়ে ধীর হয় ??
- অভ্যন্তরে দুটি ডাবল রয়েছে এমন স্ট্রাক্টকে পাস করার সমতুল্য পদ্ধতির তুলনায় নীচের কোডে দুটি দ্বিগুণ পাস করার পদ্ধতিটি কেন? (এ: পুরানো জেআইটিগুলি স্ট্রিটগুলি দুর্বলভাবে অনুকূল করেছে)
- কাঠামোর সদস্যদের মতো দক্ষ স্ট্রাক্টকে দক্ষতার সাথে চিকিত্সার জন্য। নেট জেআইটি সংকলক পাওয়ার কোনও উপায় আছে কি? (এ: আরও নতুন জেআইটি পান)
আমি যা জানি আমি জানি: আসল। নেট জেআইটি সংকলক কোনও কাঠামোর সাথে জড়িত এমন কোনও কিছুকে ইনলাইন করবে না। উদ্ভট প্রদত্ত স্ট্রাক্ট কেবল তখনই ব্যবহার করা উচিত যেখানে আপনার ছোট মান ধরণের প্রয়োজন যা বিল্ট-ইনগুলির মতো অনুকূলিত হওয়া উচিত তবে সত্য। ভাগ্যক্রমে, .NET 3.5SP1 এবং .NET 2.0SP2 এ, তারা জেআইটি অপ্টিমাইজারে কিছু উন্নতি করেছে, বিশেষত স্ট্রাইকগুলির জন্য ইনলাইনিংয়ের উন্নতি সহ। (আমি অনুমান করছি তারা এগুলি করেছে কারণ অন্যথায় তারা যে নতুন কমপ্লেক্স কাঠামোটি প্রবর্তন করছিল তা ভয়াবহভাবে পারফরম্যান্স করত ... সুতরাং কমপ্লেক্স টিম সম্ভবত জেআইটি অপ্টিমাইজার দলের দিকে ঝুঁকছে)) সুতরাং, নেট 3.5 এসপি 1 এর পূর্বে যে কোনও ডকুমেন্টেশন সম্ভবত এই সমস্যাটির সাথে খুব প্রাসঙ্গিক নয়।
আমার পরীক্ষাটি কী দেখায়: আমি সি: \ উইন্ডোজ \ মাইক্রোসফ্ট.নোট \ ফ্রেমওয়ার্ক \ v2.0.50727 \ mscorwks.dll ফাইলের সংস্করণ> = 3053 আছে এবং যাচাই করেছিলাম যা যাচাই করে আমি নতুন JIT অপ্টিমাইজার পেয়েছি তা যাচাই করেছি জেআইটি অপ্টিমাইজারের কাছে যাইহোক, এমনকি এটির সাথে, আমার সময়গুলি এবং ডিসঅাসেপশন উভয় শোতে কী দেখায়:
দুটি ডাবলস সহ স্ট্রাক্ট পাসের জন্য জেআইটি-প্রণীত কোডটি কোডের তুলনায় খুব কম দক্ষ যা সরাসরি দুটি ডাবলকে পাস করে।
কোনও কাঠামো পদ্ধতির জন্য জেআইটি-প্রণীত কোডটি আপনি যুক্তি হিসাবে কোনও কাঠামো পাস করেছেন তার চেয়ে অনেক বেশি দক্ষতার সাথে 'এই' এ পাস করে।
একটি লুপে স্পষ্ট হওয়ার কারণে গুণক সহ এমনকি দুটি ডাবলসের সাথে একটি কাঠামো পাস করার চেয়ে আপনি দুটি ডাবল পাস করলেও জেআইটি আরও ভাল ইনলাইন করে।
সময়গুলি: প্রকৃতপক্ষে, বিচ্ছিন্নতার দিকে তাকিয়ে আমি বুঝতে পারি যে লুপগুলির বেশিরভাগ সময় কেবল তালিকার বাইরে টেস্টের ডেটা অ্যাক্সেস করে। যদি আপনি লুপের ওভারহেড কোড এবং ডেটা অ্যাক্সেসের অধ্যায় নির্ধারণ করেন তবে একই কল করার চারটি পদ্ধতির মধ্যে পার্থক্য নাটকীয়ভাবে আলাদা different আমি PlusEqual (এলিমেন্ট) এর পরিবর্তে PlusEqual (ডাবল, ডাবল) করার জন্য 5x থেকে 20x স্পিডআপগুলি যে কোনও জায়গায় পেতে পারি। অপারেটর + = এর পরিবর্তে PlusEqual (ডাবল, ডাবল) করার জন্য 10x থেকে 40x। কি দারুন. দু: খিত।
এখানে সময় নির্ধারিত এক সেট:
Populating List<Element> took 320ms.
The PlusEqual() method took 105ms.
The 'same' += operator took 131ms.
The 'same' -= operator took 139ms.
The PlusEqual(double, double) method took 68ms.
The do nothing loop took 66ms.
The ratio of operator with constructor to method is 124%.
The ratio of operator without constructor to method is 132%.
The ratio of PlusEqual(double,double) to PlusEqual(Element) is 64%.
If we remove the overhead time for the loop accessing the elements from the List...
The ratio of operator with constructor to method is 166%.
The ratio of operator without constructor to method is 187%.
The ratio of PlusEqual(double,double) to PlusEqual(Element) is 5%.
কোড:
namespace OperatorVsMethod
{
public struct Element
{
public double Left;
public double Right;
public Element(double left, double right)
{
this.Left = left;
this.Right = right;
}
public static Element operator +(Element x, Element y)
{
return new Element(x.Left + y.Left, x.Right + y.Right);
}
public static Element operator -(Element x, Element y)
{
x.Left += y.Left;
x.Right += y.Right;
return x;
}
/// <summary>
/// Like the += operator; but faster.
/// </summary>
public void PlusEqual(Element that)
{
this.Left += that.Left;
this.Right += that.Right;
}
/// <summary>
/// Like the += operator; but faster.
/// </summary>
public void PlusEqual(double thatLeft, double thatRight)
{
this.Left += thatLeft;
this.Right += thatRight;
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Stopwatch stopwatch = new Stopwatch();
// Populate a List of Elements to multiply together
int seedSize = 4;
List<double> doubles = new List<double>(seedSize);
doubles.Add(2.5d);
doubles.Add(100000d);
doubles.Add(-0.5d);
doubles.Add(-100002d);
int size = 2500000 * seedSize;
List<Element> elts = new List<Element>(size);
stopwatch.Reset();
stopwatch.Start();
for (int ii = 0; ii < size; ++ii)
{
int di = ii % seedSize;
double d = doubles[di];
elts.Add(new Element(d, d));
}
stopwatch.Stop();
long populateMS = stopwatch.ElapsedMilliseconds;
// Measure speed of += operator (calls ctor)
Element operatorCtorResult = new Element(1d, 1d);
stopwatch.Reset();
stopwatch.Start();
for (int ii = 0; ii < size; ++ii)
{
operatorCtorResult += elts[ii];
}
stopwatch.Stop();
long operatorCtorMS = stopwatch.ElapsedMilliseconds;
// Measure speed of -= operator (+= without ctor)
Element operatorNoCtorResult = new Element(1d, 1d);
stopwatch.Reset();
stopwatch.Start();
for (int ii = 0; ii < size; ++ii)
{
operatorNoCtorResult -= elts[ii];
}
stopwatch.Stop();
long operatorNoCtorMS = stopwatch.ElapsedMilliseconds;
// Measure speed of PlusEqual(Element) method
Element plusEqualResult = new Element(1d, 1d);
stopwatch.Reset();
stopwatch.Start();
for (int ii = 0; ii < size; ++ii)
{
plusEqualResult.PlusEqual(elts[ii]);
}
stopwatch.Stop();
long plusEqualMS = stopwatch.ElapsedMilliseconds;
// Measure speed of PlusEqual(double, double) method
Element plusEqualDDResult = new Element(1d, 1d);
stopwatch.Reset();
stopwatch.Start();
for (int ii = 0; ii < size; ++ii)
{
Element elt = elts[ii];
plusEqualDDResult.PlusEqual(elt.Left, elt.Right);
}
stopwatch.Stop();
long plusEqualDDMS = stopwatch.ElapsedMilliseconds;
// Measure speed of doing nothing but accessing the Element
Element doNothingResult = new Element(1d, 1d);
stopwatch.Reset();
stopwatch.Start();
for (int ii = 0; ii < size; ++ii)
{
Element elt = elts[ii];
double left = elt.Left;
double right = elt.Right;
}
stopwatch.Stop();
long doNothingMS = stopwatch.ElapsedMilliseconds;
// Report results
Assert.AreEqual(1d, operatorCtorResult.Left, "The operator += did not compute the right result!");
Assert.AreEqual(1d, operatorNoCtorResult.Left, "The operator += did not compute the right result!");
Assert.AreEqual(1d, plusEqualResult.Left, "The operator += did not compute the right result!");
Assert.AreEqual(1d, plusEqualDDResult.Left, "The operator += did not compute the right result!");
Assert.AreEqual(1d, doNothingResult.Left, "The operator += did not compute the right result!");
// Report speeds
Console.WriteLine("Populating List<Element> took {0}ms.", populateMS);
Console.WriteLine("The PlusEqual() method took {0}ms.", plusEqualMS);
Console.WriteLine("The 'same' += operator took {0}ms.", operatorCtorMS);
Console.WriteLine("The 'same' -= operator took {0}ms.", operatorNoCtorMS);
Console.WriteLine("The PlusEqual(double, double) method took {0}ms.", plusEqualDDMS);
Console.WriteLine("The do nothing loop took {0}ms.", doNothingMS);
// Compare speeds
long percentageRatio = 100L * operatorCtorMS / plusEqualMS;
Console.WriteLine("The ratio of operator with constructor to method is {0}%.", percentageRatio);
percentageRatio = 100L * operatorNoCtorMS / plusEqualMS;
Console.WriteLine("The ratio of operator without constructor to method is {0}%.", percentageRatio);
percentageRatio = 100L * plusEqualDDMS / plusEqualMS;
Console.WriteLine("The ratio of PlusEqual(double,double) to PlusEqual(Element) is {0}%.", percentageRatio);
operatorCtorMS -= doNothingMS;
operatorNoCtorMS -= doNothingMS;
plusEqualMS -= doNothingMS;
plusEqualDDMS -= doNothingMS;
Console.WriteLine("If we remove the overhead time for the loop accessing the elements from the List...");
percentageRatio = 100L * operatorCtorMS / plusEqualMS;
Console.WriteLine("The ratio of operator with constructor to method is {0}%.", percentageRatio);
percentageRatio = 100L * operatorNoCtorMS / plusEqualMS;
Console.WriteLine("The ratio of operator without constructor to method is {0}%.", percentageRatio);
percentageRatio = 100L * plusEqualDDMS / plusEqualMS;
Console.WriteLine("The ratio of PlusEqual(double,double) to PlusEqual(Element) is {0}%.", percentageRatio);
}
}
}
আইএল: (উপরের কিছুতে কী সংকলিত হয়)
public void PlusEqual(Element that)
{
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,30h
00000009 xor eax,eax
0000000b mov dword ptr [ebp-10h],eax
0000000e xor eax,eax
00000010 mov dword ptr [ebp-1Ch],eax
00000013 mov dword ptr [ebp-3Ch],ecx
00000016 cmp dword ptr ds:[04C87B7Ch],0
0000001d je 00000024
0000001f call 753081B1
00000024 nop
this.Left += that.Left;
00000025 mov eax,dword ptr [ebp-3Ch]
00000028 fld qword ptr [ebp+8]
0000002b fadd qword ptr [eax]
0000002d fstp qword ptr [eax]
this.Right += that.Right;
0000002f mov eax,dword ptr [ebp-3Ch]
00000032 fld qword ptr [ebp+10h]
00000035 fadd qword ptr [eax+8]
00000038 fstp qword ptr [eax+8]
}
0000003b nop
0000003c lea esp,[ebp-0Ch]
0000003f pop ebx
00000040 pop esi
00000041 pop edi
00000042 pop ebp
00000043 ret 10h
public void PlusEqual(double thatLeft, double thatRight)
{
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,30h
00000009 xor eax,eax
0000000b mov dword ptr [ebp-10h],eax
0000000e xor eax,eax
00000010 mov dword ptr [ebp-1Ch],eax
00000013 mov dword ptr [ebp-3Ch],ecx
00000016 cmp dword ptr ds:[04C87B7Ch],0
0000001d je 00000024
0000001f call 75308159
00000024 nop
this.Left += thatLeft;
00000025 mov eax,dword ptr [ebp-3Ch]
00000028 fld qword ptr [ebp+10h]
0000002b fadd qword ptr [eax]
0000002d fstp qword ptr [eax]
this.Right += thatRight;
0000002f mov eax,dword ptr [ebp-3Ch]
00000032 fld qword ptr [ebp+8]
00000035 fadd qword ptr [eax+8]
00000038 fstp qword ptr [eax+8]
}
0000003b nop
0000003c lea esp,[ebp-0Ch]
0000003f pop ebx
00000040 pop esi
00000041 pop edi
00000042 pop ebp
00000043 ret 10h