首页 > 代码库 > CCS+C6678LE开发记录11:多核协作(IPC)入门

CCS+C6678LE开发记录11:多核协作(IPC)入门

为更好地发挥C6678的多核性能,需要用到多核协作。幸运的是,我们可以使用官方提供的IPC模块。

IPC=Inter-Processor Communication, 核间通信,粗略来说就是多核之间进行信息、数据交换。

作为入门篇,本文不打算深入讨论IPC,仅仅列出自带的两个简单示例:Notify和MessageQ.

"通知"(Notify)模型

技术分享

"消息队列"(MessageQ)模型

技术分享

 

以下介绍Notify示例的创建过程以及测试结果。

首先新建一个项目,取名demo_ipcNotify,项目类型从模板中选择

技术分享

选择"IPC and I/O Examples"分支下的"C6678 Examples"

技术分享

然后【Next】,在XDCtools version选择3.23.4.60(不带"core"后缀的那一个)

技术分享

创建并编译链接无错误之后执行Debug

建议勾选下方的"Create a debug group for selected cores"

技术分享

如果没有选,可以在稍后执行如下操作

技术分享

分组的好处是,当有多个核心加载时,不必一一启动,只需要在组别上点击启动(分组下所有核心全部启动)

这样做虽然不是必要的,但建议这样做。

如果勾选了分组,将会是如下这个样子,测试的时候只需在"Group 1"上点击一次【Step On(继续将执行)】

技术分享

 

以下是测试示例的输出(中间有部分省略)

[plain] view plain copy

 print?

  1. [C66xx_6] main: MultiProc id = 6  
  2. main: MultiProc name = CORE6  
  3. [C66xx_7] main: MultiProc id = 7  
  4. main: MultiProc name = CORE7  
  5. [C66xx_0] main: MultiProc id = 0  
  6. [C66xx_1] main: MultiProc id = 1  
  7. [C66xx_2] main: MultiProc id = 2  
  8. [C66xx_3] main: MultiProc id = 3  
  9. [C66xx_4] main: MultiProc id = 4  
  10. [C66xx_5] main: MultiProc id = 5  
  11. [C66xx_0] main: MultiProc name = CORE0  
  12. [C66xx_1] main: MultiProc name = CORE1  
  13. [C66xx_2] main: MultiProc name = CORE2  
  14. [C66xx_3] main: MultiProc name = CORE3  
  15. [C66xx_4] main: MultiProc name = CORE4  
  16. [C66xx_5] main: MultiProc name = CORE5  
  17. [C66xx_0] tsk1_func: Sent request #0 to CORE1  
  18. [C66xx_1] tsk1_func: Received request #1 from CORE0  
  19. tsk1_func: Sent request #1 to CORE2  
  20. [C66xx_2] tsk1_func: Received request #1 from CORE1  
  21. tsk1_func: Sent request #1 to CORE3  
  22. [C66xx_3] tsk1_func: Received request #1 from CORE2  
  23. tsk1_func: Sent request #1 to CORE4  
  24. ///省略///  
  25. [C66xx_3] tsk1_func: Received request #10 from CORE2  
  26. tsk1_func: Sent request #10 to CORE4  
  27. Test completed  
  28. [C66xx_4] tsk1_func: Received request #10 from CORE3  
  29. tsk1_func: Sent request #10 to CORE5  
  30. Test completed  
  31. [C66xx_5] tsk1_func: Received request #10 from CORE4  
  32. tsk1_func: Sent request #10 to CORE6  
  33. Test completed  
  34. [C66xx_6] tsk1_func: Received request #10 from CORE5  
  35. tsk1_func: Sent request #10 to CORE7  
  36. Test completed  
  37. [C66xx_7] tsk1_func: Received request #10 from CORE6  
  38. tsk1_func: Sent request #10 to CORE0  
  39. Test completed  
  40. [C66xx_0] tsk1_func: Received request #10 from CORE7  
  41. Test completed  

 

类似的可以新建一个MessageQ示例项目

后续步骤同上,测试的输出如下(中间有部分省略)

[plain] view plain copy

 print?

  1. [C66xx_1] Start the main loop  
  2. [C66xx_5] Start the main loop  
  3. [C66xx_7] Start the main loop  
  4. [C66xx_6] Start the main loop  
  5. [C66xx_0] Start the main loop  
  6. [C66xx_2] Start the main loop  
  7. [C66xx_3] Start the main loop  
  8. [C66xx_4] Start the main loop  
  9. [C66xx_0] Sending a message #1 to CORE1  
  10. [C66xx_1] Sending a message #1 to CORE2  
  11. [C66xx_2] Sending a message #1 to CORE3  
  12. [C66xx_3] Sending a message #1 to CORE4  
  13. [C66xx_4] Sending a message #1 to CORE5  
  14. [C66xx_5] Sending a message #1 to CORE6  
  15. [C66xx_6] Sending a message #1 to CORE7  
  16. [C66xx_7] Sending a message #1 to CORE0  
  17. ///省略///  
  18. [C66xx_5] Sending a message #9 to CORE6  
  19. [C66xx_6] Sending a message #9 to CORE7  
  20. [C66xx_7] Sending a message #9 to CORE0  
  21. [C66xx_0] Sending a message #10 to CORE1  
  22. [C66xx_1] Sending a message #10 to CORE2  
  23. The test is complete  
  24. [C66xx_2] Sending a message #10 to CORE3  
  25. The test is complete  
  26. [C66xx_3] Sending a message #10 to CORE4  
  27. The test is complete  
  28. [C66xx_4] Sending a message #10 to CORE5  
  29. The test is complete  
  30. [C66xx_5] Sending a message #10 to CORE6  
  31. The test is complete  
  32. [C66xx_6] Sending a message #10 to CORE7  
  33. The test is complete  
  34. [C66xx_7] Sending a message #10 to CORE0  
  35. The test is complete  
  36. [C66xx_0] The test is complete  


最后附上示例代码(模板生成的,仅删除部分注释,其他未做改动)

示例Notify的主要代码

[cpp] view plain copy

 print?

  1. #include <xdc/std.h>  
  2. /*  XDC.RUNTIME module Headers    */  
  3. #include <xdc/runtime/System.h>  
  4. /*  IPC module Headers           */  
  5. #include <ti/ipc/MultiProc.h>  
  6. #include <ti/ipc/Notify.h>  
  7. #include <ti/ipc/Ipc.h>  
  8. /*  BIOS6 module Headers         */  
  9. #include <ti/sysbios/knl/Semaphore.h>  
  10. #include <ti/sysbios/knl/Task.h>  
  11. #include <ti/sysbios/BIOS.h>  
  12. /*  To get globals from .cfg Header */  
  13. #include <xdc/cfg/global.h>  
  14. #define INTERRUPT_LINE  0  
  15. /* Notify event number that the app uses */  
  16. #define EVENTID         10  
  17. /* Number of times to run the loop */  
  18. #define NUMLOOPS        10   
  19.     
  20. UInt32 seq = 0;  
  21. UInt16 recvProcId;  
  22. UInt16 srcProc, dstProc;  
  23.     
  24. /* 
  25.  *  ======== cbFxn ======== 
  26.  *  This function was registered with Notify. It is called when any event is 
  27.  *  sent to this processor. 
  28.  */  
  29. Void cbFxn(UInt16 procId, UInt16 lineId, UInt32 eventId, UArg arg,  
  30.         UInt32 payload)  
  31. {  
  32.     /* The payload is a sequence number. */  
  33.     recvProcId = procId;  
  34.     seq = payload;  
  35.     Semaphore_post(semHandle);  
  36. }  
  37.     
  38. /* 
  39.  *  ======== tsk0_func ======== 
  40.  *  Sends an event to the next processor then pends on a semaphore. 
  41.  *  The semaphore is posted by the callback function. 
  42.  */  
  43. Void tsk0_func(UArg arg0, UArg arg1)  
  44. {  
  45.     Int i = 1;  
  46.     Int status;  
  47.     
  48.     if (MultiProc_self() == 0)  
  49.     {  
  50.         while (i <= NUMLOOPS)  
  51.         {  
  52.             /* Send an event to the next processor */  
  53.             status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, i,  
  54.             TRUE);  
  55.     
  56.             /* Continue until remote side is up */  
  57.             if (status < 0)  
  58.             {  
  59.                 continue;  
  60.             }  
  61.     
  62.             System_printf("tsk1_func: Sent request #%d to %s\n", seq,  
  63.                     MultiProc_getName(dstProc));  
  64.     
  65.             /* Wait to be released by the cbFxn posting the semaphore */  
  66.             Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);  
  67.     
  68.             System_printf("tsk1_func: Received request #%d from %s\n", seq,  
  69.                     MultiProc_getName(recvProcId));  
  70.     
  71.             /* increment for next iteration */  
  72.             i++;  
  73.         }  
  74.     }  
  75.     else  
  76.     {  
  77.         while (seq < NUMLOOPS)  
  78.         {  
  79.             /* wait forever on a semaphore, semaphore is posted in callback */  
  80.             Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);  
  81.     
  82.             System_printf("tsk1_func: Received request #%d from %s\n", seq,  
  83.                     MultiProc_getName(recvProcId));  
  84.     
  85.             /* Send an event to the next processor */  
  86.             status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, seq,  
  87.             TRUE);  
  88.             if (status < 0)  
  89.             {  
  90.                 System_abort("sendEvent failed\n");  
  91.             }  
  92.     
  93.             System_printf("tsk1_func: Sent request #%d to %s\n", seq,  
  94.                     MultiProc_getName(dstProc));  
  95.         }  
  96.     }  
  97.     
  98.     System_printf("Test completed\n");  
  99.     BIOS_exit(0);  
  100. }  
  101.     
  102. /* 
  103.  *  ======== main ======== 
  104.  *  Synchronizes all processors (in Ipc_start), calls BIOS_start, and registers  
  105.  *  for an incoming event 
  106.  */  
  107. Int main(Int argc, Char* argv[])  
  108. {  
  109.     Int status;  
  110.     UInt numProcs = MultiProc_getNumProcessors();  
  111.     
  112.     /* 
  113.      *  Determine which processors Notify will communicate with based on the 
  114.      *  local MultiProc id.  Also, create a processor-specific Task. 
  115.      */  
  116.     srcProc = ((MultiProc_self() - 1 + numProcs) % numProcs);  
  117.     dstProc = ((MultiProc_self() + 1) % numProcs);  
  118.     
  119.     System_printf("main: MultiProc id = %d\n", MultiProc_self());  
  120.     System_printf("main: MultiProc name = %s\n",  
  121.             MultiProc_getName(MultiProc_self()));  
  122.     
  123.     /* 
  124.      *  Ipc_start() calls Ipc_attach() to synchronize all remote processors 
  125.      *  because ‘Ipc.procSync‘ is set to ‘Ipc.ProcSync_ALL‘ in *.cfg 
  126.      */  
  127.     status = Ipc_start();  
  128.     if (status < 0)  
  129.     {  
  130.         System_abort("Ipc_start failed\n");  
  131.     }  
  132.     
  133.     /* 
  134.      *  Register call back with Notify. It will be called when the processor 
  135.      *  with id = srcProc sends event number EVENTID to this processor. 
  136.      */  
  137.     status = Notify_registerEvent(srcProc, INTERRUPT_LINE, EVENTID,  
  138.             (Notify_FnNotifyCbck) cbFxn, NULL);  
  139.     if (status < 0)  
  140.     {  
  141.         System_abort("Notify_registerEvent failed\n");  
  142.     }  
  143.     
  144.     BIOS_start();  
  145.     
  146.     return (0);  
  147. }  

 

示例MessageQ的主要代码

[cpp] view plain copy

 print?

  1. #include <xdc/std.h>  
  2. #include <string.h>  
  3. /*  XDC.RUNTIME module Headers    */  
  4. #include <xdc/runtime/System.h>  
  5. #include <xdc/runtime/IHeap.h>  
  6. /*  IPC module Headers           */  
  7. #include <ti/ipc/Ipc.h>  
  8. #include <ti/ipc/MessageQ.h>  
  9. #include <ti/ipc/HeapBufMP.h>  
  10. #include <ti/ipc/MultiProc.h>  
  11. /*  BIOS6 module Headers         */  
  12. #include <ti/sysbios/BIOS.h>  
  13. #include <ti/sysbios/knl/Task.h>  
  14. /*  To get globals from .cfg Header */  
  15. #include <xdc/cfg/global.h>  
  16.     
  17. #define HEAP_NAME   "myHeapBuf"  
  18. #define HEAPID      0  
  19. #define NUMLOOPS    10  
  20. Char localQueueName[10];  
  21. Char nextQueueName[10];  
  22. UInt16 nextProcId;  
  23.     
  24. /* 
  25.  *  ======== tsk0_func ======== 
  26.  *  Allocates a message and ping-pongs the message around the processors. 
  27.  *  A local message queue is created and a remote message queue is opened. 
  28.  *  Messages are sent to the remote message queue and retrieved from the 
  29.  *  local MessageQ. 
  30.  */  
  31. Void tsk0_func(UArg arg0, UArg arg1)  
  32. {  
  33.     MessageQ_Msg msg;  
  34.     MessageQ_Handle messageQ;  
  35.     MessageQ_QueueId remoteQueueId;  
  36.     Int status;  
  37.     UInt16 msgId = 0;  
  38.     HeapBufMP_Handle heapHandle;  
  39.     HeapBufMP_Params heapBufParams;  
  40.     
  41.     if (MultiProc_self() == 0)  
  42.     {  
  43.         /* 
  44.          *  Create the heap that will be used to allocate messages. 
  45.          */  
  46.         HeapBufMP_Params_init(&heapBufParams);  
  47.         heapBufParams.regionId = 0;  
  48.         heapBufParams.name = HEAP_NAME;  
  49.         heapBufParams.numBlocks = 1;  
  50.         heapBufParams.blockSize = sizeof(MessageQ_MsgHeader);  
  51.         heapHandle = HeapBufMP_create(&heapBufParams);  
  52.         if (heapHandle == NULL)  
  53.         {  
  54.             System_abort("HeapBufMP_create failed\n");  
  55.         }  
  56.     }  
  57.     else  
  58.     {  
  59.         /* Open the heap created by the other processor. Loop until opened. */  
  60.         do  
  61.         {  
  62.             status = HeapBufMP_open(HEAP_NAME, &heapHandle);  
  63.             /* 
  64.              *  Sleep for 1 clock tick to avoid inundating remote processor 
  65.              *  with interrupts if open failed 
  66.              */  
  67.             if (status < 0)  
  68.             {  
  69.                 Task_sleep(1);  
  70.             }  
  71.         } while (status < 0);  
  72.     }  
  73.     
  74.     /* Register this heap with MessageQ */  
  75.     MessageQ_registerHeap((IHeap_Handle) heapHandle, HEAPID);  
  76.     
  77.     /* Create the local message queue */  
  78.     messageQ = MessageQ_create(localQueueName, NULL);  
  79.     if (messageQ == NULL)  
  80.     {  
  81.         System_abort("MessageQ_create failed\n");  
  82.     }  
  83.     
  84.     /* Open the remote message queue. Spin until it is ready. */  
  85.     do  
  86.     {  
  87.         status = MessageQ_open(nextQueueName, &remoteQueueId);  
  88.         /* 
  89.          *  Sleep for 1 clock tick to avoid inundating remote processor 
  90.          *  with interrupts if open failed 
  91.          */  
  92.         if (status < 0)  
  93.         {  
  94.             Task_sleep(1);  
  95.         }  
  96.     } while (status < 0);  
  97.     
  98.     if (MultiProc_self() == 0)  
  99.     {  
  100.         /* Allocate a message to be ping-ponged around the processors */  
  101.         msg = MessageQ_alloc(HEAPID, sizeof(MessageQ_MsgHeader));  
  102.         if (msg == NULL)  
  103.         {  
  104.             System_abort("MessageQ_alloc failed\n");  
  105.         }  
  106.     
  107.         /* 
  108.          *  Send the message to the next processor and wait for a message 
  109.          *  from the previous processor. 
  110.          */  
  111.         System_printf("Start the main loop\n");  
  112.         while (msgId < NUMLOOPS)  
  113.         {  
  114.             /* Increment...the remote side will check this */  
  115.             msgId++;  
  116.             MessageQ_setMsgId(msg, msgId);  
  117.     
  118.             System_printf("Sending a message #%d to %s\n", msgId,nextQueueName);  
  119.     
  120.             /* send the message to the remote processor */  
  121.             status = MessageQ_put(remoteQueueId, msg);  
  122.             if (status < 0)  
  123.             {  
  124.                 System_abort("MessageQ_put had a failure/error\n");  
  125.             }  
  126.     
  127.             /* Get a message */  
  128.             status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);  
  129.             if (status < 0)  
  130.             {  
  131.                 System_abort("This should not happen since timeout is forever\n");  
  132.             }  
  133.         }  
  134.     }  
  135.     else  
  136.     {  
  137.         /* 
  138.          *  Wait for a message from the previous processor and 
  139.          *  send it to the next processor 
  140.          */  
  141.         System_printf("Start the main loop\n");  
  142.         while (TRUE)  
  143.         {  
  144.             /* Get a message */  
  145.             status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);  
  146.             if (status < 0)  
  147.             {  
  148.                 System_abort("This should not happen since timeout is forever\n");  
  149.             }  
  150.     
  151.             System_printf("Sending a message #%d to %s\n",MessageQ_getMsgId(msg),   
  152.                 nextQueueName);  
  153.     
  154.             /* Get the message id */  
  155.             msgId = MessageQ_getMsgId(msg);  
  156.     
  157.             /* send the message to the remote processor */  
  158.             status = MessageQ_put(remoteQueueId, msg);  
  159.             if (status < 0)  
  160.             {  
  161.                 System_abort("MessageQ_put had a failure/error\n");  
  162.             }  
  163.     
  164.             /* test done */  
  165.             if (msgId >= NUMLOOPS)  
  166.             {  
  167.                 break;  
  168.             }  
  169.         }  
  170.     }  
  171.     
  172.     System_printf("The test is complete\n");  
  173.     BIOS_exit(0);  
  174. }  
  175.     
  176. /* 
  177.  *  ======== main ======== 
  178.  *  Synchronizes all processors (in Ipc_start) and calls BIOS_start 
  179.  */  
  180. Int main(Int argc, Char* argv[])  
  181. {  
  182.     Int status;  
  183.     
  184.     nextProcId = (MultiProc_self() + 1) % MultiProc_getNumProcessors();  
  185.     
  186.     /* Generate queue names based on own proc ID and total number of procs */  
  187.     System_sprintf(localQueueName, "%s", MultiProc_getName(MultiProc_self()));  
  188.     System_sprintf(nextQueueName, "%s", MultiProc_getName(nextProcId));  
  189.     
  190.     /* 
  191.      *  Ipc_start() calls Ipc_attach() to synchronize all remote processors 
  192.      *  because ‘Ipc.procSync‘ is set to ‘Ipc.ProcSync_ALL‘ in *.cfg 
  193.      */  
  194.     status = Ipc_start();  
  195.     if (status < 0)  
  196.     {  
  197.         System_abort("Ipc_start failed\n");  
  198.     }  
  199.     
  200.     BIOS_start();  
  201.     
  202.     return (0);  
  203. }  



本文原创,博文地址
http://blog.csdn.net/fengyhack/article/details/44034941

CCS+C6678LE开发记录11:多核协作(IPC)入门