Domanda Risolto velocita' di esecuzione di una funzione

obbligatorio70

Utente Iron
28 Luglio 2020
10
2
0
12
Trading alta frequenza
Ricevo i dati alla velocita della luce ma la mia funzione è lenta e il tempo di esecuzione è irregolare si parla di milisecondi, uso c#
vorrei fare un confronto con c++ linux se qualcuno è disponibile

non riesco a stabilizzarmi e a capire come mai l'esecuzione a volte e' estremamente lenta
si tratta di creare un semplice ciclo e scrivere i tempi di esecuzione

esempio del mio codice

tempi.png
 
Serve sapere cosa fa questa funzione e anche la specifica implementazione, in base ai metodi usati puo' variare parecchio (ed anche ai dati che vengono passati). Comunque C# ottimizza parecchio quindi non vedrai chissa' quali differenze, pero' se il codice C++ e' scritto bene vedrai sicuramente un miglioramento di performance sul lungo termine.
 
Uso questo codice per il ciclo
C#:
public partial class Form1 : Form
    {
        Stopwatch st;
        System.Timers.Timer tmData;
        StreamWriter sw ;
        Thread t;
        bool bVai = true;
        Int32 i = 0;
        Int64 l = 0;
        string sOra = string.Empty;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            tmData = new System.Timers.Timer()
            {
                SynchronizingObject = this,
                Interval = 20
            };

            tmData.Elapsed += TmData_Elapsed;
            tmData.Enabled = false;

            st = new Stopwatch();
            sw = new StreamWriter(@"C:\nj\ciclo" + DateTime.Now.ToString("HH") + ".txt", true);

            t = new Thread(new ThreadStart(ciclo));
            t.Start();

        }

        private void TmData_Elapsed(object sender, ElapsedEventArgs e)
        {
            ciclo();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            bVai = false;
            Thread.Sleep(10);
            sw.Close();
            tmData.Dispose();

        }

        private void ciclo()
        {
            i = 0;
            l = 0;

            while (bVai)
            {
                st.Start();

                for (i = 0; i < 50000; i++)
                {
                    l += i;
                    if ((l % 4) == 0)
                    {
                        l /= 2;
                    }
                }

                st.Stop();

                sw.WriteLine(st.ElapsedTicks.ToString());

                st.Reset();

                if (sOra != DateTime.Now.ToString("HH"))
                {
                    sOra = DateTime.Now.ToString("HH");
                    try
                    {
                        sw.Close();
                        sw.Dispose();
                    }
                    catch { }

                    sw = new StreamWriter(@"c:\nj\ciclo" + sOra + ".txt", true);
                }
            }
        }
    }


poi sto indagando per capire come stabilizzare meglio perchè non so se dipende dalla gestione cpu, ram, sistema operativo o software perchè a volte è un po lento
 
Ultima modifica:
Non ho capito la parte del timer che poi resta disabilitato e poi viene usato un thread comunque arrivando al punto se consideriamo solo questa parte di codice che stai cercando di monitorare:
C#:
int i, l = 0;
for (i = 0; i < 50000; i++)
{
    l += i;
    if ((l % 4) == 0)
    {
        l /= 2;
    }
}

Sono 50k addizioni, 50k moduli, ~15k divisioni. Per le divisioni puoi velocizzare un pochino sostituendolo con un right shift l >>= 1; ma il grosso rimane.

Visual C++ Su Windows:
Codice:
C++:
iStart = microtime();
for (i = 0; i < 50000; i++)
{
    l += i;
    if ((l % 4) == 0)
        l = l >> 1;
}
iEnd = microtime();

0 - 65µs
1 - 133µs
2 - 78µs
3 - 58µs
4 - 58µs
5 - 58µs
6 - 58µs
7 - 58µs
8 - 58µs
9 - 58µs
10 - 80µs
11 - 73µs
12 - 72µs
13 - 59µs
14 - 58µs
15 - 58µs
16 - 58µs
17 - 59µs
18 - 58µs
19 - 58µs
20 - 58µs
21 - 61µs
22 - 58µs
23 - 58µs
24 - 58µs
25 - 58µs
26 - 58µs
27 - 58µs
28 - 58µs
29 - 58µs

PS: Intel i7 7th generazione
 
Ciao, il timer era una prova, volevo vedere che differenza fa eseguire la routine a determinati intervalli o di continuo
ok, lo shift renderebbe il ciclo piu' veloce, quello che pero' vorrei capire e' come mai una volta viene eseguito (nel tuo esempuo) in 58µs poi 133µs poi 65...insomma sto cercando sia la velocita' che stabilita' dei tempi di esecuzione
Secondo te da cosa possono dipendere i tempi fuori "range"?
tempi2.png
 
Secondo te da cosa possono dipendere i tempi fuori "range"?

I tempi non sono mai uguali, ho diversi programmi aperti simultaneamente, tra cui una VM guest. Il processore puo' mettere in parallelo tanti thread quanti core ha, dopo di che' deve fare time-sharing, quindi dove vedi un picco probabilmente l'OS ha sospeso per qualche microsecondo la nostra esecuzione per poter eseguire operazioni di altri processi. Piu' cose il sistema fa alla volta piu' differenze vedrai nei tempi tra un esecuzione ed un'altra. Immagino che per avere il top della stabilita' servirebbe un octa-core con una distro Linux super-minimale con neanche l'interfaccia grafica in modo che i processi siano giusto quelli di sistema, ssh e il tuo programma. Diciamo un tantino esagerato, alla fine cosa ti cambiano 50 micro secondi?
 
Java e i7 mobile di quarta generazione
Codice:
103 µs, 99 µs, 108 µs, 92 µs, 92 µs, 92 µs, 92 µs, 95 µs, 97 µs, 95 µs, 96 µs, 95 µs, 95 µs, 95 µs, 92 µs, 95 µs, 90 µs, 95 µs, 95 µs, 93 µs, 95 µs, 94 µs, 97 µs, 99 µs, 102 µs, 98 µs, 104 µs, 96 µs, 94 µs, 95 µs
paragonabili ai tempi di JunkCoder nonostante il mio computer sia molto più scarso del suo e nonostante abbia scelto un linuguaggio di programmazione notoriamente più lento. Nota che i tuoi valori sono in millisecondi, un'ordine di grandezza più lenti dei nostri.

Morale della favola: è complicato fare microbenchmarks attendibili, ci sono un sacco varianti che entrano in gioco; in primis, le ottimizzazioni del compilatore. Spiega cosa vuoi fare senza assumere che lo stai già facendo in modo corretto. Se vuoi, per esempio, calcolare quanto tempo ci vuole ad eseguire un'addizione sulla tua CPU... si può fare, ma non con ogni linguaggio e non nel modo che pensi tu: devi poter scrivere codice a basso livello per prevenire ogni tipo di ottimizzazione e devi prendere mediana e variaza su svariate ripetizioni.

Ricevo i dati alla velocita della luce ma la mia funzione è lenta e il tempo di esecuzione è irregolare si parla di milisecondi
Fai dei benchmark sulla tua funzione e identifica per quale motivo è lenta. Non testare un'altra funzione sperando che sia equivalente.
 
Sto testando con una vps volutamente lenta per vedere meglio i miei progressi, la prima immagine che ho postato sono i tempi dopo 10 ore di utilizzo devo fare altri test
questa è la macchina mentre gira il ciclo
 

Allegati

  • spec.png
    spec.png
    10.9 KB · Visualizzazioni: 12
Ultima modifica:
Va bene che e' dual core con 4 GB di ram pero' 6000 ms sono 6 secondi, e' troppo esagerato quando in un PC performante ci sta < 100 µs. Se hai usato quel codice e non hai fatto ulteriori modifiche all'output quello che c'e' in st.ElapsedTicks non sono millisecondi, ma sono ticks (il valore in st.Frequency sono il numero di ticks per secondo). Per avere il valore in microsecondi dividi 1M (1M µs = 1 s) per la frequenza e poi moltiplicalo per gli ElapsedTicks.

C#:
double microsecPerTick = (1000000 / st.Frequency);
double microseconds = microsecPerTick * st.ElapsedTicks;

E' probabile che i tuoi risultati siano simili a quelli in C++ grossomodo, in quanto C# (JIT) come ti dicevo ottimizza davvero bene (e io non ho fatto particolari ottimizzazioni da compilatore, considera pero' che nel frattempo il PC era molto occupato).
 
Ho modificato il codice calcolando i microsecondi come suggerito da JunkCoder, ho fatto una prova su un i5 e un i7 e sono intorno ai 225µs, molto sopra i vostri tempi
Non riesco a capire cosa sbaglio o mi sfugge
 
Si, compilato in Release x64

Ho fatto altre prove col c++ ed e' nettamente piu' veloce
Non sviluppo in c++, i tempi dovrebbero essere in microsecondi, vi posto ance il codice

Codice:
int main()

{

    int i, l = 0;


    long microseconds;


    ofstream fout("ciclocpp.txt");


    for (int k = 0; k < 100000; k++)

    {

        auto start = std::chrono::high_resolution_clock::now();


        for (i = 0; i < 50000; i++)

        {

            l += i;

            if ((l % 4) == 0)

                l = l >> 1;

        }

        auto elapsed = std::chrono::high_resolution_clock::now() - start;


        microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();



        fout << microseconds << "\n";

    }



    fout.close();

}
 

Allegati

  • tempi22.png
    tempi22.png
    12.6 KB · Visualizzazioni: 7
Ho fatto una modifica al sorgente per fargli scrivere un file ogni x minuti per vedere se dopo qualche ora i tempi sono stabili, mi scrive il primo file con i tempi ma gli altri sono vuoti, dove sbaglio?
Codice:
#include <chrono>
#include <fstream>
#include <string>


using namespace std;

int main()
{
    int i, l = 0;
    int iNum = 0;

    long microseconds;
    std::string name = "";

    name = "ciclocpp" + std::to_string(iNum) + ".txt";

    ofstream fout(name);

    for (int k = 0; k < 1000000; k++)
    {
        if (k > 0 &&  (k % 100000) == 0)
        {
            fout.close();
            iNum++;
            name = "ciclocpp" + std::to_string(iNum) + ".txt";
            ofstream fout(name);
        }

        auto start = std::chrono::high_resolution_clock::now();

        for (i = 0; i < 50000; i++)
        {
            l += i;
            if ((l % 4) == 0)
                l = l >> 1;
        }
        auto elapsed = std::chrono::high_resolution_clock::now() - start;

        microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();


        fout << microseconds << "\n";
    }


    fout.close();
}
 
Stai ri-dichiarando fout dentro un if, una volta uscito dall'if l'oggetto verra' distrutto (sempre che non venga ottimizzato a monte dal compilatore). Invece di ricrearlo chiamando il costruttore chiudi il file precedente ed aprine uno nuovo:

C++:
fout.close();
fout.open(name);
 
  • Mi piace
Reazioni: obbligatorio70