SORU
16 Mart 2015, PAZARTESİ


Nadiren çalıştırılır ve if ifadesi büyük ölçüde C performansı azaltır neredeyse boş

Editörün açıklama:Bu aslında yayınlanmıştır zaman, iki konu vardı:

  • Eğer üç görünüşte önemsiz deyiminin bir faktör tarafından Test performans düşer ekledi
  • Zaman testi tamamlamak için gereken rasgele farklılık gösterdiği görülmektedir

İkinci sorun çözüldü: tek hata ayıklayıcı altında çalışan oluşur rastgele.

Geriye kalan soru bu olmalı anlaşıldığı gibi olmanın ilk kurşun noktası üstünde, ve bağlamında çalışan VC 2010 Express Sürümü Modu ile en iyi duruma getirme "Maksimize Hız" ve "iyilik hızlı kodu".

Hala yorum bölümüne ikinci nokta hakkında konuşurken bazı Yorumlar var ama artık göz ardı edilebilir.


Ben bir simülasyon nerede olursa ekleyebilirim basit bir if içine while döngüsü çalışan gerçek simülasyon, performans düşer hakkında bir faktör üç (ve benim bir sürü hesaplamalarda while döngüsü, n-vücut yerçekimi güneş sistemi dışında başka şeyler) bile, eğer deyim neredeyse hiç çalıştırılır:

if (time - cb_last_orbital_update > 5000000)
{
    cb_last_orbital_update = time;
}

time cb_last_orbital_update her iki tip double ve bu deyimi de bulunduğu ana işlevi başlangıcı, tanımlanan ile. Genelde ben de çok istiyorum hesaplamaları vardır, ama eğer onları silersem hiç fark etmez. Yukarıdaki gibi deyimi performansı üzerinde aynı etkiye sahiptir.

Değişken time simülasyon zaman artar hassasiyeti 0,001 adım başında çok zaman alır, çok uzun zaman kadar eğer deyimi çalıştırılır ilk defa (ben de dahil baskı mesaja bakın Eğer idam ediliyor, ama değil, ya da en azından sadece zaman gerekiyor). Ne olursa olsun, performans, bir kez daha idam olmadı ne zaman simülasyon ilk dakikada bile 3 kat düşer. Ben satırı dışında açıklama

cb_last_orbital_update = time;

o zaman daha hızlı çalışır, kontrol et

time - cb_last_orbital_update > 5000000

ya da, kesinlikle bu değişken geçerli simülasyon zamanı yazma basit hareket.

Eğer cb_last_orbital_update, yerine başka bir değişken, mevcut zaman yazarsam da, performansı düşmeyecektir. Bu kontrol etmek için kullanılan bir değişken için yeni bir değer atama ile ilgili bir sorun "" idam olmalı mı? varsa olabilir yani Bu karanlık olmasına rağmen tüm çekim vardır.

Yasal Uyarı: programlama için oldukça yeni ve ben tüm metni için üzgünüm.

Visual C 2010 Express stdafx.h önceden derlenmiş üstbilgi işlevi bir fark değildi devre dışı bırakılması kullanıyorum.

EDİT: programın Temel yapısı. Hiçbir süre sonunda ayrıca loop (time = time_interval;) time değiştirilir. Ayrıca, cb_last_orbital_update sadece 3 tekrarı var: Bildiri / başlatma, ayrıca soruna neden olan ıf deyimi içinde iki kez.

int main(void)
{
    ...
    double time = 0;
    double time_interval = 0.001;
    double cb_last_orbital_update = 0;

    F_Rocket_Preset(time, time_interval, ...);

    while(conditions)
    {
    Rocket[active].Stage[Rocket[active].r_stage].F_Update_Stage_Performance(time, time_interval, ...);
    Rocket[active].F_Calculate_Aerodynamic_Variables(time);
    Rocket[active].F_Calculate_Gravitational_Forces(cb_mu, cb_pos_d, time);
    Rocket[active].F_Update_Rotation(time, time_interval, ...);
    Rocket[active].F_Update_Position_Velocity(time_interval, time, ...);
    Rocket[active].F_Calculate_Orbital_Elements(cb_mu);
    F_Update_Celestial_Bodies(time, time_interval, ...);

    if (time - cb_last_orbital_update > 5000000.0)
    {
        cb_last_orbital_update = time;
    }

    Rocket[active].F_Check_Apoapsis(time, time_interval);
    Rocket[active].F_Status_Check(time, ...);
    Rocket[active].F_Update_Mass (time_interval, time);
    Rocket[active].F_Staging_Check (time, time_interval);

    time  = time_interval;

    if (time > 3.1536E8)
    {
        std::cout << "\n\nBreak main loop! Sim Time: " << time << std::endl;
        break;
    }
    }
...
}

EDİT 2:

Here derleme kod farkı vardır. Soldaki hat ile hızlı kod

cb_last_orbital_update = time;

outcommented, doğru çizgi ile yavaş kod.

EDİT 4:

Yani şimdiye kadar iyi iş gibi görünüyor bir çözüm buldum:

int cb_orbit_update_counter = 1; // before while loop

if(time - cb_orbit_update_counter * 5E6 > 0)
{
    cb_orbit_update_counter  ;
}

EDİT 5:

Bu geçici çözüm işe, ancak sadece __declspec(noinline) kullanımı ile birlikte çalışır. Ben sadece işlevi bildirimleri bir daha bu bir şey değiştirir ve yok olmadığını görmek için kaldırıldı.

EDİT 6: Üzgünüm, bu kafa karıştırıcı oluyor. Bu fonksiyon için __declspec(noinline) çıkarırken, if içinde yürütülen daha düşük performans için suçlu buldum:

__declspec(noinline) std::string F_Get_Body_Name(int r_body)
{
switch (r_body)
{
case 0:
    {
        return ("the Sun");
    }
case 1:
    {
        return ("Mercury");
    }
case 2:
    {
        return ("Venus");
    }
case 3:
    {
        return ("Earth");
    }
case 4:
    {
        return ("Mars");
    }
case 5:
    {
        return ("Jupiter");
    }
case 6:
    {
        return ("Saturn");
    }
case 7:
    {
        return ("Uranus");
    }
case 8:
    {
        return ("Neptune");
    }
case 9:
    {
        return ("Pluto");
    }
case 10:
    {
        return ("Ceres");
    }
case 11:
    {
        return ("the Moon");
    }
default:
    {
        return ("unnamed body");
    }
}

}

if ayrıca artık sadece artış daha fazla sayaç yapar:

if(time - cb_orbit_update_counter * 1E7 > 0)
{
    F_Update_Orbital_Elements_Of_Celestial_Bodies(args);
    std::cout << F_Get_Body_Name(3) << " SMA: " << cb_sma[3] << "\tPos Earth: " << cb_pos_d[3][0] << " / " << cb_pos_d[3][1] << " / " << cb_pos_d[3][2] <<
    "\tAlt: " << sqrt(pow(cb_pos_d[3][0] - cb_pos_d[0][0],2)   pow(cb_pos_d[3][1] - cb_pos_d[0][1],2)   pow(cb_pos_d[3][2] - cb_pos_d[0][2],2)) << std::endl;
    std::cout << "Time: " << time << "\tcb_o_h[3]: " << cb_o_h[3] << std::endl;
    cb_orbit_update_counter  ;
}

Ben fonksiyonu F_Get_Body_Name __declspec(noinline) yalnız kaldırın, kod daha yavaş olur. Ben bu işlevi yürütme kaldırmak veya __declspec(noinline) tekrar ekleyin aynı şekilde eğer kod daha hızlı çalışır. Diğer tüm fonksiyonları hala __declspec(noinline).

EDİT 7: Geçiş fonksiyonu değiştirdim

const std::string cb_names[] = {"the Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto","Ceres","the Moon","unnamed body"}; // global definition
const int cb_number = 12; // global definition

std::string F_Get_Body_Name(int r_body)
{
if (r_body >= 0 && r_body < cb_number)
{
    return (cb_names[r_body]);
}
else
{
    return (cb_names[cb_number]);
}
}

ve ayrıca başka bir kod parçası daha ince yapılmış. Programı şimdi hızlı __declspec(noinline) herhangi olmadan çalışır. ElderBug önerdiği gibi, CPU komut önbelleği ile ilgili bir sorun, o zaman bu kod çok büyük/?

CEVAP
16 Mart 2015, PAZARTESİ


Intel'in şube tahmini paramı koyardım. http://en.wikipedia.org/wiki/Branch_predictor

İşlemci (zaman - ^ cb_last_orbital_update . varsayar 5000000) zaman ve yüklerin çoğu yürütme boru hattı buna göre yanlış.

(Zaman - ^ cb_last_orbital_update . durumu bir kez 5000000) doğru geliyor. Misprediction gecikme seni vuruyor. 10 ila 20 döngü gevşek olabilir.

if (time - cb_last_orbital_update > 5000000)
{
    cb_last_orbital_update = time;
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Benjamin Heckendorn

    Benjamin Hec

    4 Mayıs 2008
  • LounaTutorials

    LounaTutoria

    10 EYLÜL 2009
  • Vsauce

    Vsauce

    30 Temmuz 2007