This is the mail archive of the crossgcc@sourceware.org mailing list for the crossgcc project.

See the CrossGCC FAQ for lots more information.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: crosstool-ng: cross compiler for -mach=arm4vt (Cirrus Logic EP93xx target)


On 9/12/09, Khem Raj <raj.khem@gmail.com> wrote:
> On (11/09/09 23:20), Martin Guy wrote:
>  >         --the compiler itself-- --on gcc-4.3.2 stage1--
>  > Version  gcc     cc1     cc1    Elapsed Max VM  xgcc
>  >          text    text    data   time    used    text
>  > gcc-3.4  79579  3862155   3236  4m30    104128  209509
>  > gcc-4.0  86429  4579965  10208  4m44    111104  225846
>  > gcc-4.1 193369  5115620  15976  4m56    123264  226469
>  > gcc-4.2 188582  5490547  17364  4m50    112128  221171
>  > gcc-4.3 203918* 7010746 420820  6m41    157440  227755
>  > gcc-4.4 202989* 9431805 546128  8m21    170550  249260
>  > llvm4.2 189365                  4m56     67136  236957
>
> Did you compile exact same insn_recog.c source ?

I built the same source tree gcc-4.3.2 (4.3.4 above was a typo) with
the same configuration line and CC=gcc-X.Y on x86.

What I've called "Max VM" here is obtained from the process accounting
records for the build run on an otherwise silent machine
It is the maximum value of the per-process "average VM usage", not the
high-water mark you see by watching "top" (216MB for 4.3). I can't
think of an easy way to measure the HWM.
You need a custom program to extract the top avg VM usage.
I used "lc" whose source is visible under
martinwguy.co.uk/martin/src/acct
lc | cut -c 52- | sed 's/ .*//' | sort -rn | head -1

    M

(BTW this is off topic for crossgcc any more)
/*
 *	lc - Visualizza gli ultimi commandi eseguiti
 *
 *	Per difetto, legge l'archivio ACCT_FILE. Se viene dato un parametro,
 *	legge quel file piuttosto.
 *
 *	Martin Guy, Catania, ottobre 2000
 *
 *	Modified dicembre 2002  x aggiungere -r (reverse-reverse-order flag)
 */

#include <stdio.h>
#include <stdlib.h> /* for exit() */

#ifdef linux
#include <linux/acct.h>	/* per struct acct etc. */
typedef struct acct_v3 acct_t;
#else
#include <sys/acct.h>	/* per struct acct etc. */
typedef struct acct acct_t;
#endif

#include <pwd.h>	/* per struct passwd, getpwuid() etc. */
#include <grp.h>	/* per convertire gid in nome gruppo */
#include <sys/time.h>	/* per select() */
#include <sys/types.h>	/* per dirent.h */
#include <dirent.h>	/* per opendir(), readdir() closedir() */
#include <sys/stat.h>	/* per lstat() */
#include <unistd.h>	/* per lstat() */
#include <time.h>	/* per struct tm etc */
#include <string.h>	/* per strchr() */
#include <sys/wait.h>	/* per decodificare exit status (macro W*()): richiede sys/types.h */

#include "comp_t.h"

/* Location of accounting file, which can be anywhere accoding to your distro.
 * Other favourite locations are /usr/adm/pacct /var/log/pacct and similar.
 */
#define ACCT_FILE "/var/log/account/pacct"

/* Alcuni parametri per la formattazione */
#define PWNAME_LEN	8	/* Stimata massima lunghezza del nome utente */
#define GRNAME_LEN	8	/* ditto nome gruppo */
#define TTYNAME_LEN	5	/* ditto nome tty (ttyS0, diciamo) */
#define TIME_LEN	4	/* ditto per CPU time e tempo trascorso */
/* N.B. anche print_ac_time() ipende del valore TIME_LEN per scegliere i vari
 * formati di stampa. Modificando TIME_LEN, bisogna anche modificare questa
 * funzione. */
#define DATE_LEN	16	/* Larghezza di data/ora prodotta da strftime */

static void usage(void);
static void do_backwards(FILE *acct_fp);
static void do_forwards(FILE *acct_fp);
static void do_follow(FILE *acct_fp);
static void print_ac_header(void);
static void print_ac(acct_t *a);
static void print_ac_time(comp_t atime, int int_width);
static void print_ac_date(time_t atime);
static void print_ac_tty(u_int16_t atty);
static void print_ac_exitcode(u_int32_t exitcode);

/* Se diversi di NULL, questi fanno vedere soltanto alcune record */
static char *sw_user = NULL;	/* per un'utente */
static char *sw_group = NULL;	/* per un gruppo */
static char *sw_tty = NULL;	/* su una tty */
static char *sw_cmd = NULL;	/* di un comando */

static int sw_follow = 0;	/* Fare come tail -f */
static int sw_forwards = 0;	/* Stampa nell'ordine in cui si trova nel file */

static u_int16_t sw_uid;	/* se sw_user != NULL, questo e` l'uid. */
static u_int16_t sw_gid;	/* se sw_group != NULL, questo e` il gid. */
static u_int16_t sw_ttydev;	/* se sw_tty != NULL, questo e` il major/minor del device. */

static char *argv0;	/* argv[0] for error reporting */

main(int argc, char **argv)
{
	char *acct_file = ACCT_FILE;
	FILE *acct_fp = NULL;

	argv0 = argv[0];

	/* Process switches (metodo all'antico...) */
	while (argc > 1 && argv[1][0] == '-') {
		char *arg;	/* seconda parte dei parametri di 2 arg */
		char sw;	/* ricorda carattere del flag */

		switch (sw = argv[1][1]) {
		case 'f':	/* Segui l'output mentre si aggiunge */
			sw_follow = 1;
			break;
		case 'r':	/* Stampa nell'ordeine del file */
			sw_forwards = 1;
			break;
		case 'u':	/* Stampa solo righe per utente X */
		case 'g':	/* Stampa solo righe per gruppo X */
		case 't':	/* Stampa solo righe per tty X */
		case 'c':	/* Stampa solo righe per comando X */
			if (argv[1][2] != '\0') arg = &(argv[1][2]);
			else if (argc < 3) usage();
			else {
				arg = argv[2];
				argv++; argc--;
			}
			switch (sw) {
			case 'u': sw_user = arg; break;
			case 'g': sw_group = arg; break;
			case 't': sw_tty = arg; break;
			case 'c': sw_cmd = arg; break;
			}
			break;
		case '\0':
			acct_file = "-";
			acct_fp = stdin;
			break;
		default:
			usage();
		}
		argv++; argc--;
	}

	/* Dovrebbe rimanere soltanto il nome facoltativo dell'archivio
	 * contabile */
	switch (argc) {
	case 1:
		break;
	case 2:
		if (acct_fp != NULL) {
			fputs("Specify one accounting file only.\n", stderr);
			exit(1);
		}
		acct_file = argv[1];
		break;
	default:
		usage();
		/* NOTREACHED */
	}

	/* Converte nome utente in uid ecc per filtraggio dei record */
	if (sw_user != NULL) {
		if (isdigit(sw_user[0])) sw_uid = atoi(sw_user);
		else {
			struct passwd *pw;
			pw = getpwnam(sw_user);
			if (pw == NULL) {
				fprintf(stderr, "%s: No such user \"%s\".\n",
					argv0, sw_user);
				exit(1);
			}
			sw_uid = pw->pw_uid;
		}
	}

	/* Converte nome gruppo in gid */
	if (sw_group != NULL) {
		if (isdigit(sw_group[0])) sw_gid = atoi(sw_group);
		else {
			struct group *gr;
			gr = getgrnam(sw_group);
			if (gr == NULL) {
				fprintf(stderr, "%s: No such group \"%s\".\n",
					argv0, sw_group);
				exit(1);
			}
			sw_gid = gr->gr_gid;
		}
	}

	/* Converte nome device in coppia major/minor */
	if (sw_tty != NULL) {
		int maj, min;
		/* Prima, controlla coppia esplicita maj/min */
		if (sscanf(sw_tty, "%d/%d", &maj, &min) == 2) {
			sw_ttydev = ((maj & 0xff) << 8) | (min & 0xff);
		} else {
			char devname[80]; /* speriamo che basti... */
			struct stat stbuf;

			sprintf(devname, "/dev/%s", sw_tty);
			if (stat(devname, &stbuf) != 0) {
				fprintf(stderr, "%s: Cannot stat ", argv0);
				perror(devname);
				exit(1);
			}
			sw_ttydev = stbuf.st_rdev;
		}
	}

	if (acct_fp == NULL) {
		acct_fp = fopen(acct_file, "r");
		if (acct_fp == NULL) {
			fputs("lc: Cannot read file ", stderr);
			perror(acct_file);
			exit(1);
		}
	}

	print_ac_header();

	if (sw_forwards) {
		do_forwards(acct_fp);
		if (sw_follow)
			/* forwards AND follow */
			/* We may miss a record or two if they were added
			 * between our EOF in do_forwards and our lseek()
			 * in do_follow().  Oh well...
			 */
			do_follow(acct_fp);
	} else {
		if (sw_follow) {
			do_follow(acct_fp);
		} else {
			do_backwards(acct_fp);
		}
	}

	exit(0);
}

static void
usage(void)
{
	fputs("Usage: lc [-f] [-u user] [-g group] [-t tty] [-c command] [acct_file]\n\
-f	Follow the accounting file: prints new records as they are added\n\
-u user	Only show records for a particular user (or numerical user-id)\n\
-g group Only show records for a group (or numerical group-id)\n\
-t tty	Only show records associated with a particular control terminal\n\
-c cmd	Only show records for a particular command\n\
Flags:\n\
F	Executed fork() but did not exec()\n\
S	used super-user privileges\n\
D	dumped core\n\
X	was killed by a signal\n\
Fields:\n\
USER	Real user name or user id\n\
TTY	Control terminal\n\
START	Process creation time\n\
USER	User CPU time\n\
SYS	System CPU time\n\
REAL	Elapsed time\n\
MEM	Average memory usage\n\
MIN	Minor page faults\n\
MAJ	Major page faults\n\
SW	Number of swaps\n\
EX	Exit code: if positive, this is the process' regular exit status;\n\
		   if negative, the untrapped signal that killed the process\n\
CMD	Command name\n", stderr);
	exit(1);
}

/*
 * Il solito modus operandi: Stampa i piu` recenti per primo, come "last".
 */
static void
do_backwards(FILE *acct_fp)
{
	acct_t a;

	if (fseek(acct_fp, (long) -sizeof(acct_t), SEEK_END) != 0) {
		perror("lc: Cannot seek to last record");
		exit(1);
	}

	while (fread(&a, sizeof(acct_t), 1, acct_fp) == 1) {
		print_ac(&a);

		/*
		 * Seek back over the record we just read and position at the
		 * start of the previous one. N.B. The manual doesn't say that
		 * we can do negative seeks, so we may have to change strategy
		 * to measure the size of the file at startup, then seek to
		 * explicit offsets.
		 */
		if (fseek(acct_fp, (long) (-sizeof(acct_t) * 2), SEEK_CUR) != 0) break;
	}
}

/*
 * l'insolito modus operandi: Stampa i piu` vecchi per primo.
 */
static void
do_forwards(FILE *acct_fp)
{
	acct_t a;

	rewind(acct_fp);	/* "cannot" fail */

	while (fread(&a, sizeof(acct_t), 1, acct_fp) == 1) {
		print_ac(&a);
	}
}

/*
 * Mostra i nuovi record mentre arivano, alla "tail -f".
 */
static void
do_follow(FILE *acct_fp)
{
	acct_t a;
	/* Roba per select() */
	fd_set rfds;
	int retval;

	FD_ZERO(&rfds);
	FD_SET(fileno(acct_fp), &rfds);

	/* Seek to end of accounting file.
	 * if sw_follow and sw_forwards are both true, do_follow() is
	 * called *after* sw_forwards, and the file pointer is already
	 * positioned at the next record we should print (or at EOF).
	 */
	if (!sw_forwards) {
		if (fseek(acct_fp, 0L, SEEK_END) != 0) {
			perror("lc: Cannot seek to last record");
			exit(1);
		}
	}

	for(;;) {
		while (fread(&a, sizeof(acct_t), 1, acct_fp) == 1) {
			print_ac(&a);
		}
		if (ferror(acct_fp)) {
			perror("Error reading accounting file");
			exit(1);
		}
#if 0
		if (select(fileno(acct_fp) + 1, &rfds, NULL, NULL, NULL) != 1) {
			perror("Error waiting for data");
			exit(1);
		}
#else
		/*
		 * select() is also "ready" on end-of-file, so is useless here,
 		 * and makes us loop taking 100% CPU!
		 */
		sleep (1);
#endif
	}
}

/* Stampa intestazione all'inizio della listata */
static void
print_ac_header(void)
{
	fputs("\
FLAG USER     TTY   START           USER SYS  REAL MEM  MIN MAJ SW EX CMD\
\n", stdout);
}

/* Decodifica e stampa un record contabile */
static void
print_ac(acct_t *a)
{
	struct passwd *pw;
	struct group *gr;

	/* Prima, controlla se dobbiamo excludere questo record */
	if (sw_user != NULL && a->ac_uid != sw_uid) return;
	if (sw_group != NULL && a->ac_gid != sw_gid) return;
	if (sw_tty != NULL && a->ac_tty != sw_ttydev) return;
	if (sw_cmd != NULL && strcmp(a->ac_comm, sw_cmd) != 0) return;

	/* Decodifica dei flag */
	printf("%c%c%c%c ",
		(a->ac_flag & AFORK)   ? 'F' : ' ',
		(a->ac_flag & ASU)     ? 'S' : ' ',
	/* printf("%c", (a->ac_flag & ACOMPAT) ? 'C' : ' '); Solo sul VAX */
		(a->ac_flag & ACORE)   ? 'D' : ' ',
		(a->ac_flag & AXSIG)   ? 'X' : ' ');

	/* Decodifica del nome dell'utente contabile */
	pw = getpwuid(a->ac_uid);
	if (pw != NULL) {
		/* Nome utente, allineato a sinistra */
		printf("%-*s ", PWNAME_LEN, pw->pw_name);
	} else {
		/* Conversione in nome utente fallito: stampa uid numerico
		 * allineato a sinistra */
		printf("%-*d ", PWNAME_LEN, a->ac_uid);
	}

#ifdef SHOW_GROUP
	/* E del gruppo contabile */
	gr = getgrgid(a->ac_uid);
	if (gr != NULL) {
		printf("%-*s ", GRNAME_LEN, gr->gr_name);
	} else {
		printf("%-*d ", GRNAME_LEN, a->ac_gid);
	}
#endif

	/* Stampa nome del Control Terminal */
	print_ac_tty(a->ac_tty);

	/* Start time in seconds since the epoch (as unsigned 32-bit int) */
	print_ac_date((time_t) a->ac_btime);

/*
  Campi utime fino a swaps sono di tipo comp_t.
  comp_t is a 16-bit "floating" point number with a 3-bit base 8
  exponent and a 13-bit fraction. See linux/kernel/acct.c for the
  specific encoding system used.
*/
	/* User and system CPU use, and elapsed times, presumably in AHZ. */
	print_ac_time(a->ac_utime, 1); fputs(" ", stdout);
	print_ac_time(a->ac_stime, 1); fputs(" ", stdout);
	print_ac_time(a->ac_etime, 2); fputs(" ", stdout);

	printf("%4ld ", decode_comp_t(a->ac_mem));
	/* printf("%d ", decode_comp_t(a->ac_io));	/* Sempre 0? */
	/* printf("%d ", decode_comp_t(a->ac_rw));	/* Sempre 0? */
	printf("%3ld ", decode_comp_t(a->ac_minflt));
	printf("%3ld ", decode_comp_t(a->ac_majflt));
	printf("%ld ", decode_comp_t(a->ac_swaps));
	print_ac_exitcode(a->ac_exitcode);
	printf("%s\n", a->ac_comm);
}

/* Stampa secondi di CPU o tempo reale in 4 caratteri.
 * fino a 10 secondi, stampiamo 1.24
 * da 10 secondi fino ad un minuto, stampiamo 13.4
 * da un minuto fino a dieci minuti, stampiano 3m42
 * da 10 minuti fino ad una ora, "45m"
 * da una ora fino a dieci ore, stampiano "3h24" (3 ore 24 minuti)
 * da 10 ore in poi, stampiamo "24h" ecc.
 *
 * Non facciamo arrotondamento.
 */
#define MINSEC 60
#define HOURSEC 3600
static void
print_ac_time(comp_t atime, int int_width)
{
	unsigned long time = decode_comp_t(atime);
	double ftime = (double)time / (double)AHZ;	/* tempo in secondi */

	/* Se int_width == 2, la formattazione viene regolare fino a 99.99
	 * secondi; da 100 in poi, spinge il resto della riga a destra.
	 * 5.2f: minimo di 5 caratteri: 2 frazionali, il punto e 3 di intero.
	 */
	if (ftime < 10.0)	/* meno di 10 secondi */
		printf("%*.2f", TIME_LEN, ftime);
	else if (ftime < 60.0)	/* 10 secondi fino a 59.9 secondi */
		printf("%*.1f", TIME_LEN, ftime);
	else if (ftime < 600.0) /* un minuto fino a 9:59 minuti */
		printf("%1dm%02d", (int)ftime / 60, (int)ftime % 60);
	else if (ftime < 3600.0) /* 10 minuti fino a 59m */
		printf("%2dm ", (int)ftime / 60);
	else if (ftime < 36000.0) /* 1 ora fino a 9h59 */
		/* Dipende da 32-bit int! */
		printf("%dh%02d", (int)ftime / 3600, ((int)ftime/60)%60);
	else  printf("%3dh", (int)((long) ftime / 3600));
}

/* Converte numero del Control Terminal in nome del device.
 * 0 sembra significare "nessuno", mentre altri numeri sono fatti dal
 * major_device_number * 256 + minor_device_number
 *
 * L'algoritmo attuale e` inefficiente: fa la scansione di /dev ogni volta
 * per ripescare, in tutta probabilita, gli stessi nomi.
 *
 * Nel caso dei pts, siamo fregati.  Anche se li andiamo a cercare in
 * /dev/pts/*, la presenza di una tale voce dipende dalla presenza attuale
 * dell'utente.  Controlliamo per questo caso specifico (ugh!)
 */
static void
print_ac_tty(u_int16_t atty)
{
	DIR *d = NULL;		/* Puntatore a /dev per leggere i nomi */
	struct dirent *dirent;	/* Puntatore all'elemento attuale in /dev */
	char *ttyname = NULL;	/* Nome del device in questione, se trovato */
	static char *ttyname_cache[65536]; /* Init to NULL */

	if (ttyname_cache[atty] != NULL) {
		ttyname = ttyname_cache[atty];
	} else {
		if (atty == 0) ttyname = "-";
		else if ((atty & 0xff00) == 136<<8) {
			/* Pseudo-terminal. Emmettiamo "pts/n" */
			static char ptsname[8];	/* 3 + 1 + 3 + '\0' */

			sprintf(ptsname, "pts/%d", atty & 0xff);
			ttyname = ptsname;
		} else {
			/* Cerca device in /dev */
			d = opendir("/dev");
			if (d == NULL) {
				perror("lc: Cannot read /dev");
				exit(1);
			}
			while ((dirent = readdir(d)) != NULL) {
				static char devname[5 + NAME_MAX + 1];
				struct stat stbuf;

				sprintf(devname, "/dev/%s", dirent->d_name);
				if (lstat(devname, &stbuf) != 0) {
					fputs("lc: Cannot stat ", stderr);
					perror(devname);
					continue;	/* Non e` fatale */
				}
				
				/* Cerca device a caratteri con major & minor giusti */
				if (S_ISCHR(stbuf.st_mode) && stbuf.st_rdev == atty) {
					ttyname = dirent->d_name;
					break;
				}
			}

			if (ttyname == NULL) {
				static char majmin[8];
				/* Non e` stato trovato una device che corrisponde
				 * Stampa major/minor. */
				sprintf(majmin, "%d/%d", (atty >> 8) & 0xff, atty & 0xff);
				ttyname = majmin;
			}
		}
		/* Ricorda questo nome nella cache */
		ttyname_cache[atty] = strdup(ttyname);
	}

	/* Stampa info *prima* di chiamare closedir() perché lo spazio in
	 * cui il nome e` registrato appartiene a opendir/readdir */
	printf("%-*s ", TTYNAME_LEN, ttyname);

	/* Se l'abbiamo aperto, lo chiudiamo */
	if (d != NULL) closedir(d);
}

/* Stampa ora d'inizio processo, convertendo da numero di secondi dall'epoch */
static void
print_ac_date(time_t atime)
{
	struct tm *tm;		/* Ora decomposta in campi separati */
	char strtime[DATE_LEN+1];	/* Ora pronta da stampare */
	char *s, *p;
	
	tm = localtime(&atime);
	s = asctime(tm);
	/* Hack brutale per togliere giorno-di-settimana iniziale e anno finale,
	 * tenendo uno spazio finale. */
	printf("%.16s", s+4);
}

/* Stampa campo "exitcode", codificato come il campo "status" pescato da
 * wait(2), e cioe` con il valore passato ad exit() negli otto bit superiori,
 * il signal che l'ha ucciso negli 7 bit inferiori, e con bit 128 settato se
 * il processo ha lasciato un core dump (quest'informazione presente anche nel
 * campo "flags" del struct acct).
 * Non so se e` necessario stampare sia exit code sia segnale che l'ha ucciso;
 * m'immagino che coltanto uno dei due puo` avere un valore diverso da zero.
 *
 * Per distinguere in breve, le uccisioni per exit stampano valori positivi
 * (di solito 0-127) e per i segnali, valori negativi (i segnali sono di solito
 * di valori di una o de cifre).
 */
static void
print_ac_exitcode(u_int32_t exitcode)
{
	/* Soltanto uno di questi due dovrebbe mai essere vero */
	if (WIFEXITED(exitcode)) printf("%3d ", WEXITSTATUS(exitcode));
	if (WIFSIGNALED(exitcode)) printf("%3d ", -WTERMSIG(exitcode));
}
/*
 * comp_t.c
 *
 * Routine per la manipolazione dei record di accounting di Linux.
 *
 * decode_comp_t() converte le quantita` codificate in comp_t
 *	nel semplice numero che codifica.
 *
 * Martin Guy, FreakNet Medialab, Luglio 2001
 */

#include "comp_t.h"

#if 0
/* Da /usr/src/linux/kernel/acct.c */
/*
 *  encode an unsigned long into a comp_t
 *
 *  This routine has been adopted from the encode_comp_t() function in
 *  the kern_acct.c file of the FreeBSD operating system. The encoding
 *  is a 13-bit fraction with a 3-bit (base 8) exponent.
 */

#define	MANTSIZE	13			/* 13 bit mantissa. */
#define	EXPSIZE		3			/* Base 8 (3 bit) exponent. */
#define	MAXFRACT	((1 << MANTSIZE) - 1)	/* Maximum fractional value. */

static comp_t encode_comp_t(unsigned long value)
{
	int exp, rnd;

	exp = rnd = 0;
	while (value > MAXFRACT) {
		rnd = value & (1 << (EXPSIZE - 1));	/* Round up? */
		value >>= EXPSIZE;	/* Base 8 exponent == 3 bit shift. */
		exp++;
	}

	/*
         * If we need to round up, do it (and handle overflow correctly).
         */
	if (rnd && (++value > MAXFRACT)) {
		value >>= EXPSIZE;
		exp++;
	}

	/*
         * Clean it up and polish it off.
         */
	exp <<= MANTSIZE;		/* Shift the exponent into place */
	exp += value;			/* and add on the mantissa. */
	return exp;
}
#endif

/* Convertita nella funzione inversa... */
#define	MANTSIZE	13			/* 13 bit mantissa. */
#define	EXPSIZE		3			/* Base 8 (3 bit) exponent. */

unsigned long
decode_comp_t(comp_t comp)
{
	unsigned long value;
	int exp;

	exp = comp >> MANTSIZE;		/* Sappiamo che comp_t e` unsigned */
	value = comp & ((1<<MANTSIZE) - 1);

	return(value << (exp * 3));	/* Exponent is in base 8 */
}
/*
 * Declarations for clients of comp_t.c
 */

#ifdef linux
#include <linux/acct.h>
#else
#include <sys/acct.h>
#endif

unsigned long decode_comp_t(comp_t comp);

Attachment: Makefile
Description: Binary data

--
For unsubscribe information see http://sourceware.org/lists.html#faq

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]