මගේ කේතය වේගවත් කිරීමට උත්සාහ කරන්න?


1508

උත්සාහක දිනුම් වල බලපෑම පරීක්ෂා කිරීම සඳහා මම යම් කේතයක් ලිවුවෙමි, නමුත් පුදුම සහගත ප්‍රති .ල දැකීම.

static void Main(string[] args)
{
    Thread.CurrentThread.Priority = ThreadPriority.Highest;
    Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;

    long start = 0, stop = 0, elapsed = 0;
    double avg = 0.0;

    long temp = Fibo(1);

    for (int i = 1; i < 100000000; i++)
    {
        start = Stopwatch.GetTimestamp();
        temp = Fibo(100);
        stop = Stopwatch.GetTimestamp();

        elapsed = stop - start;
        avg = avg + ((double)elapsed - avg) / i;
    }

    Console.WriteLine("Elapsed: " + avg);
    Console.ReadKey();
}

static long Fibo(int n)
{
    long n1 = 0, n2 = 1, fibo = 0;
    n++;

    for (int i = 1; i < n; i++)
    {
        n1 = n2;
        n2 = fibo;
        fibo = n1 + n2;
    }

    return fibo;
}

මගේ පරිගණකයේ, මෙය නිරන්තරයෙන් අගය 0.96 ක් පමණ මුද්‍රණය කරයි.

මම ෆිබෝ () තුළ ඇති ෆෝ ලූපය මෙවැනි උත්සාහක දිනුම් බ්ලොක් එකකින් ඔතා ගත් විට:

static long Fibo(int n)
{
    long n1 = 0, n2 = 1, fibo = 0;
    n++;

    try
    {
        for (int i = 1; i < n; i++)
        {
            n1 = n2;
            n2 = fibo;
            fibo = n1 + n2;
        }
    }
    catch {}

    return fibo;
}

දැන් එය නිරන්තරයෙන් 0.69 මුද්‍රණය කරයි ... - එය සැබවින්ම වේගයෙන් ධාවනය වේ! නමුත් ඇයි?

සටහන: මම මෙය මුදා හැරීමේ වින්‍යාසය භාවිතයෙන් සම්පාදනය කර EXE ගොනුව සෘජුවම ධාවනය කළෙමි (විෂුවල් ස්ටුඩියෝවෙන් පිටත).

සංස්කරණය: ජෝන් Skeet ගේ විශිෂ්ට විශ්ලේෂණයක් උත්සාහක-අතට උඩ පන්දුවක් කෙසේ හෝ, x86 CLR (සහ මම ඒ ඇයි කියලා අපි තේරුම් ගැනීමට තවමත් හිතන්නේ) මෙම විශේෂ නඩුව වඩාත් හිතකර ආකාරයෙන් CPU ලේඛන භාවිතය හේතු වන බව පෙන්නුම් කළේය. X64 CLR ට මෙම වෙනසක් නොමැති බවත් එය x86 CLR ට වඩා වේගවත් බවත් ජෝන් සොයාගත් බව මම තහවුරු කළෙමි. intවර්ග වෙනුවට ෆයිබෝ ක්‍රමවේදය තුළ ඇති වර්ග භාවිතා කිරීමද මම පරීක්‍ෂා කළෙමි long, පසුව x86 CLR x64 CLR තරම් වේගවත් විය.


යාවත්කාලීන කිරීම: මෙම ගැටළුව රොස්ලින් විසින් විසඳා ඇති බව පෙනේ. එකම යන්ත්‍රය, එකම සීඑල්ආර් අනුවාදය - වීඑස් 2013 සමඟ සම්පාදනය කිරීමේදී ගැටළුව ඉහත පරිදි පවතී, නමුත් වීඑස් 2015 සමඟ සම්පාදනය කිරීමේදී ගැටළුව පහව යයි.


113
L ලොයිඩ් ඔහුගේ ප්‍රශ්නයට පිළිතුරක් ලබා ගැනීමට උත්සාහ කරයි "එය සැබවින්ම වේගයෙන් දිව යයි! නමුත් ඇයි?"
ඇන්ඩ්‍රියාස් නයිඩර්මෙයාර්

139
ඉතින්, දැන් "ගිලීමේ ව්‍යතිරේකයන්" නරක පුරුද්දක සිට හොඳ කාර්ය සාධන ප්‍රශස්තිකරණයකට සමත් විය: P
Luciano

2
මෙය පරීක්ෂා නොකළ හෝ පරීක්ෂා කරන ලද අංක ගණිතමය සන්දර්භයකද?
Random832

7
ras taras.roshko: මම එරික්ට අගෞරවයක් කිරීමට අකමැති වුවද, මෙය ඇත්ත වශයෙන්ම C # ප්‍රශ්නයක් නොවේ - එය JIT සම්පාදක ප්‍රශ්නයකි. එය ලෙස, x86 සඳහා JIT දරුවකුට / උඩ තොරව බොහෝ ලේඛන ලෙස භාවිතා නොවන ඇයි අවසාන අපහසු පිටතට වැඩ සමග එම උත්සාහක / උඩ වාරණ.
ජෝන් ස්කීට්

66
මිහිරි, ඉතින් අපි මේ උත්සාහක දිනුම් කූඩු දැමුවහොත් අපට ඊටත් වඩා වේගයෙන් යා හැකිද?
චක් පින්කර්ට්

Answers:


1057

එකක් Roslyn අඩුක්කුව භාවිතය පිළිබඳ අවබෝධය ප්රශස්තිකරණය විශේෂඥයකු වන ඉංජිනේරුවන් මට මේ හා වාර්තා දෙස ගෙන සී # සම්පාදක දේශීය විචල්ය ගබඩා, මාර්ගය ජනනය මාර්ගය අතර අන්තර් දී මෙහි ගැටලුවකි බව JIT සම්පාදක ලේඛනය කරන්නේ අනුරූප x86 කේතයේ උපලේඛනගත කිරීම. මෙහි ප්‍රති result ලය වනුයේ ප්‍රදේශවාසීන්ගේ පැටවුම් සහ වෙළඳසැල්වල උප ප්‍රශස්ත කේත උත්පාදනය කිරීමයි.

කිසියම් හේතුවක් නිසා අප සැමට අපැහැදිලි නිසා, අවහිරතා උත්සාහක ආරක්ෂිත කලාපයක පවතින බව JITter දැනගත් විට ගැටළු සහගත කේත උත්පාදනය කිරීමේ මාර්ගය මඟ හැරේ.

මේක හරිම අමුතුයි. අපි JITter කණ්ඩායම සමඟ පසු විපරම් කර දෝෂයක් ඇතුලත් කර ගත හැකිදැයි බලමු එවිට ඔවුන්ට මෙය නිවැරදි කළ හැකිය.

එසේම, අපි රොස්ලින් සඳහා සී # සහ වීබී සම්පාදකයින්ගේ ඇල්ගොරිතම වැඩිදියුණු කිරීම සඳහා කටයුතු කරමින් සිටිමු. සක්‍රිය කිරීමේ කාලය. මීට පෙර ප්‍රදේශවාසීන් “මළ” බවට පත් කළ හැක්කේ කවදාද යන්න පිළිබඳව වඩා හොඳ ඉඟි ලබා දෙන්නේ නම්, රෙජිස්ටර් වෙන් කිරීම හා වඩා හොඳ කාර්යයක් කිරීමට ජිටර්ට හැකි වනු ඇතැයි අපි විශ්වාස කරමු.

මෙය අපගේ අවධානයට යොමු කිරීම ගැන ස්තූතියි, සහ අමුතු හැසිරීම ගැන සමාව ඉල්ලන්න.


8
සී # සම්පාදකයා මෙතරම් බාහිර දේශීයයන් ජනනය කරන්නේ මන්දැයි මම නිතරම කල්පනා කළෙමි. නිදසුනක් ලෙස, නව අරාව ආරම්භක ප්‍රකාශන සෑම විටම දේශීය ජනනය කරයි, නමුත් කිසි විටෙකත් දේශීයව ජනනය කිරීමට අවශ්‍ය නොවේ. මැනිය හැකි තරම් ක්‍රියාකාරී කේතයක් නිපදවීමට එය ජිටර්ට ඉඩ දෙන්නේ නම්, සමහර විට සී # සම්පාදකයා අනවශ්‍ය දේශීය ජනනය කිරීම ගැන මඳක් සැලකිලිමත් විය යුතුය ...
ටිම්වි

33
Im තිම්වි: නියත වශයෙන්ම. භාවිතයට නොගත් කේතයක් තුළ, සම්පාදකයා විසින් අනවශ්‍ය දේශීයයන් විශාල අතහැර දැමීමක් සිදු කරයි. ප්‍රශස්තිකරණය කළ කේතයේ දී අනවශ්‍ය තාවකාලිකයන් හැකි නම් ඉවත් කළ යුතුය. අවාසනාවකට මෙන්, තාවකාලිකව තුරන් කිරීමේ ප්‍රශස්තකරණය අහම්බෙන් ඉවත් කළ වසර ගණනාවක් තිස්සේ අපට බොහෝ දෝෂ තිබේ. ඉහත සඳහන් කළ ඉංජිනේරුවරයා මුල සිටම රොස්ලින් සඳහා මෙම කේත සියල්ලම සම්පූර්ණයෙන්ම ප්‍රතිනිර්මාණය කරමින් සිටින අතර, එහි ප්‍රති result ලයක් ලෙස අප රොස්ලින් කේත උත්පාදක යන්ත්රය තුළ වැඩි දියුණු කළ ප්‍රශස්ත හැසිරීමක් තිබිය යුතුය.
එරික් ලිපර්ට්

24
මෙම ගැටලුව සම්බන්ධයෙන් කිසියම් ව්‍යාපාරයක් කවදා හෝ සිදුවී තිබේද?
රොබට් හාවි

10
රොස්ලින් එය නිවැරදි කළ බව පෙනේ.
එරන් අර්සන්මේස්

56
එය "ජිටර් දෝෂයක්" ලෙස හැඳින්වීමේ අවස්ථාව ඔබට මග හැරුණි.
mbomb007

734

හොඳයි, ඔබ කාලය ගත කරන ආකාරය මට හරිම නපුරුයි. මුළු ලූපයටම කාලය යෙදවීම වඩා සංවේදී වනු ඇත:

var stopwatch = Stopwatch.StartNew();
for (int i = 1; i < 100000000; i++)
{
    Fibo(100);
}
stopwatch.Stop();
Console.WriteLine("Elapsed time: {0}", stopwatch.Elapsed);

ඒ ආකාරයෙන් ඔබ ඉතා කුඩා වේලාවන්, පාවෙන ලක්ෂ්‍ය ගණිතය සහ සමුච්චිත දෝෂ වල අනුකම්පාව නොදක්වයි.

එම වෙනස සිදු කිරීමෙන් පසුව, "අල්ලා නොගන්නා" අනුවාදය "ඇල්ලීමේ" අනුවාදයට වඩා මන්දගාමී දැයි බලන්න.

සංස්කරණය කරන්න: හරි, මම එය මා විසින්ම උත්සාහ කර ඇත්තෙමි. හරිම අමුතුයි. උත්සාහය / ඇල්ලීම නරක ඉන්ලයින් අක්‍රීය කරන්නේ දැයි මම කල්පනා කළෙමි, නමුත් [MethodImpl(MethodImplOptions.NoInlining)]ඒ වෙනුවට භාවිතා කිරීම උදව් කළේ නැත ...

මූලික වශයෙන් ඔබ cordbg යටතේ ඇති ප්‍රශස්ත JITted කේතය දෙස බැලිය යුතුය, මම සැක කරමි ...

සංස්කරණය කරන්න: තවත් තොරතුරු කිහිපයක්:

  • උත්සාහය / ඇල්ලීම n++;රේඛාව වටා තැබීම තවමත් කාර්ය සාධනය වැඩි දියුණු කරයි, නමුත් එය මුළු කොටස වටා තැබීම තරම් නොවේ
  • ඔබ විශේෂිත ව්‍යතිරේකයක් අල්ලා ගන්නේ නම් ( ArgumentExceptionමගේ පරීක්ෂණ වලදී) එය තවමත් වේගවත්ය
  • ඔබ ව්‍යතිරේකය ඇල්ලීමේ කොටසෙහි මුද්‍රණය කළහොත් එය තවමත් වේගවත් ය
  • ඔබ ඇල්ලීමේ කොටසෙහි ව්‍යතිරේකය නැවත සලකා බැලුවහොත් එය නැවතත් මන්දගාමී වේ
  • ඔබ අල්ලා ගැනීමේ වාරණයක් වෙනුවට අවසාන වාරණයක් භාවිතා කරන්නේ නම් එය නැවතත් මන්දගාමී වේ
  • ඔබ අවසාන වාරණයක් මෙන්ම ඇල්ලීමේ වාරණයක් භාවිතා කරන්නේ නම් එය වේගවත්ය

අමුතු ...

සංස්කරණය කරන්න: හරි, අපි විසුරුවා හැරියා ...

මෙය C # 2 සම්පාදකය සහ .NET 2 (32-බිට්) CLR භාවිතා කරමින් mdbg සමඟ විසුරුවා හරිනු ලැබේ (මගේ යන්ත්‍රයේ කෝඩ්බීජී නොමැති බැවින්). නිදොස්කරණය යටතේ වුවද, මම තවමත් එකම කාර්ය සාධන බලපෑම් දකිමි. වේගවත් අනුවාදය හසුරුවන්නෙකු tryසමඟ විචල්‍ය ප්‍රකාශන සහ ආපසු ප්‍රකාශය අතර සෑම දෙයක්ම අවහිර කරයි catch{}. නිසැකවම මන්දගාමී අනුවාදය උත්සාහය / අල්ලා ගැනීම හැරෙන්නට සමාන වේ. ඇමතුම් කේතය (එනම් ප්‍රධාන) අවස්ථා දෙකෙහිම එක හා සමාන වන අතර එකලස් කිරීමේ නියෝජනයක් ඇත (එබැවින් එය ආශ්‍රිත ගැටළුවක් නොවේ).

වේගවත් අනුවාදය සඳහා විසුරුවා හරින ලද කේතය:

 [0000] push        ebp
 [0001] mov         ebp,esp
 [0003] push        edi
 [0004] push        esi
 [0005] push        ebx
 [0006] sub         esp,1Ch
 [0009] xor         eax,eax
 [000b] mov         dword ptr [ebp-20h],eax
 [000e] mov         dword ptr [ebp-1Ch],eax
 [0011] mov         dword ptr [ebp-18h],eax
 [0014] mov         dword ptr [ebp-14h],eax
 [0017] xor         eax,eax
 [0019] mov         dword ptr [ebp-18h],eax
*[001c] mov         esi,1
 [0021] xor         edi,edi
 [0023] mov         dword ptr [ebp-28h],1
 [002a] mov         dword ptr [ebp-24h],0
 [0031] inc         ecx
 [0032] mov         ebx,2
 [0037] cmp         ecx,2
 [003a] jle         00000024
 [003c] mov         eax,esi
 [003e] mov         edx,edi
 [0040] mov         esi,dword ptr [ebp-28h]
 [0043] mov         edi,dword ptr [ebp-24h]
 [0046] add         eax,dword ptr [ebp-28h]
 [0049] adc         edx,dword ptr [ebp-24h]
 [004c] mov         dword ptr [ebp-28h],eax
 [004f] mov         dword ptr [ebp-24h],edx
 [0052] inc         ebx
 [0053] cmp         ebx,ecx
 [0055] jl          FFFFFFE7
 [0057] jmp         00000007
 [0059] call        64571ACB
 [005e] mov         eax,dword ptr [ebp-28h]
 [0061] mov         edx,dword ptr [ebp-24h]
 [0064] lea         esp,[ebp-0Ch]
 [0067] pop         ebx
 [0068] pop         esi
 [0069] pop         edi
 [006a] pop         ebp
 [006b] ret

මන්දගාමී අනුවාදය සඳහා විසුරුවා හරින ලද කේතය:

 [0000] push        ebp
 [0001] mov         ebp,esp
 [0003] push        esi
 [0004] sub         esp,18h
*[0007] mov         dword ptr [ebp-14h],1
 [000e] mov         dword ptr [ebp-10h],0
 [0015] mov         dword ptr [ebp-1Ch],1
 [001c] mov         dword ptr [ebp-18h],0
 [0023] inc         ecx
 [0024] mov         esi,2
 [0029] cmp         ecx,2
 [002c] jle         00000031
 [002e] mov         eax,dword ptr [ebp-14h]
 [0031] mov         edx,dword ptr [ebp-10h]
 [0034] mov         dword ptr [ebp-0Ch],eax
 [0037] mov         dword ptr [ebp-8],edx
 [003a] mov         eax,dword ptr [ebp-1Ch]
 [003d] mov         edx,dword ptr [ebp-18h]
 [0040] mov         dword ptr [ebp-14h],eax
 [0043] mov         dword ptr [ebp-10h],edx
 [0046] mov         eax,dword ptr [ebp-0Ch]
 [0049] mov         edx,dword ptr [ebp-8]
 [004c] add         eax,dword ptr [ebp-1Ch]
 [004f] adc         edx,dword ptr [ebp-18h]
 [0052] mov         dword ptr [ebp-1Ch],eax
 [0055] mov         dword ptr [ebp-18h],edx
 [0058] inc         esi
 [0059] cmp         esi,ecx
 [005b] jl          FFFFFFD3
 [005d] mov         eax,dword ptr [ebp-1Ch]
 [0060] mov         edx,dword ptr [ebp-18h]
 [0063] lea         esp,[ebp-4]
 [0066] pop         esi
 [0067] pop         ebp
 [0068] ret

සෑම අවස්ථාවකම *නිදොස් කිරීම සරල "පියවරක්" තුළට ඇතුළු වූ ස්ථානය පෙන්වයි.

සංස්කරණය කරන්න: හරි, මම දැන් කේතය හරහා බැලුවෙමි, එක් එක් අනුවාදය ක්‍රියා කරන ආකාරය මට දැකගත හැකි යැයි මම සිතමි ... මන්දගාමී අනුවාදය මන්දගාමී බව මම විශ්වාස කරන්නේ එය අඩු ලේඛනයක් සහ වැඩි ඉඩ ප්‍රමාණයක් භාවිතා කරන බැවිනි. එහි කුඩා අගයන් සඳහා nවේගවත් විය හැකිය - නමුත් ලූපය වැඩි කාලයක් ගත කරන විට එය මන්දගාමී වේ.

සමහරවිට උත්සාහක / උඩ වාරණ හමුදා වැඩි ලේඛන ගැලවීම හා යථා තත්ත්වයට පත් කිරීමට, සඳහා JIT මෙන්ම කම්බියක් සඳහා එම භාවිතා ඉතින් ... සමස්ත කාර්ය සාධනය වැඩි දියුණු කිරීම සඳහා සිදු කරන. “සාමාන්‍ය” කේතයේ ඇති තරම් ලේඛණ භාවිතා නොකිරීම JIT ආයතනයට සාධාරණ තීරණයක්ද යන්න පැහැදිලි නැත .

සංස්කරණය කරන්න: මෙය මගේ x64 යන්ත්‍රයෙන් උත්සාහ කර බලන්න. මෙම කේතයේ x86 CLR ට වඩා x64 CLR වඩා වේගවත් (3-4 ගුණයක් පමණ වේගවත්) වන අතර x64 යටතේ උත්සාහ කරන්න / අල්ලා ගැනීමේ කොටස සැලකිය යුතු වෙනසක් නොකරයි.


4
Ord ගෝර්ඩන් සිම්ප්සන් නමුත් නිශ්චිත ව්‍යතිරේකයක් පමණක් හසු වුවහොත් අනෙක් සියලුම ව්‍යතිරේකයන් හසු නොවනු ඇත, එබැවින් ඔබගේ කල්පිතයට කිසිදු උත්සාහයක් නොගෙන ඕනෑම පොදු කාර්යයක් අවශ්‍ය වේ.
ජෝන් හැනා

45
එය රෙජිස්ටර් ප්‍රතිපාදනවල වෙනසක් සේ පෙනේ. වේගවත් අනුවාදය esi,ediතොගය වෙනුවට දිගු එකක් භාවිතා කිරීමට කළමනාකරණය කරයි . ebxමන්දගාමී අනුවාදය භාවිතා කරන කවුන්ටරය ලෙස එය භාවිතා කරයි esi.
ජෙෆ්රි සැක්ස්

13
E ජෙෆ්රි සැක්ස්: එය භාවිතා කරන්නේ කුමන රෙජිස්ටාර් පමණක් නොව කීයක් ද? මන්දගාමී අනුවාදය අඩු තොගයක් ස්පර්ශ කරමින් වැඩි තොග ඉඩක් භාවිතා කරයි. ඒ ඇයි දැයි මට අදහසක් නැත ...
ජෝන් ස්කීට්

2
සීඑල්ආර් ව්‍යතිරේක රාමු ලේඛණ හා තොග සම්බන්ධයෙන් කටයුතු කරන්නේ කෙසේද? එකක් සැකසීමෙන් කෙසේ හෝ භාවිතා කිරීම සඳහා ලේඛනයක් නිදහස් කළ හැකිද?
සසම්භාවී 832

4
IIRC x64 හි x86 ට වඩා වැඩි ලේඛනයක් තිබේ. ඔබ දුටු වේගවත් කිරීම x86 යටතේ අමතර රෙජිස්ටර් භාවිතය සඳහා උත්සාහ කිරීම / අල්ලා ගැනීම සමඟ අනුකූල වේ.
ඩෑන් ඊස් ෆයිඩ්ලිං ෆයර්ලයිට්

116

ජෝන් ගේ විසුරුවා හැරීම් වලින් පෙනී යන්නේ, අනුවාද දෙක අතර ඇති වෙනස esi,ediවන්නේ මන්දගාමී අනුවාදය නොමැති දේශීය විචල්‍යයන්ගෙන් එකක් ගබඩා කිරීම සඳහා වේගවත් අනුවාදය රෙජිස්ටර් යුගලයක් භාවිතා කරන බවයි.

JIT සම්පාදකයා විසින් කේත සඳහා රෙජිස්ටර් භාවිතය සම්බන්ධයෙන් විවිධ උපකල්පන සිදු කරයි. මෙය විවිධ ලේඛණ වෙන් කිරීමේ තේරීම් කිරීමට හේතු වේ. මෙම අවස්ථාවේ දී, මෙය උත්සාහක-අල්ලා ගැනීමේ කොටස සමඟ කේතයට කැමැත්තක් දක්වයි. විවිධ කේතයන් ප්‍රතිවිරුද්ධ බලපෑමට තුඩු දිය හැකි බැවින් මම මෙය පොදු කාර්ය වේගවත් කිරීමේ ක්‍රමයක් ලෙස නොසලකමි.

අවසානයේදී, වේගයෙන් ධාවනය වන්නේ කුමන කේතයදැයි පැවසීම ඉතා අපහසුය. රෙජිස්ටර් වෙන් කිරීම වැනි දෙයක් සහ එයට බලපාන සාධක එවැනි පහත් මට්ටමේ ක්‍රියාත්මක කිරීමේ තොරතුරු වන අතර කිසිදු නිශ්චිත තාක්‍ෂණයකට විශ්වාසනීය ලෙස වේගවත් කේතයක් නිපදවිය හැක්කේ කෙසේදැයි මම නොදනිමි.

උදාහරණයක් ලෙස, පහත දැක්වෙන ක්‍රම දෙක සලකා බලන්න. ඒවා අනුවර්තනය කරන ලද්දේ සැබෑ ජීවිත උදාහරණයකින් ය:

interface IIndexed { int this[int index] { get; set; } }
struct StructArray : IIndexed { 
    public int[] Array;
    public int this[int index] {
        get { return Array[index]; }
        set { Array[index] = value; }
    }
}

static int Generic<T>(int length, T a, T b) where T : IIndexed {
    int sum = 0;
    for (int i = 0; i < length; i++)
        sum += a[i] * b[i];
    return sum;
}
static int Specialized(int length, StructArray a, StructArray b) {
    int sum = 0;
    for (int i = 0; i < length; i++)
        sum += a[i] * b[i];
    return sum;
}

එකක් අනෙකාගේ සාමාන්‍ය අනුවාදයකි. සාමාන්‍ය වර්ගය වෙනුවට ආදේශ කිරීමෙන් StructArrayක්‍රම එක සමාන වේ. නිසා StructArrayඅගය වර්ගය වන අතර, එය මේ ලිපිය තුළ වර්ගීය ක්රමය එහි ම සකස් අනුවාදය ලැබෙනවා. තථ්‍ය ධාවන කාලය විශේෂිත ක්‍රමයට වඩා සැලකිය යුතු තරම් දිගු නමුත් x86 සඳහා පමණි. X64 සඳහා, වේලාවන් බොහෝ දුරට සමාන වේ. වෙනත් අවස්ථාවල දී, මම x64 සඳහා ද වෙනස්කම් නිරීක්ෂණය කර ඇත්තෙමි.


6
එසේ පැවසීමත් සමඟ ... උත්සාහ කිරීම / ඇල්ලීම භාවිතා නොකර විවිධ ලේඛණ වෙන් කිරීමේ තේරීම් බල කිරීමට ඔබට හැකිද? එක්කෝ මෙම උපකල්පනය සඳහා වූ පරීක්ෂණයක් ලෙසද නැතහොත් වේගය වෙනස් කිරීම සඳහා වන සාමාන්‍ය උත්සාහයක් ලෙසද?
වර්නර්සීඩී

1
මෙම විශේෂිත නඩුව වෙනස් වීමට හේතු ගණනාවක් තිබේ. සමහර විට එය උත්සාහය අල්ලා ගැනීම විය හැකිය. සමහර විට විචල්යයන් අභ්‍යන්තර විෂය පථයක් තුළ නැවත භාවිතා කිරීම විය හැකිය. නිශ්චිත හේතුව කුමක් වුවත්, එය එකම වැඩසටහන වෙනත් වැඩසටහනක කැඳවනු ලැබුවද, එය ආරක්ෂා කර ගත හැකි යැයි ඔබට විශ්වාස කළ නොහැකි ක්‍රියාත්මක කිරීමේ විස්තරයකි.
ජෙෆ්රි සැක්ස්

4
Ern වර්නර්සීඩී බොහෝ නවීන සම්පාදකයින් විසින් නොසලකා හරින ලද (අ) සහ (ආ) සී # ඇතුළත් නොකිරීමට තීරණය කළ බව යෝජනා කිරීම සඳහා සී සහ සී ++ යතුරට යතුරු පදයක් ඇති බව මම කියමි, මෙය අප යමක් නොවන බව යෝජනා කරයි ' මම තවත් සෘජු ආකාරයකින් දකිමි.
ජෝන් හැනා

2
Er වර්නර්සීඩී - ඔබ එකලස් කිරීම ලිවුවහොත් පමණි
ඔරේන්ජ් ඩොග්

73

මෙය පේළිගත කිරීම නරක අතට හැරී ඇති බවක් පෙනේ. X86 හරයක, ජිටරයේ දේශීය විචල්‍යයන් පොදු අරමුණු සඳහා ගබඩා කිරීම සඳහා ebx, edx, esi සහ edi ලේඛනයක් ඇත. මෙම ecx ලේඛනය එය ගබඩා කිරීමට නැත, ස්ථිතික ක්රමය ලබා ගත බවට පත් මෙම . ගණනය කිරීම් සඳහා බොහෝ විට eax ලේඛනය අවශ්‍ය වේ. නමුත් මේවා 32-බිට් රෙජිස්ටර් වේ, විචල්‍ය දිග සඳහා එය රෙජිස්ටර් යුගලයක් භාවිතා කළ යුතුය. ඒවා නම් edx: ගණනය කිරීම් සඳහා eax සහ ගබඩා කිරීම සඳහා edi: ebx ය.

මන්දගාමී අනුවාදය සඳහා විසුරුවා හැරීමේදී කැපී පෙනෙන දෙය නම්, එඩි හෝ ඊබක්ස් භාවිතා නොවේ.

දේශීය විචල්‍යයන් ගබඩා කිරීම සඳහා ප්‍රමාණවත් ලේඛනයක් ජිටර්ට සොයාගත නොහැකි වූ විට, එය තොග රාමුවෙන් පටවා ගබඩා කිරීමට කේත ජනනය කළ යුතුය. එමඟින් කේතය මන්දගාමී වන අතර, එය "රෙජිස්ටර් නැවත නම් කිරීම" නම් වූ ප්‍රොසෙසර ප්‍රශස්තිකරණය වළක්වයි, එය අභ්‍යන්තර ප්‍රොසෙසරයක මූලික ප්‍රශස්තිකරණ උපක්‍රමයක් වන අතර එය ලේඛනයක පිටපත් කිහිපයක් භාවිතා කරන අතර සුපිරි පරිමාණ ක්‍රියාත්මක කිරීමට ඉඩ දෙයි. එකම ලේඛනයක් භාවිතා කරන විට පවා සමගාමීව ක්‍රියාත්මක වීමට උපදෙස් කිහිපයක් සඳහා අවසර දෙයි. ප්‍රමාණවත් ලේඛණ නොමැති වීම x86 කෝර් වල පොදු ගැටළුවක් වන අතර එය x64 හි ආමන්ත්‍රණය කර ඇති අතර එයට අමතර රෙජිස්ටර් 8 ක් ඇත (r9 සිට r15 දක්වා).

තවත් කේත උත්පාදක ප්‍රශස්තිකරණයක් යෙදීමට ජිටර් උපරිම උත්සාහයක් දරනු ඇත, එය ඔබගේ ෆයිබෝ () ක්‍රමය පෙළගැස්වීමට උත්සාහ කරනු ඇත. වෙනත් වචන වලින් කිවහොත්, ක්‍රමයට ඇමතුමක් ලබා නොදී ප්‍රධාන () ක්‍රමයේ පේළියේ පේළිය සඳහා කේතය ජනනය කරන්න. ඉතා වැදගත් ප්‍රශස්තිකරණය, එකක් සඳහා, C # පන්තියක ගුණාංග නොමිලයේ ලබා දෙන අතර එමඟින් ඔවුන්ට ක්ෂේත්‍රයක පරිපූර්ණත්වය ලබා දේ. එය ක්‍රමවේදය ඇමතීමට සහ එහි සිරස් රාමුව සැකසීමට ඉහළින් වැලකී, නැනෝ තත්පර කිහිපයක් ඉතිරි කරයි.

ක්‍රමයක් ආදානය කළ හැකි විට හරියටම තීරණය කරන නීති කිහිපයක් තිබේ. ඒවා හරියටම ලේඛනගත කර නැති නමුත් බ්ලොග් සටහන් වල සඳහන් කර ඇත. එක් රීතියක් නම් ක්‍රමවේදය ශරීරය විශාල වූ විට එය සිදු නොවන බවයි. එමඟින් පේළිගත කිරීමෙන් ලැබෙන ලාභය පරාජය වන අතර, එය L1 උපදෙස් හැඹිලියට නොගැලපෙන තරම් කේත ජනනය කරයි. මෙහි අදාළ වන තවත් දැඩි රීතියක් නම්, ක්‍රමයක් උත්සාහ කිරීමේ / අල්ලා ගැනීමේ ප්‍රකාශයක් අඩංගු වන විට එයට නැඹුරු නොවන බවයි. ඒ පිටුපස ඇති පසුබිම ව්‍යතිරේකයන් ක්‍රියාත්මක කිරීමේ විස්තරයකි, ඒවා වින්ඩෝස් හි ගොඩනංවන ලද SEH (ව්‍යුහ ව්‍යතිරේක හැසිරවීම) සඳහා සහය දක්වයි.

ජිටර් තුළ ඇති රෙජිස්ටර් වෙන් කිරීමේ ඇල්ගොරිතමයේ එක් හැසිරීමක් මෙම කේතය සමඟ සෙල්ලම් කිරීමෙන් අනුමාන කළ හැකිය. විහිළුකාරයා ක්‍රමවේදයක් යෙදවීමට උත්සාහ කරන විට එය දැනුවත්ව සිටින බව පෙනේ. එක් රීතියක් ලෙස පෙනෙන්නේ දේශීය වර්ගයේ දිග විචල්‍යයන් ඇති පේළිගත කේත සඳහා edx: eax register යුගලය පමණක් භාවිතා කළ හැකි බවයි. නමුත් එඩී නොවේ: ebx. ඇමතුම් ක්‍රමයට කේත උත්පාදනයට එය අහිතකර වනු ඇති බවට සැකයක් නැත, එඩී සහ ඊබීඑක්ස් යන දෙකම වැදගත් ගබඩා ලේඛණ වේ.

එබැවින් ඔබට වේගවත් අනුවාදය ලැබෙනුයේ ක්‍රමවේදය ශරීරයේ උත්සාහක / අල්ලා ගැනීමේ ප්‍රකාශ අඩංගු බව ජිටර් දන්නා බැවිනි. එය කිසි විටෙකත් පේළිගත කළ නොහැකි බව එය දනී, එබැවින් දිගු විචල්‍යය සඳහා ගබඩා කිරීම සඳහා පහසුවෙන් edi: ebx භාවිතා කරයි. ඔබට මන්දගාමී අනුවාදය ලැබුනේ ඉන්ලයින් කිරීම ක්‍රියා නොකරන බව ජිටර් දැන නොසිටි බැවිනි. එය සොයාගත්තේ ක්‍රමවේදය සඳහා කේතය ජනනය කිරීමෙන් පසුව පමණි .

එවිට ඇති අඩුපාඩුව නම්, එය ආපසු ගොස් ක්‍රමවේදය සඳහා කේතය නැවත උත්පාදනය නොකිරීමයි . එය ක්‍රියාත්මක වීමට ඇති කාල සීමාවන් සැලකිල්ලට ගෙන එය තේරුම් ගත හැකි ය.

X64 හි මෙම මන්දගාමී වීම සිදු නොවන්නේ එක් අයෙකුට තවත් රෙජිස්ටර් 8 ක් ඇති බැවිනි. තවත් එකක් සඳහා එය එක් ලේඛනයක (රැක්ස් වැනි) දිගු කාලයක් ගබඩා කළ හැකි බැවිනි. දිගු වේලාවක් වෙනුවට ඔබ int භාවිතා කරන විට මන්දගාමී වීම සිදු නොවේ. මන්ද ලේඛකයාට රෙජිස්ටර් තෝරා ගැනීමේදී වැඩි නම්යශීලී බවක් ඇති බැවිනි.


21

මෙය එසේ විය හැකි බව මට විශ්වාස නැති නිසා මම මෙය අදහස් දැක්වීමක් ලෙස ඉදිරිපත් කර ඇත්තෙමි, නමුත් මට මතක ඇති පරිදි එය උත්සාහයක් / හැර ප්‍රකාශයක් නොවේ කසළ බැහැර කිරීමේ යාන්ත්‍රණය වෙනස් කිරීමකි. සම්පාදකයා ක්‍රියා කරයි, එමඟින් එය වස්තු මතක ප්‍රතිපාදන තොගයෙන් බැහැරව පුනරාවර්තන ආකාරයකින් ඉවත් කරයි. මෙම නඩුවේදී ඉවත් කළ යුතු වස්තුවක් නොතිබිය හැකිය, නැතහොත් වෙනත් එකතු කිරීමේ ක්‍රමයක් බලාත්මක කිරීමට ප්‍රමාණවත් ලෙස කසළ එකතු කිරීමේ යාන්ත්‍රණය හඳුනාගෙන ඇති බව වසා දැමීමක් විය හැකිය. බොහෝ විට නැත, නමුත් වෙනත් තැනක සාකච්ඡා කර ඇති බවක් මා දැක නැති නිසා එය සඳහන් කිරීම වටී යැයි මම සිතුවෙමි.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.