Well, I can't see what the problem is. I was thinking maybe your use of
locks left one CPU thread waiting for the other CPU for a while, but that
doesn't seem like it would happen here.
So each of these threads, when run alone, takes very little time to
execute, but run concurrently (1 per cpu) they each take a very long time?
Hmmm. One other possibility is overflow of the 'duration' variable..
but.. even if that happens you would probably get reported run times that
are LOW not high... and at any rate I don't see why each of those loops
should take even longer than 1ms to process. Very strange indeed!
On Tue, 2 Oct 2001, Lionel Gauthier wrote:
> On Monday 01 October 2001 04:59 pm, Calin A. Culianu wrote:
> > Hmm.. just playing around with pointers should not take that long
> > (unless you are like on a 16 MHz 386sx or something).
> >
> > Here's one possible explanation that doesn't really account for the 5ms
> > run-time of each thread, but does account for the observed phenomenon that
> > 1 thread running 1 task will display significantly lower run times than 2
> > threads that share a mutex running the same task:
> >
> > 1) Thread A acquires lock
> > 2) Thread B wants lock, but can't get it so sleeps
> > 3) Thread A does work that takes time T
> > 4) Thread A releases lock
> > 5) Thread B is immediately awoken because it was next-in-line for the
> > mutex
> > 6) Thread B does work that takes roughly time T as well
> > 7) Thread B releases lock
> > 8) goto (1)
> >
> > As you can see, thread B did work that took time T, but ended up taking
> > over 2T's work of time to do it.
> >
> > Now this is a sort of obvious example.. but could it be enough to explain
> > your really long run times? Maybe if you posted some code I might be able
> > to help better? Thanks...
> >
> >
> > -Calin
>
> Thanks a lot for your help, here is the code:
> -----------------------------------------------------
> Hardware : Bi processor PIII 1 GHz 512Mo
> -----------------------------------------------------
> Software :
> � Redhat 7.1
> � Kernel 2.4.4 from kernel.org
> � RT-Linux 3.1
> -----------------------------------------------------
> pthread_attr_t attr1,attr2;
> struct sched_param sched_param1,sched_param2;
> pthread_t pthread_test1;
> pthread_t pthread_test2;
> int counter1 = 0;
> int duration1= 0;
> int cpu1 = 100;
> int counter2 = 0;
> int duration2= 0;
> int cpu2 = 100;
>
> extern struct mem_pool *mem;
> extern volatile char *shm;
>
> //--------------------------------------------------
> void *thread_test1(void* notusedP) {
> //--------------------------------------------------
> hrtime_t start, end, process;
> struct mem_block *mb;
>
> pthread_attr_getcpu_np(&attr1, &cpu1);
> pthread_make_periodic_np(pthread_self(), gethrtime(), 10000000);
>
> while (1) {
>
> pthread_wait_np();
> start = gethrtime();
>
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
>
> end = gethrtime();
> process = end - start;
> if (process > 1000000) {
> counter1+=1;
> duration1 += process;
> }
> }
> }
> //--------------------------------------------------
> void *thread_test2(void* notusedP) {
> //--------------------------------------------------
> hrtime_t start, end,process;
> struct mem_block *mb;
>
> pthread_attr_getcpu_np(&attr2, &cpu2);
> pthread_make_periodic_np(pthread_self(), gethrtime(), 99000000);
>
> while (1) {
> pthread_wait_np();
>
> start = gethrtime();
>
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> mb = get_free_mem_block(200);
> free_mem_block(mb);
> end = gethrtime();
> process = end - start;
> if (process > 1000000) {
> counter2+=1;
> duration2 += process;
> }
> }
> }
> //------------------------------------------------------------------------------
> int init_module(void) {
> //------------------------------------------------------------------------------
> pthread_attr_t attr;
> struct sched_param sched_param;
> long int shm_size;
> int result, i;
> int ret, index;
>
>
> shm_size = sizeof(struct mem_pool);
> printk("shm size = %ld bytes\n", shm_size);
> shm_size = (shm_size & ~((long int)0xFFFF)) + 0x10000;// alloc by
> 64Kbytes
> printk("mbuff_alloc %ld Kbytes\n", shm_size>>10);
>
> shm = (volatile char*) mbuff_alloc("wcdma",shm_size);
>
> if(shm == NULL) {
> printk("mbuff_alloc failed\n");
> return(2);
> }
> printk("mbuff_alloc succeed mem_pool=%p\n", shm);
> mem = (struct mem_pool *)shm;
>
>
> /**********************************/
> /* discovering processor IDs */
> /**********************************/
> nb_processors = 0;
> printk("Found processor IDs ");
> for (index=0;(index<32) && (nb_processors < NB_MAX_PROCESSORS); index++) {
> if (rtl_cpu_exists(index)) {
> processor_id[nb_processors++]=index;
> printk("%d ",index);
> }
> }
> printk("\n");
> /**********************************/
> /* init memory management */
> /**********************************/
> pthread_attr_init (&attr);
> sched_param.sched_priority = 2;
> pthread_attr_setschedparam (&attr, &sched_param);
>
> printk("creation thread init mem\n");
> ret = pthread_create(&pool_buffer_init_thr, &attr, pool_buffer_init,
> (void *)mem);
> pthread_join(pool_buffer_init_thr, NULL);
> printk("joined thread init mem\n");
>
> pthread_attr_init (&attr1);
> if (nb_processors > 1) {
> pthread_attr_setcpu_np(&attr1, processor_id[nb_processors -1]);
> }
> sched_param1.sched_priority = 10;
> pthread_attr_setschedparam (&attr1, &sched_param1);
> ret = pthread_create(&pthread_test1, &attr1, thread_test1,(void *)1);
>
> pthread_attr_init (&attr2);
> if (nb_processors > 1) {
> pthread_attr_setcpu_np(&attr2, processor_id[nb_processors -2]);
> }
> sched_param2.sched_priority = 10;
> pthread_attr_setschedparam (&attr2, &sched_param2);
> ret = pthread_create(&pthread_test2, &attr2, thread_test2, (void*)1);
>
> return 0;
> } else {
> return -ENODEV;
> }
> }
> //------------------------------------------------------------------------------
> void cleanup_module(void) {
> //------------------------------------------------------------------------------
> pthread_delete_np(pthread_test1);
> pthread_delete_np(pthread_test2);
>
> printk("COUNTER 1 = %016X\n", counter1);
> printk("CPU 1 = %d\n", cpu1);
> if (counter1) {
> printk("DURATION AVERAGE 1 = %d\n", duration1/counter1);
> }
> printk("COUNTER 2 = %016X\n", counter2);
> printk("CPU 2 = %d\n", cpu2);
> if (counter2) {
> printk("DURATION AVERAGE 2 = %d\n", duration2/counter2);
> }
>
> if (shm) {
> mbuff_free("wcdma",(void*)shm);
> }
> }
> //-----------------------------------------------------------------------------
> inline void free_mem_block(struct mem_block *leP) {
> //-----------------------------------------------------------------------------
> add_tail(leP, &mem->mem_lists[leP->pool_id]);
> }
> //-----------------------------------------------------------------------------
> inline struct mem_block* get_free_mem_block(u16 sizeP) {
> //-----------------------------------------------------------------------------
> struct mem_block* le;
>
> if (sizeP <= MEM_MNGT_MB0_BLOCK_SIZE) {
> if ((le=remove_head( &mem->mem_lists[MEM_MNGT_POOL_ID0]))) {
> return le;
> }
> }
> if (sizeP <= MEM_MNGT_MB1_BLOCK_SIZE) {
> if ((le=remove_head( &mem->mem_lists[MEM_MNGT_POOL_ID1]))) {
> return le;
> }
> }
> if (sizeP <= MEM_MNGT_MB2_BLOCK_SIZE) {
> if ((le=remove_head( &mem->mem_lists[MEM_MNGT_POOL_ID2]))) {
> return le;
> }
> }
> etc
> return NULL;
> };
> //-----------------------------------------------------------------------------
> inline void add_tail(struct mem_block *elementP,
> struct list* listP) {
> //-----------------------------------------------------------------------------
> struct mem_block* tail;
>
> if (elementP != NULL) {
> #ifdef TARGET_RT_LINUX
> pthread_mutex_lock(&listP->mutex);
> #endif
> elementP->next = NULL;
> tail = listP->tail;
> // almost one element
> if (tail == NULL) {
> listP->head = elementP;
> } else {
> tail->next = elementP;
> }
> listP->tail = elementP;
> #ifdef TARGET_RT_LINUX
> pthread_mutex_unlock(&listP->mutex);
> #endif
> } else {
> rtl_printf("[RLC][ERROR] add_tail() element NULL\n");
> }
> }
> //-----------------------------------------------------------------------------
> inline struct mem_block* remove_head(struct list* listP) {
> //-----------------------------------------------------------------------------
> struct mem_block* head;
>
> #ifdef TARGET_RT_LINUX
> pthread_mutex_lock(&listP->mutex);
> #endif
>
> head = listP->head;
> // almost one element
> if (head != NULL) {
> listP->head = head->next;
> // if only one element, update tail
> if (listP->head == NULL) {
> listP->tail = NULL;
> } else {
> head->next = NULL;
> }
> }
> #ifdef TARGET_RT_LINUX
> pthread_mutex_unlock(&listP->mutex);
> #endif
> return head;
> }
> //-----------------------------------------------------------------------------
> struct mem_block {
> struct mem_block *next;
> struct mem_block *previous;
> u8 pool_id;
> u8 *data;
> };
> struct list {
> struct mem_block *head;
> struct mem_block *tail;
> char name[20];
> #ifdef TARGET_RT_LINUX
> pthread_mutex_t mutex;
> #endif
> };
> struct mem_pool {
> //-----------------------------------------------------------
> // basic memory management
> //-----------------------------------------------------------
> u8 mem_pool0[MEM_MNGT_MB0_NB_BLOCKS][MEM_MNGT_MB0_BLOCK_SIZE];
> u8 mem_pool1[MEM_MNGT_MB1_NB_BLOCKS][MEM_MNGT_MB1_BLOCK_SIZE];
> u8 mem_pool2[MEM_MNGT_MB2_NB_BLOCKS][MEM_MNGT_MB2_BLOCK_SIZE];
> u8 mem_pool3[MEM_MNGT_MB3_NB_BLOCKS][MEM_MNGT_MB3_BLOCK_SIZE];
> u8 mem_pool4[MEM_MNGT_MB4_NB_BLOCKS][MEM_MNGT_MB4_BLOCK_SIZE];
> u8 mem_pool5[MEM_MNGT_MB5_NB_BLOCKS][MEM_MNGT_MB5_BLOCK_SIZE];
> u8 mem_pool6[MEM_MNGT_MB6_NB_BLOCKS][MEM_MNGT_MB6_BLOCK_SIZE];
> struct mem_block mem_blocks[MEM_MNGT_LE_NB_ELEMENTS];
> struct list mem_lists[7];
>
> };
> //-----------------------------------------------------------------------------
> void init_list(struct list* listP, char* nameP) {
> //-----------------------------------------------------------------------------
> #ifdef TARGET_RT_LINUX
> pthread_mutexattr_t attr;
> int error_code;
> #endif
> u8 i=0;
> if (nameP) {while ((listP->name[i] = nameP[i]));}
> listP->tail = NULL;
> listP->head = NULL;
> #ifdef TARGET_RT_LINUX
> // tried several attributes (setpshared, protocol)without success for
> scheduling problem
> pthread_mutexattr_init(&attr);
> pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
> if ((error_code = pthread_mutex_init(&listP->mutex, &attr))) {
> rtl_printf("[MUTEX][ERROR] init_list(%s) %d\n", nameP, error_code);
> }
> #endif
> }
>
>
>
> -- [rtl] ---
> To unsubscribe:
> echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
> echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
> --
> For more information on Real-Time Linux see:
> http://www.rtlinux.org/
>
-- [rtl] ---
To unsubscribe:
echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
--
For more information on Real-Time Linux see:
http://www.rtlinux.org/