Abfrage zum Zeitverbrauch meines Codes



  • Hallo.

    Ich habe hier folgenden Code:

    #include "cBild.h"
    #include "cCameraHandle.h"
    
    int  main()
    {
    	DWORD zeit1=GetTickCount(); 
    	cBild bild;
    	std::vector <cBild> data;
    	cCameraHandle cam;
    	int i,j,nr=0,bildanz=1,start=0;
    
    	DWORD zeit2;
    	for (i=0;i<bildanz;i++)
    	{
    		zeit2 = GetTickCount();
    
    		Function (bildanz,start);
    
    		std::cout << "\ttime: " << (double)(GetTickCount()-zeit2)/1000 << "s" << std::endl;
    	}
    
    	std::cout << "\n\n\n\nTotal time: " << (double)(GetTickCount()-zeit1)/1000 << "s" << std::endl;
    	return 0;
    }
    

    Was mich nun sehr wundert ist folgender Aspekt. Bei Durchlauf des Programms wird eingezeigt, dass ein Durchlauf der Vorschleife ('GetTickCount()-zeit2') etwa 1.5 Sekunden dauert. Der gesamte Durchlauf ('GetTickCount()-zeit1') aber etwa 3 Sekunden. Da frage ich mich jetzt, wie die restlichen 1.5 Sekunden entstehen? Kann das an den 3 Zeilen 7-9 liegen?

    Danke.
    H.W.



  • Gib doch einfach vor Eintritt in die Schleife auch noch die Zeit aus. Da wir die Klassen cBild und cCameraHandle nicht kennen, können wir auch nicht wissen, ob die was zweitintensives tun.



  • Hallo H.W.

    An der Zeile 8 liegt es sicher nicht, denn dort passiert nichts, was eine Laufzeit im Bereich von Sekunden rechtfertigt. Und die Zeile 7 solltest Du weglassen können, da 'bild' nirgendwo mehr benötigt wird.

    Gruß
    Werner



  • Gib doch einfach vor Eintritt in die Schleife auch noch die Zeit aus.

    Ja, damit konnte ich jetzt feststellen, dass meine Klasse 'zu viel' Zeit beansprucht. Darum möchte ich die gerne ändern, weis nur nicht wie. Darum kopiere ich sie mal. Das ganze soll dazu dienen, Bilddaten zu speichern. Da ich den Code für die Bilder nicht noch mit einfügen wollte, habe ich hier einfach mal paar Zufallszahlen reingeschrieben.
    Das Problem ist nun aber, dass jetzt jedes Mal, wenn ich die Variable 'data' in main.cpp in den Vector schreiben will, dann dauert das enorm lange. Könnte ich nicht anstelle der gesamten Daten (**itsVal) dort nur eine Adresse speichern, die ich denn im Assign- bzw. Kopieroperator einfach kopieren kann? Würde es mein Programm schneller machen, oder was schlagt ihr vor?

    Danke.
    H.W.

    main.cpp

    #include <iostream>
    #include <ctime>
    
    #include "cBild.h"
    
    const int DIM1 = 768;
    const int DIM2 = 1024;
    
    int main()
    {
    	cBild data;
    	std::vector <cBild> Vector;
    	int i;
    
    	for (i=0;i<5;i++)
    	{
    		rand();
    		data.SetX();
    		Vector.push_back(data);
    	}
    
    	return 0;
    }
    

    cBild.h:

    #include <iostream>
    #include <ctime>
    #include <vector>
    
    #pragma once
    
    extern const int DIM1;
    extern const int DIM2;
    
    class cPixel
    {
    public:
    	cPixel(void)
    	{
    		for (int i=0;i<3;i++)
    			itsRGB[i] = 0;
    	}
    	void SetRGB (int type, int val)
    	{itsRGB[type] = val;}
    	int GetRGB (int type) const
    	{return itsRGB[type];}
    
    private:
    	int itsRGB[3]; //Red,Green,Blue
    };
    
    class cBild
    {
    public:
    	cBild(void);
    	~cBild(void);
    	cBild (const cBild &right);
    	const cBild& operator=(const cBild &right);
    	void SetX();
    private:
    	cPixel **itsVal;
    };
    

    cBild.cpp

    #include "cBild.h"
    
    cBild::cBild(void)
    {
    	itsVal = new cPixel *[DIM1];
    	for (int i=0;i<DIM1;i++)
    		itsVal[i] = new cPixel [DIM2];
    }
    
    cBild::cBild (const cBild &right)
    {
    	itsVal = new cPixel *[DIM1];
    	for(int i=0;i<DIM1;i++)
    	{
    		itsVal[i] = new cPixel [DIM2];
    		for(int j=0;j<DIM2;j++)
    		{
    			for (int k=0;k<5;k++)
    				itsVal[i][j].SetRGB(k,right.itsVal[i][j].GetRGB(k));
    		}
    	}
    }
    
    cBild::~cBild(void)
    {
    	for (int i=0;i<DIM1;i++)
    		delete[] itsVal[i];
    	delete[] itsVal;
    }
    void cBild::SetX()
    {
    	for (int i=0;i<DIM1;i++)
    	{
    		for (int j=0;j<DIM2;j++)
    		{
    			for (int k=0;k<3;k++)
    				itsVal[i][j].SetRGB(k,rand()%100);
    		}
    	}
    }
    const cBild& cBild::operator=(const cBild &right)
    {
    	if (this != &right) 
    	{
    		int i,j;
    		for (i=0;i<DIM1;i++)
    			delete[] itsVal[i];
    		delete[] itsVal;
    
    		itsVal = new cPixel *[DIM1];
    		for(i=0;i<DIM1;i++)
    		{
    			itsVal[i] = new cPixel [DIM2];
    			for(j=0;j<DIM2;j++)
    			{
    				for (int k=0;k<3;k++)
    					itsVal[i][j].SetRGB(k,right.itsVal[i][j].GetRGB(k));
    			}
    		}
    	}
    	return *this;
    }
    


  • Hallo.

    ich habe jetzt ein bisschen weiterprogrammiert und mir ist dabei die Frage aufgekommen, ob das überhaupt "schnell" funktionieren kann. Ich habe ja im Prinzip vor, für jedes Bild und jedes Pixel im Bild mindestens 3 Integerzahlen abzuspeichern. Das macht pro Bild mindestens 2,4 Millionen Werte. Da ich nun aber vorhabe, eine Bildsequenz (~200 Bilder) auszuwerten, wird diese Zahl doch recht groß (~480.000.000 Werte, wenn nur RGB abgespeichert wird 😮 ).

    Gibt es eine Möglichkeit, solche große Datenmengen programmtechnisch gut zu verarbeiten?

    Danke.
    H.W.



  • Hans Wurst schrieb:

    Gibt es eine Möglichkeit, solche große Datenmengen programmtechnisch gut zu verarbeiten?

    Naja, das ganze wird schon sehr groß. Die Frage ist aber, ob Du wirklich zu jeder Zeit alle 200 Bilder im Speicher halten mußt. Vielleicht reichen immer so ca. 5 aus? Hängt natürlich von der anstehenden Aufgabe ab.

    Es dürfte auch schon etwas helfen, wenn Du den Speicher geschickter verwaltest. Statt einem new für ein Feld von Zeigern der Dimension DIM1 und dann DIM1 weiteren news würdes es auch ein new cPixel[DIM1*DIM2] tun. Damit der Zugriff weiterhin komfortabel bleibt kannste ja Funktionen/Operatoren dafür anbieten. Dadurch dürfte die Allokation deutlich schneller werden.



  • Jester schrieb:

    Es dürfte auch schon etwas helfen, wenn Du den Speicher geschickter verwaltest. Statt einem new für ein Feld von Zeigern der Dimension DIM1 und dann DIM1 weiteren news würdes es auch ein new cPixel[DIM1*DIM2] tun.

    Könnte ich dann nicht auch einen 'vector' nehmen? Wäre das schneller oder langsamer als ein Feld?



  • Nen vector kannste natürlich auch nehmen. Solange der nicht wachsen muß dürfte der Unterschied zwischen nem Array und nem vector nicht meßbar sein.



  • Jester schrieb:

    Dadurch dürfte die Allokation deutlich schneller werden.

    Hi Jester. Bist du dir da wirklich sicher? Ich habe mein Programm diesbezüglich modifiziert, kann aber keinerlei zeitliche Verbesserung feststellen.

    Also anstelle von:

    cPixel		**itsVal;
    

    steht jetzt:

    cPixel		*itsVal;
    

    und der Zugriff erfolgt so:

    int  Con (int i, int j)
    	{
    		return (i*DIM2+j);
    	}
    

    Die restlichen Veränderungen in ctor und dtor habe ich natürlich auch vorgenommen.

    H.W.



  • Also, mindestens 2 Sachen kannst du noch wesentlich schneller machen:
    1. Bei Vector.push_back( data );
    Soweit ich weiss, erstellt der Vector dann einen neuen Typ cBild und ruft dessen Konstruktor mit der Variable als const ref auf. D.h. der Vector macht ne neue Variable in seinem Array vom Typ cBild. Diese Variable wird "konstruiert" mit cBild::cBild (const cBild &right).
    Und eben diese Funktion könntest du wesentlich schneller machen. Warum kopierst du nicht z.B. mit memcpy die Daten anstatt die mit SetRGB( GetRGB() ) zu kopieren? Dann muss er nicht die einzelnen Werte auslesen und wieder speichern, sondern kopiert gleich den ganzen Bildbereich in einem Rutsch. Das dürfte erstmal wesentlich viel bringen!

    2. Alternativ dazu (oder auch parallel dazu) könntest du dir eine eigene Klasse schreiben, die wie std::vector<cBild> funktioniert. Noch funktioniert es ja so, dass du ein Bild erstellst und es dem Vector übergibst, der das Bild in seinen Array kopiert. Danach wird das Original-Bild verworfen. Statt dessen könntest du in deiner Array-Klasse ein Bild hinzufügen (mit leerem Inhalt, verbraucht keine Rechenleistung) und es dann modifizieren/laden/initialisieren/sonstwas...
    Also in etwa so:

    cBildArray BildArr;
    cBild& data = BildArr.Add();
    data.sonstwas;
    

    Dabei wird das Bild nicht erstellt und kopiert, sondern einfach nur einmal erstellt.

    :xmas1:

    Edit: Und warum nimmst du eigentlich je eine Integer-Zahl pro Farbwert? Bei einer Auflösung von 24 Bit reicht ja ein char (nur 8 statt 32 Bit) pro Farbwert.
    Also char itsRGB[3]? Dann müsste sich der Platz vervierteln 😃

    Edit: Und noch was: Wenn du ein leeres Bild erstellst, ruft es ja den Standard-Konstruktor auf. Da wird für jeden Pixel der Konstruktor aufgerufen, wo alle 3 Werte auf 0 gesetzt werden. Ist zwar wirklich schön objektorientiert gelöst (!!) aber es würde eigentlich schneller sein, wenn du nur Speicher allozierst und den auf 0 setzt. Dazu reicht sogar eine einzige Funktion, calloc. Oder, da du mit new/delete arbeitest, new char[DIM1*DIM2*3]; memset( itsVal, DIM1*DIM2*3, 0 );.
    Musst aber du entscheiden, inwiefern es für dich geschwindigkeitsrelevant ist, ob du es so (oder so ähnlich) machst oder ob du deinen sauberen Ansatz so lässt.

    Grüße,
    Badestrand



  • Hallo Badestrand.

    Deine Vorschläge gefallen mir gut. Ich werde mich mal an deren Umsetzung machen.

    Eine weitere Frage hätte ich noch: Nehmen wir mal an, ich schreibe in cBild::cBild (const cBild &right) folgende Zeile:

    cout << "cBild" << endl;
    

    Warum erscheint diese Ausgabe beim ersten Durchlauf der for-Schleife 2-Mal, beim und zweiten 3-Mal, beim dritten viermal etc....

    Danke.
    H.W.



  • Badestrand schrieb:

    Statt dessen könntest du in deiner Array-Klasse ein Bild hinzufügen (mit leerem Inhalt, verbraucht keine Rechenleistung) und es dann modifizieren/laden/initialisieren/sonstwas...

    Wenn du von hinzufügen schreibst, dann bezieht du dich sicher auf einen vector, der Member der cBildArray ist, oder verstehe ich das falsch? Wenn dies aber der Fall ist, dann muss ich in der Add()-Funktion erneut die push_back-Funktion für Vektoren aufrufen, um halt ein leeres Bild einzufügen. Dass dauert aber dann auch wieder die gleiche Zeit, oder?

    DANKE!
    H.W.



  • Hab grad mal mit deinem Source kompiliert, ist ja wirklich etwas langsam...
    Ich habe mal in cBild::cBild() als erste auszuführende Zeile std::cout << "cBild::cBild()" << std::endl; eingefügt und in cBild::cBild(const cBild &right) das hier: std::cout << "cBild::cBild( const cBild& )" << std::endl;.
    Wenn ich das durchlaufen lasse, erhalte ich dies hier:
    cBild::cBild()
    20 x cBild::cBild( const cBild& )
    Finde ich etwas heftig wenn man bedenkt, dass nur 5x etwas hinzufügt wird.

    Habe mir dann mal erlaubt, eine kleine Hilfsklasse zu schreiben, das war das was ich meinte:

    class cBildArray
    {
    	public:
    		cBildArray()
    		{
    			m_iCount = 0;
    			m_pBilder = 0;
    		}
    
    		~cBildArray()
    		{
    			for ( int i=0; i<m_iCount; i++ )
    				delete m_pBilder[i];
    			free( m_pBilder );
    		}
    
    		cBild& Add()
    		{
    			m_pBilder = (cBild**) realloc( m_pBilder, (m_iCount+1)*sizeof(cBild*) );
    			m_pBilder[m_iCount] = new cBild;
    			return *m_pBilder[m_iCount++];
    		}
    
    		cBild& Add( const cBild& right )
    		{
    			m_pBilder = (cBild**) realloc( m_pBilder, (m_iCount+1)*sizeof(cBild*) );
    			m_pBilder[m_iCount] = new cBild( right );
    			return *m_pBilder[m_iCount++];
    		}
    
    		cBild& Get( int Index )
    		{
    			if ( Index >= m_iCount )
    				; // Fehlerbehandlung!
    			return *m_pBilder[Index];
    		}
    
    		int GetCount()
    		{
    			return m_iCount;
    		}
    
    	private:
    		int     m_iCount;
    		cBild** m_pBilder;
    };
    

    Die main-Funktion sind dann so aus:

    cBild data;
        cBildArray Vector;
        int i;
        for (i=0;i<5;i++)
        {
            rand();
            data.SetX();
            Vector.Add(data);
        }
    

    Und siehe da:
    1 x cBild::cBild()
    5 x cBild::cBild( const cBild& )

    Sieht ja schonmal besser aus! Besser noch:

    cBildArray Vector;
        int i;
        for (i=0;i<5;i++)
        {
            rand(); // <-- Wofür brauchst du das eigentlich? Meinst du "srand()"?
            cBild& data = Vector.Add();
            data.SetX();
        }
    

    Bei der cBildArray-Klasse sind new und malloc gemischt. Wenn du sie verwendest, lies bitte etwas darüber, da man sonst manches kaputtmachen kann.
    Viele C++ler sind auch der Meinung, dass man malloc/realloc/free gar nicht mehr verwenden sollte, da es noch von C kommt und in C++ nichts mehr zu tun hätte.
    Wie auch immer, ich benutze es und du kannst es dir aussuchen 🙂

    Tut mir Leid dass ich auf deine Fragen nicht eingegangen bin, aber ich weiß nicht, ob die noch eine Relevanz haben, wenn ja, schreib einfach nochmal 😃



  • Hallo Badestrand,

    vielen Dank für deine Bemühungen, so geht es wirklich schneller. Ich werde es aber jetzt wahrscheinlich so machen, dass ich nur die betreffenden Ausschnitte aus dem Bild speicher, die von Interesse für mich sind, und nicht das gesamte Bild. Das dürfte dann meinen Anforderungen an die Geschwindigkeit entsprechen.

    nochmals VIELEN DANK für deine HILFE!
    H.W.


Log in to reply