29 this->master = master;
38 mutex->enter(5000, __FUNCTION__);
50 if (!mutex || !mutex->enter(5000, __FUNCTION__))
57 usage = header->usage;
64 if (!mutex || !mutex->enter(5000, __FUNCTION__))
68 bool issuesFound =
false;
70 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
77 procIssues.push_back(*pInfo);
81 procIssues.push_back(*pInfo);
87 return (!issuesFound);
91 std::vector<ProcessInfoStruct>* processes =
new std::vector<ProcessInfoStruct>;
92 if (!mutex || !mutex->enter(5000, __FUNCTION__))
96 uint16 thisNodeID = this->master->getNodeID();
98 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
100 processes->push_back(*pInfo);
107 if (!mutex || !mutex->enter(5000, __FUNCTION__))
111 uint16 thisNodeID = this->master->getNodeID();
115 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
122 if (pInfo->
type == 1)
139 perfStats.push_back(stats);
148 if (!mutex || !mutex->enter(5000, __FUNCTION__))
156 for (uint8 t = 1; t<5; t++) {
157 qHeader = getQHeader(procID, t);
159 count += qHeader->
count;
160 if (qHeader->
count) {
173 serial = master->incrementProcessShmemSerial();
179 if (!mutex->enter(5000, __FUNCTION__))
196 memset(header, 0, (
size_t)memorySize);
197 header->size = memorySize;
209 pInfo->
nodeID = master->getNodeID();
218 !setupNextAvailableQ(cmdQID) ||
219 !setupNextAvailableQ(msgQID) ||
220 !setupNextAvailableQ(sigQID) ||
221 !setupNextAvailableQ(reqQID) ) {
228 pInfo = &(header->processes[0]);
234 master->setProcessShmemSize(memorySize);
242 serial = master->getProcessShmemSerial();
243 uint64 size = master->getProcessShmemSize();
244 this->port = master->port;
247 bool createdMutex =
false;
252 if (!mutex->enter(5000, __FUNCTION__))
292 if (!mutex || !mutex->enter(5000, __FUNCTION__))
297 printf(
" --------- Process header error: %llu usage: %llu serial %u --------\n", header->size, header->usage, serial);
304 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
317 pInfo->
nodeID = master->getNodeID();
326 !setupNextAvailableQ(cmdQID) ||
327 !setupNextAvailableQ(msgQID) ||
328 !setupNextAvailableQ(sigQID) ||
329 !setupNextAvailableQ(reqQID) ) {
335 pInfo = &(header->processes[id]);
347 if (!mutex || !mutex->enter(5000, __FUNCTION__))
351 deleteQ(header->processes[
id].cmdQID);
352 deleteQ(header->processes[
id].msgQID);
353 deleteQ(header->processes[
id].sigQID);
354 deleteQ(header->processes[
id].reqQID);
361 if (!mutex || !mutex->enter(5000, __FUNCTION__))
364 if (!header->processes[
id].createdTime) {
375 if (!mutex || !mutex->enter(5000, __FUNCTION__))
379 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
380 if ((
stricmp(name, pInfo->name) == 0) && pInfo->createdTime) {
392 if (!mutex || !mutex->enter(5000, __FUNCTION__))
395 uint64 t = header->processes[id].createdTime;
402 if (!mutex || !mutex->enter(5000, __FUNCTION__))
405 if (!header->processes[
id].createdTime) {
421 if (!mutex || !mutex->enter(5000, __FUNCTION__))
424 if (!header->processes[
id].createdTime) {
429 uint8 status = header->processes[id].status;
430 lastseen = header->processes[id].lastseen;
431 createTime = header->processes[id].createdTime;
438 if (!mutex || !mutex->enter(5000, __FUNCTION__))
442 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
443 if (pInfo->osID == osid) {
455 if (!mutex || !mutex->enter(5000, __FUNCTION__))
458 if (!header->processes[
id].createdTime) {
462 uint32 osID = header->processes[id].osID;
469 if (!mutex || !mutex->enter(5000, __FUNCTION__))
472 if (!header->processes[
id].createdTime) {
476 header->processes[id].osID = osid;
483 if (!mutex || !mutex->enter(5000, __FUNCTION__))
486 if (!header->processes[
id].createdTime) {
490 header->processes[id].type = type;
497 if (!mutex || !mutex->enter(5000, __FUNCTION__))
500 if (!header->processes[
id].createdTime) {
511 if (!mutex || !mutex->enter(5000, __FUNCTION__))
515 if (!pInfo->createdTime) {
523 pInfo->stats.currentCPUTicks = currentCPUTicks;
532 if (!mutex || !mutex->enter(5000, __FUNCTION__))
534 if (serial != master->getProcessShmemSerial()) {
if (!
open()) {mutex->leave();
return perfStats;}}
547 if (!mutex || !mutex->enter(5000, __FUNCTION__))
551 if (!pInfo->createdTime) {
562 if (!mutex || !mutex->enter(5000, __FUNCTION__))
566 if (!pInfo->createdTime) {
574 pInfo->stats.msgInCount++;
575 pInfo->stats.msgInBytes += inputMsg->
getSize();
579 char* inSlot = pInfo->stats.recentInMsg + ((pInfo->stats.recentInPos % 10) *
DRAFTMSGSIZE);
587 pInfo->stats.recentInPos = (pInfo->stats.recentInPos + 1) % 10;
590 pInfo->stats.msgOutCount++;
591 pInfo->stats.msgOutBytes += outputMsg->
getSize();
592 char* outSlot = pInfo->stats.recentOutMsg + ((pInfo->stats.recentOutPos % 10) *
DRAFTMSGSIZE);
594 memcpy(outSlot, outputMsg->
data, outputMsg->
data->
size);
600 pInfo->stats.recentOutPos = (pInfo->stats.recentOutPos + 1) % 10;
608 if (!mutex || !mutex->enter(5000, __FUNCTION__))
621 if (!mutex || !mutex->enter(5000, __FUNCTION__))
634 if (!mutex || !mutex->enter(5000, __FUNCTION__))
647 if (!mutex || !mutex->enter(5000, __FUNCTION__))
652 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
653 if (pInfo->createdTime)
662 if (!mutex || !mutex->enter(5000, __FUNCTION__))
667 for (uint32 n=1; n<
MAXPROC; n++, pInfo++) {
668 if (pInfo->createdTime && (pInfo->id != except))
677 if (!mutex || !mutex->enter(5000, __FUNCTION__))
691 if (!mutex || !mutex->enter(5000, __FUNCTION__))
700 if (!mutex || !mutex->enter(5000, __FUNCTION__))
709 if (!mutex || !mutex->enter(5000, __FUNCTION__))
718 if (!mutex || !mutex->enter(5000, __FUNCTION__))
727 if (!mutex || !mutex->enter(5000, __FUNCTION__))
736 uint32 count = qHeader->count;
742 if (!mutex || !mutex->enter(5000, __FUNCTION__))
751 uint32 count = qHeader->count;
757 if (!mutex || !mutex->enter(5000, __FUNCTION__))
766 uint32 count = qHeader->count;
772 if (!mutex || !mutex->enter(5000, __FUNCTION__))
781 uint32 count = qHeader->count;
809 MessageQueueHeader* qHeader = (MessageQueueHeader*) (((
char*)header) + header->qIndex[qID]);
810 if (qHeader->id != qID)
817bool ProcessMemory::setupNextAvailableQ(uint16& qID) {
822 if (!found && !header->qIndex[n]) {
826 else if (found && header->qIndex[n]) {
837 if (header->size - header->usage < size) {
838 LogPrint(0,
LOG_MEMORY,0,
"SetupQ need more memory size: %u use: %u need: %u", header->size, header->usage, size);
840 if (!resize(memorySize * 2)) {
850 header->qIndex[qID] = header->qIndex[nextID];
851 data = ((
char*)header) + header->qIndex[nextID];
852 uint64 sizeMove = header->usage - header->qIndex[nextID];
853 memmove(data+size, data, (
size_t)sizeMove);
855 for (uint32 n=nextID; n<
MAXPROC4; n++) {
856 if (header->qIndex[n])
857 header->qIndex[n] += size;
861 header->qIndex[qID] = header->usage;
862 data = ((
char*)header) + header->usage;
866 memset(data, 0, (
size_t)size);
867 ((MessageQueueHeader*)data)->size = size;
868 ((MessageQueueHeader*)data)->id = qID;
869 snprintf(((MessageQueueHeader*)data)->name,
MAXKEYNAMELEN,
"PsycloneProcessMemoryQueue_%u_%u", port, qID);
872 header->usage += size;
876bool ProcessMemory::deleteQ(uint16
id) {
877 if (!header->qIndex[
id])
879 MessageQueueHeader* qHeader = (MessageQueueHeader*)(((
char*)header) + header->qIndex[
id]);
880 uint64 size = qHeader->size;
885 for (uint32 n=
id+1; n<
MAXPROC4; n++) {
886 if (header->qIndex[n]) {
890 memmove(qHeader, ((
char*)qHeader)+size, (
size_t)(header->usage - header->qIndex[nextID]));
892 header->qIndex[n] -= size;
897 header->qIndex[id] = 0;
898 header->usage -= size;
903bool ProcessMemory::addToQ(uint16 procID, uint8 qType,
DataMessage* msg) {
904 MessageQueueHeader* qHeader = getQHeader(procID, qType);
908 uint32 msgSize = msg->getSize();
909 uint64 spaceToEnd, inUse = 0, inUse2 = 0;
910 char* qData = ((
char*)qHeader) +
sizeof(MessageQueueHeader);
911 uint64 qDataSize = qHeader->size -
sizeof(MessageQueueHeader);
918 if (qHeader->endPos == qHeader->startPos) {
919 spaceToEnd = qDataSize;
920 if (spaceToEnd >= msgSize) {
922 memcpy(qData, msg->data, msgSize);
923 qHeader->startPos = 0;
924 qHeader->endPos = msgSize;
926 qHeader->padding = 0;
930 if (!resizeQ(qHeader->id, qHeader->size*2))
933 return addToQ(procID, qType, msg);
936 else if (qHeader->endPos > qHeader->startPos) {
937 spaceToEnd = qDataSize - qHeader->endPos;
938 if (spaceToEnd >= msgSize) {
940 memcpy(qData+qHeader->endPos, msg->data, msgSize);
941 qHeader->endPos += msgSize;
943 qHeader->padding = 0;
945 else if (qHeader->startPos > msgSize) {
947 memset(qData+qHeader->endPos, 0, (
size_t)spaceToEnd);
948 qHeader->padding = spaceToEnd;
950 memcpy(qData, msg->data, msgSize);
951 qHeader->endPos = msgSize;
956 if (!resizeQ(qHeader->id, qHeader->size*2))
959 return addToQ(procID, qType, msg);
963 spaceToEnd = qHeader->startPos - qHeader->endPos;
964 if (spaceToEnd > msgSize) {
966 memcpy(qData+qHeader->endPos, msg->data, msgSize);
967 qHeader->endPos += msgSize;
972 if (!resizeQ(qHeader->id, qHeader->size*2))
975 return addToQ(procID, qType, msg);
986 utils::Semaphore** sem = &qSemaphores[qHeader->id];
997DataMessage* ProcessMemory::waitForQ(uint16 procID, uint8 qType, uint32 timeout) {
999 MessageQueueHeader* qHeader = getQHeader(procID, qType);
1005 while (!qHeader->count) {
1006 utils::Semaphore** sem = &qSemaphores[qHeader->id];
1024 bool result = (*sem)->wait(remain);
1025 if (!mutex || !mutex->enter(5000, __FUNCTION__))
1038 qHeader = getQHeader(procID, qType);
1047 DataMessage* msg = NULL;
1048 if (qHeader->count) {
1049 msg =
new DataMessage(((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos,
true);
1050 qHeader->startPos += msg->getSize();
1051 if (qHeader->startPos >= qHeader->size -
sizeof(MessageQueueHeader) - qHeader->padding) {
1052 qHeader->startPos = 0;
1053 qHeader->padding = 0;
1066 printf(
"[%u] Data Size: %llu, count: %u startpos: %llu, endpos: %llu, padding: %llu\n",
1067 qHeader->id, (uint64)(qHeader->size -
sizeof(MessageQueueHeader)), qHeader->count, qHeader->startPos, qHeader->endPos, qHeader->padding);
1068 char* data = ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos;
1069 for (uint32 n=0; n<qHeader->count; n++) {
1071 printf(
" [%u: %llu - %llu] Msg size: %u Time: %s Type: %u.%u.%u\n", n,
1072 (uint64)(data - ((
char*)qHeader) -
sizeof(MessageQueueHeader)),
1073 (uint64)(data - ((
char*)qHeader) -
sizeof(MessageQueueHeader) + ((DataMessageHeader*)data)->size),
1074 ((DataMessageHeader*)data)->size,
PrintTimeString(((DataMessageHeader*)data)->time).c_str(),
1075 (((DataMessageHeader*)data)->type).levels[0],
1076 (((DataMessageHeader*)data)->type).levels[1],
1077 (((DataMessageHeader*)data)->type).levels[2]);
1079 printf(
" [%u: %llu] Msg corrupted\n",
1080 n, (uint64)(data - ((
char*)qHeader) -
sizeof(MessageQueueHeader)));
1083 data += ((DataMessageHeader*)data)->size;
1084 if (data == ((
char*)qHeader) + qHeader->size - qHeader->padding)
1085 data = ((
char*)qHeader) +
sizeof(MessageQueueHeader);
1090bool ProcessMemory::resize(uint64 newMemorySize) {
1092 if (newMemorySize > 100000000) {
1094 printf(
"Memory Error: Process Memory requested size %s denied...\n",
utils::BytifySize((
double)newMemorySize).c_str());
1099 serial = master->incrementProcessShmemSerial();
1102 if (!mutex || !mutex->enter(5000, __FUNCTION__))
1116 memcpy(newHeader, header, (
size_t)header->size);
1117 newHeader->size = newMemorySize;
1121 memorySize = newMemorySize;
1122 master->setProcessShmemSize(memorySize);
1126 if (newMemorySize > 20000000) {
1133bool ProcessMemory::resizeQ(uint16
id, uint64 newSize) {
1134 if (!header->qIndex[
id])
1136 MessageQueueHeader* qHeader = (MessageQueueHeader*) (((
char*)header) + header->qIndex[
id]);
1137 if (qHeader->id !=
id)
1140 uint64 difSize = newSize - qHeader->size;
1141 if (header->size - header->usage < difSize) {
1142 if (!resize(memorySize * 2))
1144 return resizeQ(
id, newSize);
1150 if (header->qIndex[n]) {
1159 char* data = ((
char*)header) + header->qIndex[nextID];
1160 uint64 sizeMove = header->usage - header->qIndex[nextID];
1161 memmove(data+difSize, data, (
size_t)sizeMove);
1164 if (header->qIndex[n])
1165 header->qIndex[n] += difSize;
1170 int64 size = qHeader->endPos - qHeader->startPos;
1171 uint64 firstSize = 0;
1172 uint64 secondSize = 0;
1174 qHeader->endPos = qHeader->startPos = 0;
1175 else if ((size > 0) && qHeader->startPos) {
1177 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1178 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos,
1180 qHeader->endPos = (uint64)size;
1181 qHeader->startPos = 0;
1183 else if (size < 0) {
1184 firstSize = qHeader->size -
sizeof(MessageQueueHeader) - qHeader->startPos - qHeader->padding;
1185 secondSize = qHeader->endPos;
1188 if (difSize > secondSize) {
1191 ((
char*)qHeader) + qHeader->size,
1192 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos,
1196 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + firstSize,
1197 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1198 (
size_t)secondSize);
1201 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1202 ((
char*)qHeader) + qHeader->size,
1207 char* copy = (
char*)malloc((
size_t)firstSize);
1208 memcpy(copy, ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos, (
size_t)firstSize);
1211 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + firstSize,
1212 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1213 (
size_t)secondSize);
1215 memcpy(((
char*)qHeader) +
sizeof(MessageQueueHeader), copy, (
size_t)firstSize);
1218 qHeader->endPos = firstSize + secondSize;
1219 qHeader->startPos = 0;
1222 qHeader->size = newSize;
1223 qHeader->padding = 0;
1224 header->usage += difSize;
1240 if (!manager->
create(0)) {
1247 uint32 count = 10000;
1248 uint32 writeCount = 0;
1249 uint32 readCount = 0;
1255 uint32 queueTestThreadID;
1278 unittest::fail(
"Message Queue wait 1000ms didn't actually wait more than %.3fms", (t/1000.0));
1286 const uint32 latIters = 20000;
1287 uint64 singleTotal = 0;
1289 for (n=0; n<latIters; n++) {
1304 if (n && n % 10000 == 0) {
1305 unittest::detail(
"Single threaded message delay[%u]: %.3fus", n, ((
double)t)/(2*10000.0));
1312 double singleLatency = (double)singleTotal / (2.0 * latIters);
1335 uint64 multiTotal = 0;
1337 for (n=0; n<latIters; n++) {
1352 if (n && n % 10000 == 0) {
1353 unittest::detail(
"Multi threaded message delay[%u]: %.3fus", n, ((
double)t)/(2*10000.0));
1359 double multiLatency = (double)multiTotal / (2.0 * latIters);
1371 for (n=0; n<count/4; n++) {
1373 snprintf(str, 128,
"Test%2u", writeCount);
1375 msg->
setTime(
"TestTime", time);
1377 msg->
setTime(
"TestTime2", time);
1390 unittest::fail(
"Queue contains %u messages instead of %u", n, count/4);
1397 for (n=0; n<count/8; n++) {
1403 snprintf(str, 128,
"Test%2u", readCount);
1404 if (strcmp(str, msg->
getString(
"TestEntry")) != 0) {
1410 if (msg->
getTime(
"TestTime") != time) {
1417 if (!cstr || strcmp(str, cstr) != 0) {
1418 unittest::fail(
"Message %u from Queue corrupted string '%s'", readCount, cstr);
1423 if (msg->
getTime(
"TestTime2") != time) {
1424 unittest::fail(
"Message %u from Queue corrupted time '%llu'", readCount, msg->
getTime(
"TestTime2"));
1434 unittest::fail(
"Queue contains %u messages instead of %u", n, count/8);
1441 for (n=0; n<3*count/4; n++) {
1443 snprintf(str, 128,
"Test%2u", writeCount);
1445 msg->
setTime(
"TestTime", time);
1447 msg->
setTime(
"TestTime2", time);
1458 unittest::fail(
"Queue contains %u messages instead of %u", n, 7*count/8);
1465 for (n=0; n<7*count/8; n++) {
1471 snprintf(str, 128,
"Test%2u", readCount);
1472 if (strcmp(str, msg->
getString(
"TestEntry")) != 0) {
1478 if (msg->
getTime(
"TestTime") != time) {
1485 if (!cstr || strcmp(str, cstr) != 0) {
1486 unittest::fail(
"Message %u from Queue corrupted string '%s'", readCount, cstr);
1491 if (msg->
getTime(
"TestTime2") != time) {
1492 unittest::fail(
"Message %u from Queue corrupted time '%llu'", readCount, msg->
getTime(
"TestTime2"));
1509 double writeUs = (double)(
GetTimeNow() - writeStart);
1511 unittest::metric(
"msg_queue_throughput", (
double)count / writeUs * 1e6,
"msg/s",
true);
1711 fprintf(stderr,
"Test Slave could not add Message %u to Queue...\n", c);
1772 fprintf(stderr,
"Test Slave could not add Message %u to Queue...\n", c);
1786 uint32 maxPageCount = 100;
1787 if (!manager->
create(0)) {
1794 uint32 count = 10000;
1795 uint32 writeCount = 0;
1796 uint32 readCount = 0;
1800 uint32 queueTestThreadID;
1812 const uint32 perfIters = 20000;
1813 uint64 dualTotal = 0;
1815 for (n=0; n<perfIters; n++) {
1830 if (n && n % 10000 == 0) {
1831 unittest::detail(
"Dual threaded message delay[%u]: %.3fus", n, ((
double)t)/(2*10000.0));
1839 double elapsedUs = (double)(
GetTimeNow() - perfStart);
1841 double dualLatency = (double)dualTotal / (2.0 * perfIters);
1843 if (elapsedUs > 0.0)
1844 unittest::metric(
"dual_thread_throughput", (
double)perfIters / elapsedUs * 1e6,
"msg/s",
true);
1854 "Process memory queues: signal/command/message queue round-trips and integrity",
"memory");
1856 "Process memory dual-threaded queue latency and throughput",
"memory");
#define DRAFTMSGSIZE
Fixed byte size of the per-message draft slots used in the recent-message rings of ComponentStats / P...
#define GetObjID(data)
Extract the cid field from a binary object block: the uint32 at byte offset 4 (after the leading size...
Shared-memory process ("space") table plus per-process message queues.
#define PSYPROC_ACTIVE
Process is actively running.
#define MSGQ_TYPE
Data-message queue.
#define CHECKPROCESSMEMORYSERIAL
Re-open the process segment if the master's resize serial no longer matches ours (another process re-...
#define SIGQ_TYPE
Signal queue.
#define PSYPROC_IDLE
Process is idle.
#define MAXPROC4
Maximum queues per node (MAXPROC x 4 queue types).
#define PSYPROC_CREATED
Table entry created; process not yet started.
#define INITIALQSIZE
Initial byte size of a newly created per-process queue.
#define CMDQ_TYPE
Command queue.
#define MAXPROC
Maximum processes (spaces) per node.
#define REQQ_TYPE
Request queue.
Process-wide thread registry and lifecycle manager: the concurrency core of CMSDK.
Small, dependency-free unit test harness used by all CMSDK object tests.
#define thread_ret_val(ret)
#define THREAD_FUNCTION_CALL
#define MAXCOMMANDLINELEN
The central Psyclone data container: a self-contained binary message with typed, named user entries.
bool setTime(const char *key, uint64 value)
setTime(const char* key, uint64 value)
bool setString(const char *key, const char *value)
setString(const char* key, const char* value)
DataMessageHeader * data
Pointer to the message's flat memory block (header + user entries).
uint32 getSize()
getSize() Get message size Many types of data of any size can be put into a message as user entries; ...
uint64 getTime(const char *key)
getTime(const char* key)
uint64 getCreatedTime()
getCreatedTime()
const char * getString(const char *key)
getString(const char* key)
Handle to the node's master shared-memory segment (MemoryMasterStruct).
Top-level facade of the shared-memory subsystem for one process.
ProcessMemory * processMemory
Accessor for the process table and per-process queues.
bool create(uint16 sysID, uint32 slotCount=100000, uint16 binCount=2, uint32 minBlockSize=1024, uint32 maxBlockSize=64 *1024, uint64 initSize=50000000L, uint64 maxSize=1000000000L, bool force=false)
Create all shared segments for a new node instance (master process only).
bool setProcessCommandLine(uint16 id, const char *cmdline)
Record the launch command line.
DataMessage * waitForCmdQ(uint16 procID, uint32 timeout)
Wait on the command queue.
static bool UnitTest()
Self-test.
bool addToCmdQ(uint16 procID, DataMessage *msg)
Enqueue on the command queue.
bool getProcessName(uint16 id, char *name, uint32 maxSize)
Copy the process name into name (max maxSize bytes).
uint32 getProcessOSID(uint16 id)
bool createNewProcess(const char *name, uint16 &id)
Register a new process (space) in the table.
uint32 getCmdQCount(uint16 procID)
bool addToReqQ(uint16 procID, DataMessage *msg)
Enqueue on the request queue.
bool addToMsgQ(uint16 procID, DataMessage *msg)
Enqueue on the data-message queue.
ProcessMemory(MasterMemory *master)
static bool PerfTest()
Queue throughput benchmark.
bool addLocalPerformanceStats(std::list< PerfStats > &perfStats)
Append PerfStats snapshots for all local processes to perfStats.
uint32 getSigQCount(uint16 procID)
AveragePerfStats getProcessPerfStats(uint16 procID)
bool addToAllSignalQs(DataMessage *msg)
Broadcast to every process's signal queue.
bool addToSigQ(uint16 procID, DataMessage *msg)
Enqueue on the signal queue.
bool addToAllSignalQsExcept(DataMessage *msg, uint16 except)
Broadcast to all signal queues except process except.
uint64 getProcessCreateTime(uint16 id)
uint32 getMsgQCount(uint16 procID)
DataMessage * waitForMsgQ(uint16 procID, uint32 timeout)
Wait on the data-message queue.
bool setProcessOSID(uint16 id, uint32 osid)
Record the OS pid.
bool setProcessStatus(uint16 id, uint8 status, uint64 currentCPUTicks=0)
Update status + heartbeat (and optionally CPU ticks) for process id.
bool getQueueSizes(uint16 procID, uint64 &bytes, uint32 &count)
Total queued bytes/messages across all four queues of procID.
uint8 getProcessStatus(uint16 id, uint64 &lastseen)
bool getMemoryUsage(uint64 &alloc, uint64 &usage)
Report allocation/usage of the process segment.
bool deleteProcess(uint16 id)
Remove a process entry and free its queues.
bool checkProcessHeartbeats(uint32 timeoutMS, std::list< ProcessInfoStruct > &procIssues)
Find processes whose heartbeat is older than timeoutMS.
bool getProcessID(const char *name, uint16 &id)
Look up a process id by name.
bool open()
Attach to the existing process segment.
bool addToProcessStats(uint16 id, DataMessage *inputMsg, DataMessage *outputMsg)
Add message traffic to the process's stats/rings.
DataMessage * waitForReqQ(uint16 procID, uint32 timeout)
Wait on the request queue.
uint32 getReqQCount(uint16 procID)
bool setProcessType(uint16 id, uint8 type)
Set type (0 = normal, 1 = inside node).
uint16 getProcessIDFromOSID(uint32 osid)
Map an OS pid to a Psyclone process id.
bool getProcessCommandLine(uint16 id, char *cmdline, uint32 maxSize)
Copy the launch command line.
std::vector< ProcessInfoStruct > * getAllProcesses()
Snapshot all process records.
DataMessage * waitForSigQ(uint16 procID, uint32 timeout)
Wait on the signal queue.
bool setProcessPerfStats(uint16 procID, AveragePerfStats &perfStruct)
Store new performance averages.
bool create(uint32 initialProcCount)
Create the process segment (master only).
static bool CreateThread(THREAD_FUNCTION func, void *args, uint32 &newID, uint32 reqID=0)
Create a new native thread and start it immediately.
static bool IsThreadRunning(uint32 id)
Check whether the thread is still alive at the OS level.
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
Recursive mutual-exclusion lock, optionally named for cross-process use.
Counting semaphore, optionally named for cross-process use.
std::string PrintTimeString(uint64 t, bool local=true, bool us=true, bool ms=true)
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
int32 GetTimeAgeMS(uint64 t)
Age of a timestamp relative to now, in milliseconds.
int64 GetTimeAge(uint64 t)
Age of a timestamp relative to now.
uint64 GetProcessMemoryUsage()
Current resident memory usage of this process.
bool Sleep(uint32 ms)
Suspend the calling thread.
char * OpenSharedMemorySegment(const char *name, uint64 size)
Open and map an existing named shared memory segment.
Semaphore * GetSemaphore(const char *name, bool autocreate=true)
Look up (and optionally create) a named semaphore in the global registry.
char * CreateSharedMemorySegment(const char *name, uint64 size, bool force=false)
Create a named shared memory segment and map it into this process.
bool CloseSharedMemorySegment(char *data, uint64 size)
Unmap a segment previously created/opened here.
std::string BytifySize(double val)
Format a byte count with binary units, e.g.
std::string StringFormat(const char *format,...)
printf into a std::string.
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
THREAD_RET THREAD_FUNCTION_CALL ProcessMemoryPerfTest(THREAD_ARG arg)
static volatile bool g_processTestStop
static uint32 g_processTestThreadID
static struct PsyType CTRL_TEST
static THREAD_RET THREAD_FUNCTION_CALL QueueTest(THREAD_ARG arg)
void Register_ProcessMemory_Tests()
static void StopProcessTestThread()
Sliding-window averages derived from successive PerfStats snapshots.
Raw per-component performance counters sampled inside shared memory.
uint16 spaceID
Id of the space (process slot) hosting the component.
uint32 osID
OS process id of the hosting process.
uint64 totalQueueBytes
Bytes currently waiting in the component's queues.
uint64 totalInputCount
Total number of input messages.
uint64 currentCPUTicks
Cumulative CPU ticks consumed so far.
uint64 totalOutputCount
Total number of output messages.
uint64 totalOutputBytes
Total bytes posted as output messages.
uint64 currentMemoryBytes
Current memory footprint in bytes.
uint64 totalInputBytes
Total bytes received as input messages.
uint16 nodeID
Id of the node the component runs on.
uint64 firstRunStartTime
Timestamp (µs) of the very first run.
uint32 totalQueueCount
Messages currently waiting in the component's queues.
One process (space) record in the shared process table.
uint16 cmdQID
Queue index of this process's command queue.
uint16 sigQID
Queue index of this process's signal queue.
uint64 createdTime
Creation timestamp (µs).
uint16 msgQID
Queue index of this process's data-message queue.
uint16 reqQID
Queue index of this process's request queue.
uint32 osID
OS process id (pid).
char name[MAXKEYNAMELEN+1]
Process (space) name.
uint32 id
Process id; corresponds to the index in the table.
AveragePerfStats perfStats
Windowed performance averages.
uint64 lastseen
Last heartbeat/status update (µs); staleness implies a crashed space.
ProcessStats stats
Throughput counters and recent-message rings.
uint8 status
PSYPROC_* lifecycle status.
uint16 nodeID
Id of the node this process belongs to.
uint8 type
0: normal space process, 1: runs inside the node process.
Root header of the process-memory segment: fixed process table plus queue index.
ProcessInfoStruct processes[MAXPROC]
Fixed-size process table.
uint64 qIndex[MAXPROC *4]
Byte offsets of each process's four queues (0 = none).
uint32 cid
Check/magic id validated on attach.
uint64 msgOutBytes
Total bytes sent.
uint64 msgInBytes
Total bytes received.
uint64 time
Timestamp of the last update (µs).
uint64 msgOutCount
Total messages sent.
uint64 msgInCount
Total messages received.
uint64 currentCPUTicks
Cumulative CPU ticks consumed.