DSP

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

2019-07-13 19:13发布

为更好地发挥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(继续将执行)】

以下是测试示例的输出(中间有部分省略) [C66xx_6] main: MultiProc id = 6 main: MultiProc name = CORE6 [C66xx_7] main: MultiProc id = 7 main: MultiProc name = CORE7 [C66xx_0] main: MultiProc id = 0 [C66xx_1] main: MultiProc id = 1 [C66xx_2] main: MultiProc id = 2 [C66xx_3] main: MultiProc id = 3 [C66xx_4] main: MultiProc id = 4 [C66xx_5] main: MultiProc id = 5 [C66xx_0] main: MultiProc name = CORE0 [C66xx_1] main: MultiProc name = CORE1 [C66xx_2] main: MultiProc name = CORE2 [C66xx_3] main: MultiProc name = CORE3 [C66xx_4] main: MultiProc name = CORE4 [C66xx_5] main: MultiProc name = CORE5 [C66xx_0] tsk1_func: Sent request #0 to CORE1 [C66xx_1] tsk1_func: Received request #1 from CORE0 tsk1_func: Sent request #1 to CORE2 [C66xx_2] tsk1_func: Received request #1 from CORE1 tsk1_func: Sent request #1 to CORE3 [C66xx_3] tsk1_func: Received request #1 from CORE2 tsk1_func: Sent request #1 to CORE4 ///省略/// [C66xx_3] tsk1_func: Received request #10 from CORE2 tsk1_func: Sent request #10 to CORE4 Test completed [C66xx_4] tsk1_func: Received request #10 from CORE3 tsk1_func: Sent request #10 to CORE5 Test completed [C66xx_5] tsk1_func: Received request #10 from CORE4 tsk1_func: Sent request #10 to CORE6 Test completed [C66xx_6] tsk1_func: Received request #10 from CORE5 tsk1_func: Sent request #10 to CORE7 Test completed [C66xx_7] tsk1_func: Received request #10 from CORE6 tsk1_func: Sent request #10 to CORE0 Test completed [C66xx_0] tsk1_func: Received request #10 from CORE7 Test completed

类似的可以新建一个MessageQ示例项目 后续步骤同上,测试的输出如下(中间有部分省略) [C66xx_1] Start the main loop [C66xx_5] Start the main loop [C66xx_7] Start the main loop [C66xx_6] Start the main loop [C66xx_0] Start the main loop [C66xx_2] Start the main loop [C66xx_3] Start the main loop [C66xx_4] Start the main loop [C66xx_0] Sending a message #1 to CORE1 [C66xx_1] Sending a message #1 to CORE2 [C66xx_2] Sending a message #1 to CORE3 [C66xx_3] Sending a message #1 to CORE4 [C66xx_4] Sending a message #1 to CORE5 [C66xx_5] Sending a message #1 to CORE6 [C66xx_6] Sending a message #1 to CORE7 [C66xx_7] Sending a message #1 to CORE0 ///省略/// [C66xx_5] Sending a message #9 to CORE6 [C66xx_6] Sending a message #9 to CORE7 [C66xx_7] Sending a message #9 to CORE0 [C66xx_0] Sending a message #10 to CORE1 [C66xx_1] Sending a message #10 to CORE2 The test is complete [C66xx_2] Sending a message #10 to CORE3 The test is complete [C66xx_3] Sending a message #10 to CORE4 The test is complete [C66xx_4] Sending a message #10 to CORE5 The test is complete [C66xx_5] Sending a message #10 to CORE6 The test is complete [C66xx_6] Sending a message #10 to CORE7 The test is complete [C66xx_7] Sending a message #10 to CORE0 The test is complete [C66xx_0] The test is complete
最后附上示例代码(模板生成的,仅删除部分注释,其他未做改动) 示例Notify的主要代码 #include /* XDC.RUNTIME module Headers */ #include /* IPC module Headers */ #include #include #include /* BIOS6 module Headers */ #include #include #include /* To get globals from .cfg Header */ #include #define INTERRUPT_LINE 0 /* Notify event number that the app uses */ #define EVENTID 10 /* Number of times to run the loop */ #define NUMLOOPS 10 UInt32 seq = 0; UInt16 recvProcId; UInt16 srcProc, dstProc; /* * ======== cbFxn ======== * This function was registered with Notify. It is called when any event is * sent to this processor. */ Void cbFxn(UInt16 procId, UInt16 lineId, UInt32 eventId, UArg arg, UInt32 payload) { /* The payload is a sequence number. */ recvProcId = procId; seq = payload; Semaphore_post(semHandle); } /* * ======== tsk0_func ======== * Sends an event to the next processor then pends on a semaphore. * The semaphore is posted by the callback function. */ Void tsk0_func(UArg arg0, UArg arg1) { Int i = 1; Int status; if (MultiProc_self() == 0) { while (i <= NUMLOOPS) { /* Send an event to the next processor */ status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, i, TRUE); /* Continue until remote side is up */ if (status < 0) { continue; } System_printf("tsk1_func: Sent request #%d to %s ", seq, MultiProc_getName(dstProc)); /* Wait to be released by the cbFxn posting the semaphore */ Semaphore_pend(semHandle, BIOS_WAIT_FOREVER); System_printf("tsk1_func: Received request #%d from %s ", seq, MultiProc_getName(recvProcId)); /* increment for next iteration */ i++; } } else { while (seq < NUMLOOPS) { /* wait forever on a semaphore, semaphore is posted in callback */ Semaphore_pend(semHandle, BIOS_WAIT_FOREVER); System_printf("tsk1_func: Received request #%d from %s ", seq, MultiProc_getName(recvProcId)); /* Send an event to the next processor */ status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, seq, TRUE); if (status < 0) { System_abort("sendEvent failed "); } System_printf("tsk1_func: Sent request #%d to %s ", seq, MultiProc_getName(dstProc)); } } System_printf("Test completed "); BIOS_exit(0); } /* * ======== main ======== * Synchronizes all processors (in Ipc_start), calls BIOS_start, and registers * for an incoming event */ Int main(Int argc, Char* argv[]) { Int status; UInt numProcs = MultiProc_getNumProcessors(); /* * Determine which processors Notify will communicate with based on the * local MultiProc id. Also, create a processor-specific Task. */ srcProc = ((MultiProc_self() - 1 + numProcs) % numProcs); dstProc = ((MultiProc_self() + 1) % numProcs); System_printf("main: MultiProc id = %d ", MultiProc_self()); System_printf("main: MultiProc name = %s ", MultiProc_getName(MultiProc_self())); /* * Ipc_start() calls Ipc_attach() to synchronize all remote processors * because 'Ipc.procSync' is set to 'Ipc.ProcSync_ALL' in *.cfg */ status = Ipc_start(); if (status < 0) { System_abort("Ipc_start failed "); } /* * Register call back with Notify. It will be called when the processor * with id = srcProc sends event number EVENTID to this processor. */ status = Notify_registerEvent(srcProc, INTERRUPT_LINE, EVENTID, (Notify_FnNotifyCbck) cbFxn, NULL); if (status < 0) { System_abort("Notify_registerEvent failed "); } BIOS_start(); return (0); }
示例MessageQ的主要代码 #include #include /* XDC.RUNTIME module Headers */ #include #include /* IPC module Headers */ #include #include #include #include /* BIOS6 module Headers */ #include #include /* To get globals from .cfg Header */ #include #define HEAP_NAME "myHeapBuf" #define HEAPID 0 #define NUMLOOPS 10 Char localQueueName[10]; Char nextQueueName[10]; UInt16 nextProcId; /* * ======== tsk0_func ======== * Allocates a message and ping-pongs the message around the processors. * A local message queue is created and a remote message queue is opened. * Messages are sent to the remote message queue and retrieved from the * local MessageQ. */ Void tsk0_func(UArg arg0, UArg arg1) { MessageQ_Msg msg; MessageQ_Handle messageQ; MessageQ_QueueId remoteQueueId; Int status; UInt16 msgId = 0; HeapBufMP_Handle heapHandle; HeapBufMP_Params heapBufParams; if (MultiProc_self() == 0) { /* * Create the heap that will be used to allocate messages. */ HeapBufMP_Params_init(&heapBufParams); heapBufParams.regionId = 0; heapBufParams.name = HEAP_NAME; heapBufParams.numBlocks = 1; heapBufParams.blockSize = sizeof(MessageQ_MsgHeader); heapHandle = HeapBufMP_create(&heapBufParams); if (heapHandle == NULL) { System_abort("HeapBufMP_create failed "); } } else { /* Open the heap created by the other processor. Loop until opened. */ do { status = HeapBufMP_open(HEAP_NAME, &heapHandle); /* * Sleep for 1 clock tick to avoid inundating remote processor * with interrupts if open failed */ if (status < 0) { Task_sleep(1); } } while (status < 0); } /* Register this heap with MessageQ */ MessageQ_registerHeap((IHeap_Handle) heapHandle, HEAPID); /* Create the local message queue */ messageQ = MessageQ_create(localQueueName, NULL); if (messageQ == NULL) { System_abort("MessageQ_create failed "); } /* Open the remote message queue. Spin until it is ready. */ do { status = MessageQ_open(nextQueueName, &remoteQueueId); /* * Sleep for 1 clock tick to avoid inundating remote processor * with interrupts if open failed */ if (status < 0) { Task_sleep(1); } } while (status < 0); if (MultiProc_self() == 0) { /* Allocate a message to be ping-ponged around the processors */ msg = MessageQ_alloc(HEAPID, sizeof(MessageQ_MsgHeader)); if (msg == NULL) { System_abort("MessageQ_alloc failed "); } /* * Send the message to the next processor and wait for a message * from the previous processor. */ System_printf("Start the main loop "); while (msgId < NUMLOOPS) { /* Increment...the remote side will check this */ msgId++; MessageQ_setMsgId(msg, msgId); System_printf("Sending a message #%d to %s ", msgId,nextQueueName); /* send the message to the remote processor */ status = MessageQ_put(remoteQueueId, msg); if (status < 0) { System_abort("MessageQ_put had a failure/error "); } /* Get a message */ status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER); if (status < 0) { System_abort("This should not happen since timeout is forever "); } } } else { /* * Wait for a message from the previous processor and * send it to the next processor */ System_printf("Start the main loop "); while (TRUE) { /* Get a message */ status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER); if (status < 0) { System_abort("This should not happen since timeout is forever "); } System_printf("Sending a message #%d to %s ",MessageQ_getMsgId(msg), nextQueueName); /* Get the message id */ msgId = MessageQ_getMsgId(msg); /* send the message to the remote processor */ status = MessageQ_put(remoteQueueId, msg); if (status < 0) { System_abort("MessageQ_put had a failure/error "); } /* test done */ if (msgId >= NUMLOOPS) { break; } } } System_printf("The test is complete "); BIOS_exit(0); } /* * ======== main ======== * Synchronizes all processors (in Ipc_start) and calls BIOS_start */ Int main(Int argc, Char* argv[]) { Int status; nextProcId = (MultiProc_self() + 1) % MultiProc_getNumProcessors(); /* Generate queue names based on own proc ID and total number of procs */ System_sprintf(localQueueName, "%s", MultiProc_getName(MultiProc_self())); System_sprintf(nextQueueName, "%s", MultiProc_getName(nextProcId)); /* * Ipc_start() calls Ipc_attach() to synchronize all remote processors * because 'Ipc.procSync' is set to 'Ipc.ProcSync_ALL' in *.cfg */ status = Ipc_start(); if (status < 0) { System_abort("Ipc_start failed "); } BIOS_start(); return (0); }

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