From 7d7298e8676bacf2f99a2c9cf4a963b21c985ae6 Mon Sep 17 00:00:00 2001 From: NicJA Date: Tue, 21 Feb 2017 15:59:00 +0000 Subject: [PATCH] wip smp test code. does no "real" work currently, but pretends to issue work to workers on each core, waits for them to finish and cleans up. git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@53820 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- test/exec/smp/main.c | 185 ++++++++++++++++++++++++++++++++++++++++++++ test/exec/smp/master.c | 66 ++++++++++++++++ test/exec/smp/mmakefile.src | 17 ++++ test/exec/smp/work.h | 34 ++++++++ test/exec/smp/worker.c | 80 +++++++++++++++++++ 5 files changed, 382 insertions(+) create mode 100644 test/exec/smp/main.c create mode 100644 test/exec/smp/master.c create mode 100644 test/exec/smp/mmakefile.src create mode 100644 test/exec/smp/work.h create mode 100644 test/exec/smp/worker.c diff --git a/test/exec/smp/main.c b/test/exec/smp/main.c new file mode 100644 index 0000000000..2940c8ba2b --- /dev/null +++ b/test/exec/smp/main.c @@ -0,0 +1,185 @@ +/* + Copyright 2017, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "work.h" + +CONST_STRPTR version = "$VER: SMP-Test 1.0 (20.02.2017) ©2017 The AROS Development Team"; + +APTR KernelBase; + +int main() +{ + struct SMPMaster workMaster; + + APTR ProcessorBase; + IPTR coreCount = 1, core; + struct TagItem tags [] = + { + { GCIT_NumberOfProcessors, (IPTR)&coreCount }, + { 0, (IPTR)NULL } + }; + ULONG signals; + + ProcessorBase = OpenResource(PROCESSORNAME); + if (!ProcessorBase) + return 0; + + KernelBase = OpenResource("kernel.resource"); + if (!KernelBase) + return 0; + + GetCPUInfo(tags); + + if (coreCount > 1) + { + struct MemList *coreML; + struct SMPWorker *coreWorker; + struct SMPWorkMessage *workMsg; + IPTR workerNameArg[1]; + + /* Create a port that workers/masters will signal us using .. */ + if ((workMaster.smpm_MasterPort = CreateMsgPort()) == NULL) + return 0; + + NEWLIST(&workMaster.smpm_Workers); + + D(bug("[SMP-Test] %s: work Master MsgPort @ 0x%p\n", __func__, workMaster.smpm_MasterPort);) + D(bug("[SMP-Test] %s: SigTask = 0x%p\n", __func__, workMaster.smpm_MasterPort->mp_SigTask);) + + for (core = 0; core < coreCount; core++) + { + ULONG coreAffinity = KrnGetCPUMask(core); + D(bug("[SMP-Test] %s: CPU #%03u affinity = %08X\n", __func__, core, coreAffinity);) + + if ((coreML = AllocMem(sizeof(struct MemList) + sizeof(struct MemEntry), MEMF_PUBLIC|MEMF_CLEAR)) != NULL) + { + coreML->ml_ME[0].me_Length = sizeof(struct SMPWorker); + if ((coreML->ml_ME[0].me_Addr = AllocMem(sizeof(struct SMPWorker), MEMF_PUBLIC|MEMF_CLEAR)) != NULL) + { + coreWorker = coreML->ml_ME[0].me_Addr; + D(bug("[SMP-Test] %s: CPU Worker Node allocated @ 0x%p\n", __func__, coreWorker);) + + coreML->ml_ME[1].me_Length = 22; + if ((coreML->ml_ME[1].me_Addr = AllocMem(22, MEMF_PUBLIC|MEMF_CLEAR)) != NULL) + { + coreML->ml_NumEntries = 2; + + workerNameArg[0] = core; + RawDoFmt("SMP-Test Worker.#%03u", (RAWARG)workerNameArg, RAWFMTFUNC_STRING, coreML->ml_ME[1].me_Addr); + D(bug("[SMP-Test] %s: Worker Task Name '%s'\n", __func__, coreML->ml_ME[1].me_Addr);) + + coreWorker->smpw_MasterPort = workMaster.smpm_MasterPort; + coreWorker->smpw_Node.ln_Type = 0; + coreWorker->smpw_Task = NewCreateTask(TASKTAG_NAME , coreML->ml_ME[1].me_Addr, + TASKTAG_AFFINITY , coreAffinity, + TASKTAG_PRI , 0, + TASKTAG_PC , SMPTestWorker, + TASKTAG_ARG1 , SysBase, + TASKTAG_USERDATA , coreWorker, + TAG_DONE); + + if (coreWorker->smpw_Task) + { + AddTail(&workMaster.smpm_Workers, &coreWorker->smpw_Node); + AddHead(&coreWorker->smpw_Task->tc_MemEntry, &coreML->ml_Node); + } + } + else + { + FreeMem(coreML->ml_ME[0].me_Addr, sizeof(struct SMPWorker)); + FreeMem(coreML, sizeof(struct MemList) + sizeof(struct MemEntry)); + } + } + else + { + FreeMem(coreML, sizeof(struct MemList) + sizeof(struct MemEntry)); + } + } + } + + D(bug("[SMP-Test] %s: Sending out work to do ...\n", __func__);) + + /* + * We now have our workers all launched, + * and a node for each on our list. + * lets get them to do some work ... + */ + workMaster.smpm_Master = NewCreateTask(TASKTAG_NAME , "SMP-Test Master", + TASKTAG_PRI , 0, + TASKTAG_PC , SMPTestMaster, + TASKTAG_ARG1 , SysBase, + TASKTAG_USERDATA , &workMaster, + TAG_DONE); + + D(bug("[SMP-Test] %s: Waiting for the work to be done ...\n", __func__);) + + /* Wait for the workers to finish processing the data ... */ + while ((signals = Wait(SIGBREAKF_CTRL_D)) != 0) + { + if (signals & SIGBREAKF_CTRL_D) + { + BOOL complete = TRUE; + + /* Is work still being issued? */ + if (workMaster.smpm_Master) + complete = FALSE; + + /* Are workers still working ? */ + ForeachNode(&workMaster.smpm_Workers, coreWorker) + { + if (!IsListEmpty(&coreWorker->smpw_MsgPort->mp_MsgList)) + complete = FALSE; + } + + if (complete) + break; + } + + /* update the output... */ + } + + D(bug("[SMP-Test] %s: Letting workers know we are finished ...\n", __func__);) + + ForeachNode(&workMaster.smpm_Workers, coreWorker) + { + /* Tell the workers they are finished ... */ + if ((workMsg = (struct SMPWorkMessage *)AllocMem(sizeof(struct SMPWorkMessage), MEMF_CLEAR)) != NULL) + { + workMsg->smpwm_Type = SPMWORKTYPE_FINISHED; + PutMsg(coreWorker->smpw_MsgPort, (struct Message *)workMsg); + } + } + } + + D(bug("[SMP-Test] %s: Waiting for workers to finish ...\n", __func__);) + + /* wait for the workers to finish up before we exit ... */ + if (workMaster.smpm_MasterPort) + { + while ((signals = Wait(SIGBREAKF_CTRL_C)) != 0) + { + if ((signals & SIGBREAKF_CTRL_C) && IsListEmpty(&workMaster.smpm_Workers)) + break; + } + DeleteMsgPort(workMaster.smpm_MasterPort); + } + + D(bug("[SMP-Test] %s: Done ...\n", __func__);) + + return 0; +} diff --git a/test/exec/smp/master.c b/test/exec/smp/master.c new file mode 100644 index 0000000000..0fce93055d --- /dev/null +++ b/test/exec/smp/master.c @@ -0,0 +1,66 @@ +/* + Copyright © 2017, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 +#include + +#include +#include + +#include +#include + +#include "work.h" + +/* + * This Task sends work out to the "Workers" to process + */ +void SMPTestMaster(struct ExecBase *SysBase) +{ + struct Task *thisTask = FindTask(NULL); + D( + int cpunum = KrnGetCPUNumber(); + + bug("[SMP-Test:Master.%03d] %s task started\n", cpunum, thisTask->tc_Node.ln_Name); + ) + struct SMPMaster *workMaster = thisTask->tc_UserData; + struct SMPWorkMessage *workMsg; + struct SMPWorker *coreWorker; + + if (workMaster) + { + IPTR msgNo; + + D(bug("[SMP-Test:Master.%03d] worker list @ 0x%p\n", cpunum, &workMaster->smpm_Workers);) + + for (msgNo = 0; msgNo < 1000; msgNo++) + { + if ((workMsg = (struct SMPWorkMessage *)AllocMem(sizeof(struct SMPWorkMessage), MEMF_CLEAR)) != NULL) + { + /* prepare the work to be done ... */ + workMsg->smpwm_Type = SPMWORKTYPE_PROCESS; + + /* send out the work to an available worker... */ + do { + ForeachNode(&workMaster->smpm_Workers, coreWorker) + { + if ((workMsg) && (coreWorker->smpw_Node.ln_Type == 1) && (coreWorker->smpw_MsgPort)) + { + D(bug("[SMP-Test] %s: Sending work @ 0x%p to worker @ 0x%p\n", __func__, workMsg, coreWorker);) + coreWorker->smpw_Node.ln_Type = 0; + PutMsg(coreWorker->smpw_MsgPort, (struct Message *)workMsg); + workMsg = NULL; + } + } + } while (workMsg); + } + } + } + + workMaster->smpm_Master = NULL; + Signal(workMaster->smpm_MasterPort->mp_SigTask, SIGBREAKF_CTRL_D); + + D(bug("[SMP-Test:Master.%03d] work complete\n", cpunum);) +} diff --git a/test/exec/smp/mmakefile.src b/test/exec/smp/mmakefile.src new file mode 100644 index 0000000000..ad1f801fd3 --- /dev/null +++ b/test/exec/smp/mmakefile.src @@ -0,0 +1,17 @@ +# $Id: mmakefile.src 53238 2017-01-19 01:46:57Z NicJA $ +# + +include $(SRCDIR)/config/aros.cfg + +FILES := main master worker +EXEDIR := $(AROS_TESTS)/exec + +#MM- test : test-exec-smp + +USER_CFLAGS := + +%build_prog mmake=test-exec-smp \ + files=$(FILES) targetdir=$(EXEDIR) \ + progname=SMP-Test + +%common diff --git a/test/exec/smp/work.h b/test/exec/smp/work.h new file mode 100644 index 0000000000..1fc72e8a86 --- /dev/null +++ b/test/exec/smp/work.h @@ -0,0 +1,34 @@ +/* + Copyright © 2017, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#include +#include + +struct SMPMaster +{ + struct List smpm_Workers; + struct Task *smpm_Master; + struct MsgPort *smpm_MasterPort; +}; + +struct SMPWorker +{ + struct Node smpw_Node; + struct Task *smpw_Task; + struct MsgPort *smpw_MasterPort; + struct MsgPort *smpw_MsgPort; +}; + +struct SMPWorkMessage +{ + struct Message smpwm_Msg; + IPTR smpwm_Type; +}; + +#define SPMWORKTYPE_FINISHED (1 << 0) +#define SPMWORKTYPE_PROCESS (1 << 1) + +void SMPTestMaster(struct ExecBase *); +void SMPTestWorker(struct ExecBase *); diff --git a/test/exec/smp/worker.c b/test/exec/smp/worker.c new file mode 100644 index 0000000000..e38f68b68a --- /dev/null +++ b/test/exec/smp/worker.c @@ -0,0 +1,80 @@ +/* + Copyright © 2017, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 +#include + +#include +#include + +#include +#include + +#include "work.h" + +/* + * This Task processes work received + */ +void SMPTestWorker(struct ExecBase *SysBase) +{ + struct Task *thisTask = FindTask(NULL); + D( + int cpunum = KrnGetCPUNumber(); + + bug("[SMP-Test:Worker.%03d] %s task started\n", cpunum, thisTask->tc_Node.ln_Name); + ) + struct SMPWorker *worker = thisTask->tc_UserData; + struct SMPWorkMessage *workMsg; + BOOL doWork = TRUE; + + D(bug("[SMP-Test:Worker.%03d] worker data @ 0x%p\n", cpunum, worker);) + + if ((worker) && (worker->smpw_MasterPort)) + { + D(bug("[SMP-Test:Worker.%03d] work Master MsgPort @ 0x%p\n", cpunum, worker->smpw_MasterPort);) + worker->smpw_MsgPort = CreateMsgPort(); + D(bug("[SMP-Test:Worker.%03d] work MsgPort @ 0x%p\n", cpunum, worker->smpw_MsgPort);) + + while (doWork) + { + IPTR workType; + + /* we are ready for work .. */ + worker->smpw_Node.ln_Type = 1; + WaitPort(worker->smpw_MsgPort); + + while((workMsg = (struct SMPWorkMessage *) GetMsg(worker->smpw_MsgPort))) + { + D(bug("[SMP-Test:Worker.%03d] work received (Msg @ 0x%p)\n", cpunum, workMsg);) + + /* cache the requested work and free the message ... */ + workType = workMsg->smpwm_Type; + FreeMem(workMsg, sizeof(struct SMPWorkMessage)); + + /* now process it .. */ + if (workType == SPMWORKTYPE_FINISHED) + { + D(bug("[SMP-Test:Worker.%03d] Finished! exiting ...\n", cpunum);) + + doWork = FALSE; + break; + } + else if (workType == SPMWORKTYPE_PROCESS) + { + /* + * Lets do some work! + */ + D(bug("[SMP-Test:Worker.%03d] Processing requested work!\n", cpunum);) + + /* let our "parent" know we are done .. */ + Signal(worker->smpw_MasterPort->mp_SigTask, SIGBREAKF_CTRL_D); + } + } + } + DeleteMsgPort(worker->smpw_MsgPort); + Remove(&worker->smpw_Node); + Signal(worker->smpw_MasterPort->mp_SigTask, SIGBREAKF_CTRL_C); + } +} -- 2.11.4.GIT