25
dic
08

Ottimizzare il codice C – strlen

no, non è gesù bambino

no, non è gesù bambino

Prima di cominciare volevo ringraziare ancora una volta tutti i presenti alla cena pidduista di ieri sera e facebook che ci ha permesso di organizzarla.
Spero vi siate divertiti e comunque ricordo che non siamo riusciti a fare un minimo di cresta e quindi questo natale sarà ancora più povero.

Molti si chiedevano che fine ha fatto jiimbo, perchè non scrive più etc…beh jiimbo dopo aver dato 100 euro ad un avvocato per scrivere una lettera di 10 righe, battuta tralaltro in malomodo e con l’ausilio di sole due dita, aveva ben pensato di non scrivere nulla se non dietro pagamento (sennò qui tutti ce guadagnano meno che io).

Dopo l’altra sera però, dopo il calore dimostrato dai nostri fan, non posso non adempiere ai miei doveri ed ho deciso quindi di tornare a scrivere (si ma niente di serio, la solita sbroda tecnica).

In questo periodo chi mi conosce sa che sto tribbolando con la tesi così tanto che se me lo avessero detto prima sarei andato a parare le pecore a sei anni, ma si sa…a noi pidduisti piace tribbolare. Argomento? Stringhe e codifiche, più o meno quelle cose che dopo un po’ ti rendono pazzo furioso e ti fanno perdere contatto con la realtà.

Ho sperimentato personalmente l’halting problem e mi sono imbattuto in così tante bizzarie del C che oramai sono portato a pensare che se dio esiste veramente abbia scritto tutto in C (il C è potere, il java è costipazione). Da questa riflessione su la vita l’universo e tutto quanto ho deciso di scrivere qualcosa che possa far capire quanto ottimizzare il codice significhi in termini di tempo.

Tutti sanno che quando si deve scrivere codice performante in genere si scrive in C perchè è il linguaggio che ti permette di controllare ogni aspetto della programmazione e si sa che “un grande potere portà con se una grande responsabilità”. Spetta a noi quindi ottimizzare il più possibile il codice e spesso si fanno errori grossolani che rendono le nostre procedure inutilizzabili.

Tra i vari aspetti quello che forse in genere viene tralasciato è quello dell’utilizzo improprio di strlen (la funzione che ritorna la lunghezza della stringa (sempre che questa sia terminata da (altrimenti solo cristo lo sa))). Come sempre un bell’esempio è meglio di tante chiacchiere. Il programma che trovate esegue le seguenti procedure:

  • Esempio di vita reale: legge un file e, scorrendolo carattere per carattere, ne genera tutte le sottostringhe che partono dal carattere corrente fino alla fine della stringa.
  • Esempio banale: scorre il file carattere per carattere e conta i caratteri rimanenti da leggere.
/*
 * Casapiddu's code production
 * strlen_optimize.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>

int read_file(char *filename, char **textt, long *length)
{
  	char *text;
  	long t;
  	FILE *infile;

  	infile = fopen(filename, "rb");

	if (infile == NULL) {
		return 1;
	}

  	// store input file length
  	if (fseek(infile, 0, SEEK_END) !=0) {
		return 1;
	}
  	*length = ftell(infile);

  	// alloc memory for text
  	text = (char *) malloc ((*length) * sizeof(char) + 1);
	if (text == NULL) {
		return 1;
	}

  	//read text in one sweep
  	rewind(infile);
  	t = fread(text, sizeof(char), (size_t) *length, infile);
  	if (t != *length) {
	 	return 1;
	}
	text[*length] = '';
  	*textt = text;
  	fclose(infile);

  	return 0;
}

int substring_naive (char *str, long start, long offset, char **ret_substring) 
{
	char *ret;
	long end_pos = (start + offset < strlen(str)) ? start + offset : strlen(str) - 1;
	long i;
	ret = (char *) malloc ((end_pos - start + 2) * sizeof(char));
	
	i = start;
	for (i; i <= end_pos; i++) {
 		ret[i - start] = str[i];
	}
	ret[end_pos - start + 1] = '';
	*ret_substring = ret;
	
	return 0;
}

int substring (char *str, long start, long offset, long length, char **ret_substring) 
{
	char *ret;
	long end_pos = (start + offset < length) ? start + offset : length - 1;
	long i;
	ret = (char *) malloc ((end_pos - start + 2) * sizeof(char));
	
	i = start;
	for (i; i <= end_pos; i++) {
 		ret[i - start] = str[i];
	}
	ret[end_pos - start + 1] = '';
	*ret_substring = ret;
	
	return 0;
}

int main (int argc, char **argv)
{
	char *buffer;
	char *tmp_buffer;
	long length;
	long i;
	long j;
	time_t startTime, endTime;
	
	if (read_file(argv[1], &buffer, &length)) {
		printf("Error reading file.\n");
		exit(1);
	}

	time(&startTime);
	i = 0;	
	for (i; i < strlen(buffer); i++) {		
		substring_naive (buffer, i, strlen(buffer) - i - 1, &tmp_buffer);
		free(tmp_buffer);
	}
	time(&endTime);
	printf("Naive elapsed time: %f\n", difftime(endTime, startTime));
	
	time(&startTime);
	i = 0;	
	for (i; i < length; i++) {
		substring (buffer, i, length - i - 1, length, &tmp_buffer);
		free(tmp_buffer);
	}
	time(&endTime);
	printf("Smart elapsed time: %f\n", difftime(endTime, startTime));
	
	time(&startTime);
	i = 0;
	for (i; i < strlen(buffer); i++) {
		j = strlen(buffer) - i;
	}
	time(&endTime);
	printf("Naive monkey elapsed time: %f\n", difftime(endTime, startTime));
	
	time(&startTime);
	i = 0;
	for (i; i < length; i++) {
		j = length - i;
	}
	time(&endTime);
	printf("Smart monkey elapsed time: %f\n", difftime(endTime, startTime));
}

Di entrambe le procedure viene eseguita prima la versione con chiamate a strlen inutili e poi la versione ottimizzata. Il primo esempio ovviamente è quello da prendere più in considerazione visto che il secondo a meno di qualche problema cerebrale nessuno lo scriverebbe in quel modo (però fa scena vedere il gap :) ).

Per compilare basta gcc strlen_optimize.c
I miei risultati sulle prime 5000 righe di questo file sono:

  • Naive elapsed time: 815.000000
  • Smart elapsed time: 612.000000
  • Naive monkey elapsed time: 88.000000
  • Smart monkey elapsed time: 0.000000 (insomma molto ma molto poco)

P.S.: L’esempio riportato è su un file e quindi la lunghezza ce la prendiamo nel momento in cui lo portiamo in memoria. In caso di stringhe basta sostituire il

	for (i = 0; i < strlen(str); i++) { }

con

	while (str[i] != '') { i++; }

Se invece è necessario richiamare strlen, e lo si deve fare in più punti, è bene salvarsi il risultato in una variabile in modo da evitare le altre chiamate inutili.

Come sempre have fun and love C!

Mi sono accorto che è sol invictus (natale insomma) quindi sostituite i vari ieri sera con l’altroieri sera e tanti auguri a nome di tutti i pidduisti!

About these ads

5 Risposte a “Ottimizzare il codice C – strlen”


  1. 25 dicembre 2008 alle 4:10:31

    “il C è potere, il java è costipazione”

    questa frase me la incornicio e magari poi mel’autografi pure =)

  2. 25 dicembre 2008 alle 11:10:40

    solo che a casapiddu il giorno di natale pensiamo alle stringhe…

  3. 25 dicembre 2008 alle 15:04:53

    Solo perché stanotte non eri con noi tra Mario Kart e UT2004 sennò sapresti che abbiamo pensato molto spesso al bambino, a sua madre, a suo padre e in generale a tutto il sistema dei valori cristiani…

  4. 4 rospetti
    30 dicembre 2008 alle 16:50:08

    scrive du commenti no eh

  5. 30 dicembre 2008 alle 17:40:45

    ma che dici, sai che commento tutto e con stile…il mangi ne ha le prove :)


Lascia un Commento

Fill in your details below or click an icon to log in:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Connessione a %s...


Difendi Rebeldia!

Aggiungi ai tuoi feed

 RSS Feed
Add to Google
Add to My Yahoo!
Add to Technorati Favorites!
Add to netvibes

Blog Stats

  • 233,202 hits

Pidduisti on-line

hit counters


Made on a Mac
Last.fm
Giveaway of the Day
highlightInterests("ProfileMusica");
Musicatable.lfmWidget8f0839bdbf919d97305135788e54986d td {margin:0 !important;padding:0 !important;border:0 !important;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmHead a:hover {background:url(http://cdn.last.fm/widgets/images/en/header/chart/weeklytracks_regular_blue.png) no-repeat 0 0 !important;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmEmbed object {float:left;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmFoot td.lfmConfig a:hover {background:url(http://cdn.last.fm/widgets/images/en/footer/blue.png) no-repeat 0px 0 !important;;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmFoot td.lfmView a:hover {background:url(http://cdn.last.fm/widgets/images/en/footer/blue.png) no-repeat -85px 0 !important;}table.lfmWidget8f0839bdbf919d97305135788e54986d tr.lfmFoot td.lfmPopup a:hover {background:url(http://cdn.last.fm/widgets/images/en/footer/blue.png) no-repeat -159px 0 !important;}

pages

dicembre: 2008
L M M G V S D
« nov   gen »
1234567
891011121314
15161718192021
22232425262728
293031  

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

%d bloggers like this: