English | Magyar
JS ki | CSS ki | Ékezetek ki | HiContrast
Lapozó:  (0 - 1424) 
<== | ==>
Ugrás a végére | Összes megjelenítése | Utolsó oldal
OpenOpera patches | Opera-SSL patches | Opera 12.15 source (Git repository) | Opera 12.15 source (Torrent) | Opera internal pages | Otter Browser Linux x64 - Qt5.15.2/QtWebKit5.602.1 (2024.04.27. 20:05)
OS for MC680x0 | OS for PPC | OS for Sparc64 | besztofbégéaefcé | CSÉNDZSLOG | WebToolz | DDG Shit Filter | Google Shit Filter | Progz | Fast CSS Box | Browser | OS | Agent | Statisztika | BBCode
Monospace font-family: Courier New | Browser default monospace
Email értesítő / Email notification ===> 
Keresés
Σ: 1 post

TCH  (statz) Főfasz
#1, Főfasz (10443)
8792 | #2d09 | ^ | Idézet | Tue, 03 Jun 2014 03:16:16 +02
188.36.*.* Linux x86 Opera Classic Hungary *.catv.pool.telekom.hu
Jegesmedvementes jó estét kívánok retkes hallgatóinknak, ez itten a basszunk lovat optimalizállyunk rovat, mai témánk a stringtömbök egyberagasztása; melyik módszer lassú, vagy nem gyors, avagy kurjunk kecskét minden pénteken fogászati célból bencsmárkollyunk. Van ugye a lóbaszó folyamatosan allokálós fajta, ami azt csinálja, hogy egy ciklusban végigmegy a stringtömbön és minden körben újraallokálja a célbuffert, hogy beleférjen a következő adag is.
char *implode_ac(char *separator, char *strings[], long long int count)
{
	unsigned long long int retlen, lpos, tmp;
	long long int i;
	unsigned int seplen;
	char *result;

	if ((separator == NULL) || (strings == NULL))
	{
		return NULL;
	}
	retlen = 0;
	result = malloc(retlen);
	if (result == NULL)
	{
		return NULL;
	}
	seplen = strlen(separator);
	--count;
	lpos = 0;
	for (i = 0; i < count; ++i)
	{
		tmp = strlen(strings[i]);
		retlen += tmp + seplen;
		result = realloc(result, retlen);
		if (result == NULL)
		{
			return NULL;
		}
		strcpy((char *)(result + lpos), strings[i]);
		strcpy((char *)(result + lpos + tmp), separator);
		lpos = retlen;
	}
	retlen += strlen(strings[i]) + 1;
	result = realloc(result, retlen);
	if (result == NULL)
	{
		return NULL;
	}
	strcpy((char *)(result + lpos), strings[i]);
	return result;
}
Alapiskola, semmi extra nem szükséges hozzá.

Aztán van a csirkés egyszer allokálós módszer, amiben két ciklus van, az egyik előbb összeszámolja a szükséges helyet, majd egyszer allokál, aztán másol.
#define loccpy_ao \
/* BEGIN LOCCPY */\
	while (*src)\
	{\
		*dst++ = *src++;\
	}\
/* END LOCCPY */\
\

char *implode_ao(char *separator, char *strings[], long long int count)
{
	unsigned long long int retlen;
	long long int i;
	unsigned int seplen;
	char *result;
	char *src;
	char *dst;

	if ((separator == NULL) || (strings == NULL))
	{
		return NULL;
	}
	retlen = 0;
	seplen = strlen(separator);
	--count;
	for (i = 0; i < count; ++i)
	{
		retlen += strlen(strings[i]) + seplen;
	}
	retlen += strlen(strings[i]);
	result = malloc(retlen + 1);
	if (result == NULL)
	{
		return NULL;
	}
	dst = result;
	for (i = 0; i < count; ++i)
	{
		src = strings[i];
		loccpy_ao;
		src = separator;
		loccpy_ao;
	}
	src = strings[i];
	loccpy_ao;
	*dst = 0;
	return result;
}
Ez már egy birkafasznyit rázósabb, mert a másolásnál akad egy kis gond: ha a strcat()-tal másolunk, az mindig megkeresi a terminátort a cél végén, tehát a célnak újra és újra megméri a hosszát, ráadásul a cél egyre hosszabb ugye. Ha strcpy-val másolunk, akkor pedig nekünk kéne megmondani, hogy hova másoljon, vagyis kéne egy másodlagos pointer, hogy tudjuk, hogy épp hol a cél vége, amit viszont kézzel kell inkrementálgatni a források hosszával, vagyis itt újból végig kéne strlen()-elni másodjára is a tömböt, ami egyértelműen marhaság lenne; tehát fogjuk a célt és írunk mi custom inline strcpy-t, ahol a pointer mindig a cél végére mutat. Így csak egyszer kell végigszámolni a tömböt.

Nosza, akkor teszteljünk. Tesztprogramnak ennyi is elég
void main(int argc, char *argv[])
{
	int i;
	for (i = 0; i < 50000000; ++i)
	{
		free(implode_ac(":::", argv, argc));
	}
}
majd mi adunk nekik elég szemetet, amit összefűzhetnek. Először teszteljük le a folyamatosan allokálót:
root@Csabi:~# gcc -O2 test.c
root@Csabi:~# time a.out kecske macska anyad buzi lo tehen kurwa picsa geci fasz mocskosmikrofos apicsaba retkes fos fos fos fos kecske geci anyad hulye buzerans takony teve foskobold szar fos hugy

real    1m35.576s
user    1m35.604s
sys     0m0.000s
Írjuk át a meghívást az egyszer allokálósra (implode_ac => implode_ao) és teszteljük újra:
root@Csabi:~# gcc -O2 test.c
root@Csabi:~# time a.out kecske macska anyad buzi lo tehen kurwa picsa geci fasz mocskosmikrofos apicsaba retkes fos fos fos fos kecske geci anyad hulye buzerans takony teve foskobold szar fos hugy

real    0m42.211s
user    0m42.220s
sys     0m0.000s
Hoppá, több mint kétszer olyan gyors. Mondjuk nem csoda, a sok allokálgatás ezzel jár.

No, hát akkor ez a helyzet, hogy a két ciklust használó, egyszer allokáló verzió gyorsabb, mint az egy ciklust használó, folyamatosan allokálgató.
Máshogy meg nem lehet csinálni, hiszen vagy végignézzük előre az összeset, hogy tudjuk mennyi az annyi és utána hosszmérés nélkül másolhassunk, vagy menetközben számolgatjuk hozzá folyamatosan. A kettőt nem lehet kombinálni, hogy hosszmérés és allokálgatás nélkül csak másolunk, pedig az lenne az igazi...

Vagy esetleg mégis lehetne? Mi is gátolja meg, hogy ezt tegyük? Mármint azonkívül, hogy ahhoz, hogy másolhassunk, előbb allokálni kéne, ahhoz meg a hosszt kéne tudni, hogy tudjuk mennyit kell allokálni? De, ha jobban végiggondoljuk: vajon tényleg kell nekünk tudni a stringek hosszát, hogy allokálhassunk? Miért nem allokálunk hasraütésszerűen, aztán írunk bele, majd alkalomadtán kitoldván a puffert, ha elfogyott? Lássuk csak a kecskét!
#define prealloc \
/* BEGIN PREALLOC */\
	if (++ssize == asize)\
	{\
		asize += alloc_buffer;\
		result = realloc(result, asize);\
		if (result == NULL)\
		{\
			return NULL;\
		}\
	}\
/* END PREALLOC */\
\

#define loccpy_pa \
/* BEGIN LOCCPY_PA */\
	while (*src)\
	{\
		prealloc;\
		*dst++ = *src++;\
	}\
/* END LOCCPY_PA */\
\

char *implode_pa(char *separator, char *strings[], long long int count, unsigned long int alloc_buffer)
{
	char *result;
	char *dst;
	char *src;
	unsigned long long int asize, ssize;
	long long int i;

	if ((separator == NULL) || (strings == NULL))
	{
		return NULL;
	}
	asize = alloc_buffer;
	ssize = 0;
	result = malloc(asize);
	if (result == NULL)
	{
		return NULL;
	}
	--count;
	dst = result;
	for (i = 0; i < count; ++i)
	{
		src = strings[i];
		loccpy_pa;
		src = separator;
		loccpy_pa;
	}
	src = strings[i];
	loccpy_pa;
	prealloc;
	*dst = 0;
	return realloc(result, ssize);
}
Voila. A custom inline copyban használunk még két változót, az egyik az allokált memória méretét, a másik a valódi, kihasznált memória méretét tárolja. A cél és forráspointerek inkrementálása mellett így kell inkrementálni egy másik változót, valamint figyelni, hogy a következő körben overflow lenne-e már és ha igen, akkor allokálni egy újabb porciót. Így 100%-ig kiszűrünk mindenféle hosszmérést és az allokálások elsöprő többségétől is megszabadultunk; kettő db. tuti allokálás van, a többi már attól függ, hogy a stringtömb teljes hossza belefér-e az alapból allokált bufferbe, vagy sem; a bufferchunkok méretét pedig mi szabályozzuk. Már csak az a kérdés, hogy vajon jó-e az ötlet és ez tényleg gyorsabb-e, mint a folyamatosan allokálgató?
void main(int argc, char *argv[])
{
	int i;
	for (i = 0; i < 50000000; ++i)
	{
		free(implode_pa(":::", argv, argc, 256));
	}
}
Kicsit változtattunk a kódon, kell a bufferchunk mérete is. Teszt:
root@Csabi:~# gcc -O2 test.c
root@Csabi:~# time a.out kecske macska anyad buzi lo tehen kurwa picsa geci fasz mocskosmikrofos apicsaba retkes fos fos fos fos kecske geci anyad hulye buzerans takony teve foskobold szar fos hugy

real    0m37.332s
user    0m37.336s
sys     0m0.004s
A válasz egyértelmű igen. Az egyszer allokálgatós módszer gyenge pontjai, a két ciklus és a hosszméregetés így megszűnt, ez cca. 13%-os sebességnövekedést hozott. Itt a cucc egybe, kulcsrakészen (implode.c)
#ifndef _IMPLODE_C
#define _IMPLODE_C 1

#include <stdlib.h>

#define prealloc \
/* BEGIN PREALLOC */\
	if (++ssize == asize)\
	{\
		asize += alloc_buffer;\
		result = realloc(result, asize);\
		if (result == NULL)\
		{\
			return NULL;\
		}\
	}\
/* END PREALLOC */\
\

#define loccpy \
/* BEGIN LOCCPY */\
	while (*src)\
	{\
		prealloc;\
		*dst++ = *src++;\
	}\
/* END LOCCPY */\
\

char *implode(char *separator, char *strings[], long long int count, unsigned long int alloc_buffer)
{
	char *result;
	char *dst;
	char *src;
	unsigned long long int asize, ssize;
	long long int i;

	if ((separator == NULL) || (strings == NULL))
	{
		return NULL;
	}
	asize = alloc_buffer;
	ssize = 0;
	result = malloc(asize);
	if (result == NULL)
	{
		return NULL;
	}
	--count;
	dst = result;
	for (i = 0; i < count; ++i)
	{
		src = strings[i];
		loccpy;
		src = separator;
		loccpy;
	}
	src = strings[i];
	loccpy;
	prealloc;
	*dst = 0;
	return realloc(result, ssize);
}

#endif
Köszönöm a figyelmetlen segget, bikacsököt bilgécnek és a kurwa anyját a mikrofosnak.


English | Magyar
JS ki | CSS ki | Ékezetek ki | HiContrast
Lapozó:  (0 - 1424) 
<== | ==>
Ugrás a végére | Összes megjelenítése | Utolsó oldal
OpenOpera patches | Opera-SSL patches | Opera 12.15 source (Git repository) | Opera 12.15 source (Torrent) | Opera internal pages | Otter Browser Linux x64 - Qt5.15.2/QtWebKit5.602.1 (2024.04.27. 20:05)
OS for MC680x0 | OS for PPC | OS for Sparc64 | besztofbégéaefcé | CSÉNDZSLOG | WebToolz | DDG Shit Filter | Google Shit Filter | Progz | Fast CSS Box | Browser | OS | Agent | Statisztika | BBCode
Monospace font-family: Courier New | Browser default monospace
Email értesítő / Email notification ===> 
Keresés

Név: (max 255 byte)

Email: (max 255 byte) Nem kötelező!

Üzenet: (max 65536 kar.) 65536-0=65536




crap_vkn v4.34.0 by TCH
Thx to saxus for the escaped string decoder function (PHP), the realIP function (PHP) & the SQL handle layer (PHP), to thookerov for the int_divide function (PHP), to Jeff Anderson for the getSelText function (JS), to Alex King for the insertAtCursor function (JS), Flood3r for the new CSS styles, Pety for the spamprotection idea and some design and comfort ideas, MaxMind for the IP2Country database, famfamfam for the flags of countries and an unknown PHP programmer for the removeAccents function.



Kecskebaszók ide!