IC5Notice: We have upgraded developerWorks Community to the latest version of IBM Connections. For more information, read our upgrade FAQ.
Topic
  • 3 replies
  • Latest Post - ‏2012-05-25T18:55:39Z by rakuraku
rakuraku
rakuraku
4 Posts

Pinned topic More than one DMA transfer to SPU program - SPU is not receiving

‏2012-05-24T21:36:46Z |
Hello, i'm using one of examples from IBM - simple_DMA example.

Code is pretty simple:


/* we allocate one control block, to correspond to one SPE */ control_block cb __attribute__ ((aligned (128)));   
/* this is the pointer to the SPE code, to be used at thread creation time */ extern spe_program_handle_t hello_spu;   
/* this is the handle which will be returned by "spe_context_create."  */ spe_context_ptr_t speid;   
/* this variable is the SPU entry point address which is initially set to the default */ unsigned 

int entry = SPE_DEFAULT_ENTRY;   
/* this variable is used to return data regarding an abnormal return from the SPE */ spe_stop_info_t stop_info;   
/* here is the variable to hold the address returned by the malloc() call. */ 

float *data;       
// NOW THE TRANSFER, WHICH WORKS!!!!!   rc = posix_memalign ((void*)(&data), 128, DATA_BUFFER_SIZE); 

if (rc != 0) 
{ fprintf (stderr, 
"Failed allocating space for data array\n"); exit (1); 
}   
/* Fill the data array */   

for (i=0; i<DATA_BUFFER_ENTRIES; i++) 
{ data[i] = 0.5; printf(
"table PPE: %f\n", data[i]); 
}   

if (spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1) < 1) 
{ fprintf(stderr, 
"System doesn't have a working SPE.  I'm leaving.\n"); 

return -1; 
}   printf(
"Address being sent in control block: %p\n", data);   
/* load the address into the control block */ cb.addr = (unsigned 

long 

long)((uintptr_t)data); 
/* create the SPE context */ 

if ((speid = spe_context_create(0, NULL)) == NULL) 
{ fprintf (stderr, 
"FAILED: spe_context_create(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
} 
/* load the SPE program into the SPE context */ 

if (spe_program_load(speid, &hello_spu) != 0) 
{ fprintf (stderr, 
"FAILED: spe_program_load(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* run the SPE context */ 

if (spe_context_run(speid, &entry, 0, &cb, NULL, &stop_info) < 0) 
{ fprintf (stderr, 
"FAILED: spe_context_run(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
} 
/* destroy the SPE context */ 

if (spe_context_destroy(speid) != 0) 
{ fprintf (stderr, 
"FAILED: spe_context_destroy(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* check the SPE status */ 

if (stop_info.stop_reason == SPE_EXIT) 
{ 

if (stop_info.result.spe_exit_code != 0) 
{ fprintf(stderr, 
"FAILED: SPE returned a non-zero exit status\n"); exit(1); 
} 
} 

else 
{ fprintf(stderr, 
"FAILED: SPE abnormally terminated\n"); exit(1); 
}       
//AFTER THAT I;M FREEING THE MEMORY FROM DATA HERE:   free(data);       
//TRANSFER 2 - WHICH DOESN'T WORK BUT IT'S THE SAME PIECE OF CODE   

for (i=0; i<DATA_BUFFER_ENTRIES; i++) 
{ data[i] = 0.5; printf(
"table PPE: %f\n", data[i]); 
}     rc = posix_memalign ((void*)(&data), 128, DATA_BUFFER_SIZE); 

if (rc != 0) 
{ fprintf (stderr, 
"Failed allocating space for data array\n"); exit (1); 
}     

if (spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1) < 1) 
{ fprintf(stderr, 
"System doesn't have a working SPE.  I'm leaving.\n"); 

return -1; 
}   printf(
"Address being sent in control block: %p\n", data);   
/* load the address into the control block */ cb.addr = (unsigned 

long 

long)((uintptr_t)data); 
/* create the SPE context */ 

if ((speid = spe_context_create(0, NULL)) == NULL) 
{ fprintf (stderr, 
"FAILED: spe_context_create(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
} 
/* load the SPE program into the SPE context */ 

if (spe_program_load(speid, &hello_spu) != 0) 
{ fprintf (stderr, 
"FAILED: spe_program_load(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* run the SPE context */ 

if (spe_context_run(speid, &entry, 0, &cb, NULL, &stop_info) < 0) 
{ fprintf (stderr, 
"FAILED: spe_context_run(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}     
/* destroy the SPE context */ 

if (spe_context_destroy(speid) != 0) 
{ fprintf (stderr, 
"FAILED: spe_context_destroy(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* check the SPE status */ 

if (stop_info.stop_reason == SPE_EXIT) 
{ 

if (stop_info.result.spe_exit_code != 0) 
{ fprintf(stderr, 
"FAILED: SPE returned a non-zero exit status\n"); exit(1); 
} 
} 

else 
{ fprintf(stderr, 
"FAILED: SPE abnormally terminated\n"); exit(1); 
}


SPE code is just mfc_get, displaying the table and giving it back by mfc_put and my problem is, that first transfer works well, and then it's just shows that second transfer has been sent in memory block and program can't move on.

What am i doing wrong? Thanks!
Updated on 2012-05-25T18:55:39Z at 2012-05-25T18:55:39Z by rakuraku
  • jk-
    jk-
    43 Posts

    Re: More than one DMA transfer to SPU program - SPU is not receiving

    ‏2012-05-25T02:38:35Z  
    Does the program fail to run completely the second time? Or do you still see the output from the SPE program from the second invocation, but the data is wrong?

    If it's the former, then your problem is probably due to re-using the old value of the SPE entry point (the `entry` var in your code). This will cause the SPE program to be started from the instruction that the previous invocation ended at. This is probably not what you want.

    Try resetting the entry var to SPE_DEFAULT_ENTRY before calling the second spe_context_run().
  • rakuraku
    rakuraku
    4 Posts

    Re: More than one DMA transfer to SPU program - SPU is not receiving

    ‏2012-05-25T08:35:05Z  
    • jk-
    • ‏2012-05-25T02:38:35Z
    Does the program fail to run completely the second time? Or do you still see the output from the SPE program from the second invocation, but the data is wrong?

    If it's the former, then your problem is probably due to re-using the old value of the SPE entry point (the `entry` var in your code). This will cause the SPE program to be started from the instruction that the previous invocation ended at. This is probably not what you want.

    Try resetting the entry var to SPE_DEFAULT_ENTRY before calling the second spe_context_run().
    Thank you for your attention!

    My output is OK for the first transfer, but for the second transfer I see only that the data was sent, and program can't move on then.

    The entry issue is possible, I'll try to do it today, and post the results here - thanks!
  • rakuraku
    rakuraku
    4 Posts

    Re: More than one DMA transfer to SPU program - SPU is not receiving

    ‏2012-05-25T18:55:39Z  
    • jk-
    • ‏2012-05-25T02:38:35Z
    Does the program fail to run completely the second time? Or do you still see the output from the SPE program from the second invocation, but the data is wrong?

    If it's the former, then your problem is probably due to re-using the old value of the SPE entry point (the `entry` var in your code). This will cause the SPE program to be started from the instruction that the previous invocation ended at. This is probably not what you want.

    Try resetting the entry var to SPE_DEFAULT_ENTRY before calling the second spe_context_run().
    Hey! That's amazing! it worked just when I added the
    
    entry = SPE_DEFAULT_ENTRY;
    
    : )

    Can you tell me how can i synchronize these transfers? I've tried to do that via mailboxes but it doesn't work for me. Now I can only do the same operation with the data sent to my program, how can I make it a way, that my SPU will make another operations to another blocks of data?

    I.e it will changing the values of the first block to 5, it will will chaning the second block to 12 etc.

    Because now it's only can change values of every block to 5 : )

    That's my SPE code:

    
    
    /* Here's the local copy of the control block, to be filled by the DMA */ 
    
    volatile control_block cb __attribute__ ((aligned (128)));   
    /* Here's the local copy of the data array, to be filled by the DMA */ 
    
    float data[DATA_BUFFER_ENTRIES] __attribute__ ((aligned (128)));     
    
    int main(unsigned 
    
    long 
    
    long speid __attribute__ ((unused)), unsigned 
    
    long 
    
    long argp, unsigned 
    
    long 
    
    long envp __attribute__ ((unused))) 
    { 
    
    int i; unsigned 
    
    int tag_id;   
    /* Reserve a tag for application usage */ 
    
    if ((tag_id = mfc_tag_reserve()) == MFC_TAG_INVALID) 
    { printf(
    "ERROR: unable to reserve a tag\n"); 
    
    return 1; 
    }   
    /* Here is the actual DMA call */ 
    /* the first parameter is the address in local store to place the data */ 
    /* the second parameter holds the main memory address                  */ 
    /* the third parameter holds the number of bytes to DMA                */ 
    /* the fourth parameter identifies a "tag" to associate with this DMA */ 
    /* (this should be a number between 0 and 31, inclusive)               */ 
    /* the last two parameters are only useful if you've implemented your  */ 
    /* own cache replacement management policy.  Otherwise set them to 0.  */   mfc_get(&cb, argp, sizeof(cb), tag_id, 0, 0);   
    /* Now, we set the "tag bit" into the correct channel on the hardware  */ 
    /* this is always 1 left-shifted by the tag specified with the DMA     */ 
    /* for whose completion you wish to wait.                              */ mfc_write_tag_mask(1<<tag_id);   
    /* Now, issue the read and wait to guarantee DMA completion before we  */ 
    /* continue. */ mfc_read_tag_status_all();   
    /* DMA the data from system memory to our local store buffer. */ mfc_get(data, cb.addr, DATA_BUFFER_SIZE, tag_id, 0, 0);     printf(
    "Address received through control block = 0x%llx\n", cb.addr);     
    /* Wait for the data array DMA to complete. */ mfc_read_tag_status_all();   
    // CHANGING DATA TABLE CONTENT TO 5!!!   
    
    for (i=2; i<DATA_BUFFER_ENTRIES; i++) 
    {   data[i] = 5.; 
    } 
    //giving it back to the ppu   mfc_put(data, cb.addr, DATA_BUFFER_SIZE, tag_id, 0, 0); printf(
    " \n"); 
    
    return 0; 
    }