Utrata wydajności. Dlaczego?

0

Mam taki kod:

// (...)
struct i_BMU {
	int	x,y, x2,y2;		// współrzędne pierwszego i drugiego BMU
};
typedef	list<double>	vec;
list<char>	Decision;	// decyzja kojarzona z każdym neuronem
list<vec> xx;		// lista wektorow wejsciowych (probki uczace)

string getClusterNo(int x, int y) {
	string	out;
	char		txt[5];
	if (clusters[x][y] > 0) {
		sprintf(txt, "%d", clusters[x][y]);
		out.assign(txt);
	}
	else
		out.assign("?");
	return out;
}

i_BMU Run(vec x) {
// "uruchamia" sieć i zwraca nr zwycięzcy
	double	min = 1e10, cur_d;
	int win_x=-1,win_y=-1;		// neuron zwyciezca (BMU = Best Matching Unit)
	int win2_x=-1,win2_y=-1;	// neuron, ktory jest kolejnym BMU
	for (int xp=0; xp<mapsize_x; xp++) {
		for (int yp=0; yp<mapsize_y; yp++) {
			cur_d = neurony[xp][yp].d(x);			// oblicz odleglosc wektora x od wektora W neuronu
			if (min > cur_d)	{
				min = cur_d;
				win_x = xp;		win_y = yp;
			}
		}
	}
	// szukanie 2nd BMU wśród sąsiadów BMU
	min = 1e10;
	for (int xp=-1; xp<=1; xp++)
		for (int yp=-1; yp<=1; yp++) {
			if ((xp==0 && yp==0) || win_x+xp < 0 || win_x+xp >= mapsize_x || win_y+yp < 0 || win_y+yp >= mapsize_y)
				continue;
			cur_d = neurony[win_x+xp][win_y+yp].d(x);	// oblicz odleglosc wektora x od wektora W neuronu
			if (min > cur_d)	{
				min = cur_d;
				win2_x = win_x+xp;		win2_y = win_y+yp;
			}
		}
	return (i_BMU){win_x,win_y, win2_x,win2_y};
}

// (...)
int main(...) {
// (....)
else if (backtest) {
	LoadNet();
	GetInputDataTeach();
	cout << endl << rpad("Generating backtest..."," ",40) << flush;
	plik_out.assign("backtest/");;
	plik_out.append("file.btst");
	FILE *fo = fopen(plik_out.c_str(), "wb");
	sprintf(c_txt,"%d %d ",mainTF, time1st);
	fputs(c_txt, fo);

//--- zapisz odpowiedzi sieci na poszczególne dane wejściowe
	list<vec>::iterator xit=xx.begin();
	char decision[2];
	list<char>::iterator		Dit;
	con_STO();   // zapamiętanie stanu konsoli używając kodów konsoli
	for (no=0; xit!=xx.end(); ++xit, no++) { // **************************
		if (no % 9 == 0) {
			con_RCL();  // odtworzenie stanu konsoli
			sprintf(c_txt, "%.2f%% ", (double)no/P*100);
			cout << progress_signs[no % 4] << "  " << c_txt << flush;		// pokaż, że pracuje
		}
		i_BMU winner = Run(*xit);   // przetworzenie wektora
		sprintf(c_txt, "%s", getClusterNo(winner.x,winner.y).c_str());
		fputs(c_txt, fo);

		Dit = Decision.begin();
		advance(Dit, mapsize_x*winner.y + winner.x);
		sprintf(decision, "%c", *Dit);
		fputs(decision, fo);
		fputs("\n", fo);
	}
	fclose(fo);
	cout << "OK" << endl;
}
} // main

i nie wiem, dlaczego pętla oznaczona gwiazdkami (********) szybko zaczyna zwalniać, aż w końcu wlecze się okropnie.
Lista xx zawiera od 2000 do 4000 elementów. Proszę o jakąś radę.

0

Jak już tak mieszasz C i C++, to mogłeś wypisywać na konsole przez printf.
Ja bym stawiał na tą funkcję con_RCL, ale nie wiem jak wygląda jej kod. Pokaż, albo powiedz co i za pomocą czego tam operujesz ;).

0

To nie ta funkcja :)

void con_RCL() {
	printf("\0338");
}

Nawet, gdy wcześniej jej nie było, to pętla zwalniała.

0

Czy może to być spowodowane tym, że do pliku fo jest cały czas zapisywane i ani razu nie ma flush'a?
Początkowo myślałem, że to wina tych operacji na liście Decision i funkcji advance. Usunąłem to, ale nadal zwalania.


Eeeee :-/ Flush też nie pomógł.

0

Przyjrzyj się operacji modulo 9, szczególnie że no ciągle rośnie.

Reszta operacji wygląda na niezależną od no, tylko od xit - może wartości w tej liście też są rosnące i operacje na nich zajmują więcej czasu im dalej?

0

To też nie to. Nawet, jak wyrzucę cały ten if z modulo, to zwalnia.
Wartości w xx na pewno nie mają znaczenia. Są rozmieszczone w miarę równomiernie.

0

A to jeszcze ten kod jest w pętli :) nie zauważyłem.

cout << progress_signs[no % 4] << " " << c_txt << flush;
To jako pierwsze może trochę zwalniać przy tylu obiektach. Iostream jest wolniejsze, bo dużo rzeczy sprawdza za nim coś zrobi. Co to jest progress_signs ? Tablica obiektów jakieś klasy ?

Operacje dyskowe są najkosztowniejsze. Najlepiej by było zapisać jak najwięcej w jednym wywołaniu funkcji, binarnie.

0

char progress_signs[4] = {'/', '-', '\\', '|'};
Odkryłem, że po jakimś czasie długo trwa wykonaniei_BMU winner = Run(*xit);

0

char progress_signs[4] = {'/', '-', '\', '|'};

To spokojnie tamtą instrukcje możesz zamienić na
printf('%c %s", progress_signs[no % 4], c_txt);
%s jeżeli c_txt to tablica char

Odkryłem, że po jakimś czasie długo trwa wykonanie

Włącz debugger i zobacz jakie wartości przyjmują zmienne kolejnych *xit.

0

W innym miejscu mam kod:

vec get_X(int nr) {
	list<vec>::iterator	it = xx.begin();
	advance(it, nr);
	return *it;
}
bool juz_wylosowany(int n) {
	for (list<int>::iterator it=wylosowane_x.begin(); it!=wylosowane_x.end(); ++it) {
		if (*it == n)	return true;
	}
	return false;
}
vec LosujX() {
	int	nr;
	if (wylosowane_x.size() == (int)((100-test_perc)*P/100))		wylosowane_x.clear();
	while(true) {
		nr = rand() % (int)((100-test_perc)*P/100);
		if (!juz_wylosowany(nr))	break;
	}
	wylosowane_x.push_back(nr);
	vec x = get_X(nr);
	wylosowany_x = nr;
	return x;
}


// (...)

for (int i=0; i<epok; i++, k++) {
	cout << " Processing epoch " << lpad(i+1," ",(int)ceil(log1p(epok)/log(10.0))) << " of " << epok << "   ";
	con_STO();	// zapamiętaj pozycję kursora (m.in.)
	for (int Pi=0; Pi<P; Pi++) {
		// -- wskaznik pracy
		if (Pi % 9 == 0) {
			con_RCL();
			sprintf(c_txt, "%.1f%% ", (double)(Pi+1)/P*100);
			cout << progress_signs[Pi % 4] << " " << c_txt << flush;
		}
		vec dajx = LosujX();
		i_BMU winner = Run(dajx);

		// podaj wspolrzedne zwyciezcy na mapie
		winner_x = winner.x;
		winner_y = winner.y;
		Change_W();
		Change_P();
	}
	con_RCL(); cout << "            ";		// zamaż wskaźnik pracy

//	CalculateUmatrix(0);
	cout << endl;
}
	cout << "Teaching done.\n\n";

i on nie zwalnia, choć kilka razy przechodzi przed wszystkie wektory z xx, ale w losowej kolejności.

0

Powodem spowolnienia może być wiele rzeczy.
Wyciek pamięci, systematyczne zwiększanie się złożoności obliczeniowej kolejnych przebiegów pętli.
Przy takiej ilości kodu (a z tego co widzę to jest tylko wycinek) przydałby się opis co to robi i w jaki sposób, bo może właśnie w tym sposobie kryje się problem.
Z takich prostych błędów kodowania to widzę przekazywanie dużego obiektu poprzez wartość. Przykładowo: i_BMU Run(vec x) powinno być raczej: i_BMU Run(const vec &x).

Poza tym dobra rada: trzymaj się jakiejś konwencji nazewnictwa. Przykładowo: wszystkie typy zaczynają się od dużej litery, a metody zaczynają się od małej litery (albo nawet zastosuj notację węgierską).

Zgadzam się też z jednym z powyższych komentarzy. Po co mieszać C i C++. Jak już używasz string to nie konwertuj bez przerwy C-String i std::string (w jedną i w drugą stronę). Użyj std::cout jest nieco wolniejsze, ale o niebo wygodniejsze.

Najważniejsze to podziel kod na mniejsze jednostki (funkcje). Łatwiej się takie coś czyta rozumie i poprawia.
Limit 20 linii na funkcję to maks (poza drobnymi wyjątkami). Jestem pewien, że ten kolos main jest nawet dla ciebie koszmarem w próbie ogarnięcia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1