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

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

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

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

“通知”(Notify)模型

CCS+C6678LE开发记录11:多核协作(IPC)入门_第1张图片

“消息队列”(MessageQ)模型

CCS+C6678LE开发记录11:多核协作(IPC)入门_第2张图片


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

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

CCS+C6678LE开发记录11:多核协作(IPC)入门_第3张图片

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

CCS+C6678LE开发记录11:多核协作(IPC)入门_第4张图片

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

CCS+C6678LE开发记录11:多核协作(IPC)入门_第5张图片

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

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

CCS+C6678LE开发记录11:多核协作(IPC)入门_第6张图片

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

CCS+C6678LE开发记录11:多核协作(IPC)入门_第7张图片

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

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

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

CCS+C6678LE开发记录11:多核协作(IPC)入门_第8张图片


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

[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\n", 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\n", 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\n", 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\n");
			}

			System_printf("tsk1_func: Sent request #%d to %s\n", seq,
					MultiProc_getName(dstProc));
		}
	}

	System_printf("Test completed\n");
	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\n", MultiProc_self());
	System_printf("main: MultiProc name = %s\n",
			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\n");
	}

	/*
	 *  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\n");
	}

	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\n");
		}
	}
	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\n");
	}

	/* 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\n");
		}

		/*
		 *  Send the message to the next processor and wait for a message
		 *  from the previous processor.
		 */
		System_printf("Start the main loop\n");
		while (msgId < NUMLOOPS)
		{
			/* Increment...the remote side will check this */
			msgId++;
			MessageQ_setMsgId(msg, msgId);

			System_printf("Sending a message #%d to %s\n", 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\n");
			}

			/* Get a message */
			status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);
			if (status < 0)
			{
				System_abort("This should not happen since timeout is forever\n");
			}
		}
	}
	else
	{
		/*
		 *  Wait for a message from the previous processor and
		 *  send it to the next processor
		 */
		System_printf("Start the main loop\n");
		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\n");
			}

			System_printf("Sending a message #%d to %s\n",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\n");
			}

			/* test done */
			if (msgId >= NUMLOOPS)
			{
				break;
			}
		}
	}

	System_printf("The test is complete\n");
	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\n");
	}

	BIOS_start();

	return (0);
}


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

你可能感兴趣的:(DSP(C6678))