[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [linux-team] resultats bizarre pour context switch process/thread



On Thu, Aug 05, 1999 at 11:41:37AM +0200, Frédéric Detienne wrote:
> Je ne suis pas bien sur de comprendre... tu as utilise quelle librairie pour
> les threads ? Quelle version du kernel ? Comment mesures-tu ?

Desole. J'etais tellement traumatise :) par les resultats que j'en ai oublie de
parler un peu de ma facon de proceder:
kernel 2.2.10, glibc 2.1.2pre??
La synchro entre processus se fait par IPC, avec deux semaphores, et une zone
de memoire partagee pour entrer les resultats.
La synchro entre threads utilise un mutex et une condition.

Pour mesurer, j'utilise une instruction asm qui renvoie le nombre de cycles
depuis le demarrage de la machine. En faisant la difference et en divisant par
la vitesse du processeur, on obtient le temps entre les deux mesures. En
supposant que les autres operations ne sont pas trop couteuses (quelques cycles
a peine), ce temps est celui du changement de contexte.

Il est peut-etre bon de signaler que je ne connais pas l'assembleur, j'ai
recopie la fonction en question et pour le reste j'ai fait des suppositions.

> Je veux bien voir le code.

Bon, comme il n'est vraiment pas gros, je l'inclus ici. Deux fichiers, un pour
les threads, un pour les processus.
 
Un petit appel a strace montre que la synchro entre threads genere beaucoup
d'appels systemes et utilise apparement des signaux. J'en deduis que c'est la
que le temps est perdu.

-- 
    Frederic Dumont           / /  (_)__  __ ____  __
 frederic.dumont@gate71.be   / /__/ / _ \/ // /\ \/ /
    PGP key 0711F125        /____/_/_//_/____/ /_/\_\  forever!!!!!!!
Linux? It's an OS, Jim, but not as we know it.
#include<stdio.h>
#include<pthread.h>

#define MHZ 166.0

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

unsigned long long times[30];
enum { thread1, thread2 } owner;

inline unsigned long long
cycle_counter(void)
{
	unsigned long low, high;
	__asm__ __volatile__("rdtsc;"
			     "movl %%eax, %0;"
			     "movl %%edx, %1"
			     : "=r" (low), "=r" (high)
			     : /* no input */
			     : "eax", "edx");
	return (((unsigned long long) high << 32) | (unsigned long long) low);
}

void *
pthread_routine(void *val)
{
	int i;

	pthread_mutex_lock(&lock);
	for(i=0;i<10;i++) {
		while(owner!=thread2) {
			pthread_cond_wait(&cond,&lock);
		}
		times[i<<1]=cycle_counter();
		owner=thread1;
		pthread_cond_signal(&cond);
	}
	pthread_mutex_unlock(&lock);
	return NULL;
}

int
main(void)
{
	pthread_t thread;
	int i;

	owner=thread1;
	pthread_mutex_lock(&lock);

	pthread_create(&thread, NULL, pthread_routine, NULL);

	for(i=0;i<10;i++) {
		owner=thread2;
		pthread_cond_signal(&cond);
		while(owner!=thread1) {
			pthread_cond_wait(&cond,&lock);
		}
		times[(i<<1)+1]=cycle_counter();
	}
	pthread_mutex_unlock(&lock);

	for(i=0;i<20;i++) {
		fprintf(stderr, "Switch: %#llx\n", times[i]);
	}

	{
		double avg = 0.0, val;

		for(i=2;i<19;i++) {
			val=((double)(times[i]-times[i-1]))/MHZ;
			fprintf(stderr, "Diff: %.2fus\n", val);
			avg+=val;
		}
		avg/=17.0;
		fprintf(stderr, "Average time: %.2fus\n", avg);
	}
}
#include<stdio.h>
#include<assert.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>

#define MHZ 166.0		/* changer en fonction de la vitesse du proc */

int semaphore;
int share_mem;
unsigned long long *array;

inline void set_sem(int s)
{
	struct sembuf op={s,1,0};
	semop(semaphore,&op,1);
}

inline void get_sem(int s)
{
	struct sembuf op={s,-1,0};
	semop(semaphore,&op,1);
}

void init()
{
	key_t key;
	char proc_id='C';
	
	if((key=ftok("/home/fdumont/test/c",proc_id))==-1) {
		perror("init,key");
		exit(1);
	}

	if((semaphore=semget(key,2,IPC_CREAT|0660))==-1) {
		perror("init,semget");
		exit(1);
	}
	if((share_mem=shmget(key,20*sizeof(unsigned long long),
				 IPC_CREAT|0660))==-1) {
		perror("init,shmget");
		exit(1);
	}
	set_sem(0);
	if((array=(unsigned long long*)shmat(share_mem,NULL,0))
	          ==(unsigned long long*)-1) {
		perror("init,shmat");
		exit(1);
	}
}

void cleanup()
{
	shmdt(array);
	semctl(semaphore,0,IPC_RMID,0);
	shmctl(share_mem,IPC_RMID,NULL);
}

inline unsigned long long cycle_count()	/* fonction _magique_ */
{
	unsigned long low, high;
	__asm__ __volatile__("rdtsc;"
			     "movl %%eax, %0;"
			     "movl %%edx, %1"
			     : "=r" (low), "=r" (high)
			     : /* no input */
			     : "eax", "edx");
	return (((unsigned long long) high << 32) | (unsigned long long) low);
}

int main()
{
	pid_t child;
	int i;
	
	init();
	assert((child=fork())!=-1);
	if(child) 	/* son */
	{
		for(i=0;i<10;i++) {
			get_sem(1);
			array[(i<<1)+1]=cycle_count();
			set_sem(0);
		}
	}
	else 		/* father */
	{
		for(i=0;i<10;i++) {
			get_sem(0);
			array[i<<1]=cycle_count();
			set_sem(1);
		}
		get_sem(0);
		for(i=0;i<20;i++)
			fprintf(stderr, "Switch: %#llx\n", array[i]);
		{
			double avg = 0.0, val;
			for(i=2;i<19;i++) {
				val=((double)(array[i]-array[i-1]))/MHZ;
				fprintf(stderr, "Diff: %.2fus\n", val);
				avg+=val;
			}
			avg/=17.0;
			fprintf(stderr, "Average time: %.2fus\n", avg);
												}
	}
	cleanup();
	return 0;
}