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);
920 uint32 msgSize = msg->getSize();
921 uint64 spaceToEnd, inUse = 0, inUse2 = 0;
922 char* qData = ((
char*)qHeader) +
sizeof(MessageQueueHeader);
923 uint64 qDataSize = qHeader->size -
sizeof(MessageQueueHeader);
930 if (qHeader->endPos == qHeader->startPos) {
931 spaceToEnd = qDataSize;
932 if (spaceToEnd >= msgSize) {
934 memcpy(qData, msg->data, msgSize);
935 qHeader->startPos = 0;
936 qHeader->endPos = msgSize;
938 qHeader->padding = 0;
942 if (!resizeQ(qHeader->id, qHeader->size*2)) {
950 return addToQ(procID, qType, msg);
953 else if (qHeader->endPos > qHeader->startPos) {
954 spaceToEnd = qDataSize - qHeader->endPos;
955 if (spaceToEnd >= msgSize) {
957 memcpy(qData+qHeader->endPos, msg->data, msgSize);
958 qHeader->endPos += msgSize;
960 qHeader->padding = 0;
962 else if (qHeader->startPos > msgSize) {
964 memset(qData+qHeader->endPos, 0, (
size_t)spaceToEnd);
965 qHeader->padding = spaceToEnd;
967 memcpy(qData, msg->data, msgSize);
968 qHeader->endPos = msgSize;
973 if (!resizeQ(qHeader->id, qHeader->size*2)) {
981 return addToQ(procID, qType, msg);
985 spaceToEnd = qHeader->startPos - qHeader->endPos;
986 if (spaceToEnd > msgSize) {
988 memcpy(qData+qHeader->endPos, msg->data, msgSize);
989 qHeader->endPos += msgSize;
998 if (!resizeQ(qHeader->id, qHeader->size*2)) {
1006 return addToQ(procID, qType, msg);
1017 utils::Semaphore** sem = &qSemaphores[qHeader->id];
1028DataMessage* ProcessMemory::waitForQ(uint16 procID, uint8 qType, uint32 timeout) {
1030 MessageQueueHeader* qHeader = getQHeader(procID, qType);
1036 while (!qHeader->count) {
1037 utils::Semaphore** sem = &qSemaphores[qHeader->id];
1055 bool result = (*sem)->wait(remain);
1056 if (!mutex || !mutex->enter(5000, __FUNCTION__))
1069 qHeader = getQHeader(procID, qType);
1091 DataMessage* msg = NULL;
1092 if (qHeader->count) {
1101 msg =
new DataMessage(((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos,
true);
1102 qHeader->startPos += msg->getSize();
1103 if (qHeader->startPos >= qHeader->size -
sizeof(MessageQueueHeader) - qHeader->padding) {
1104 qHeader->startPos = 0;
1105 qHeader->padding = 0;
1118 printf(
"[%u] Data Size: %llu, count: %u startpos: %llu, endpos: %llu, padding: %llu\n",
1119 qHeader->id, (uint64)(qHeader->size -
sizeof(MessageQueueHeader)), qHeader->count, qHeader->startPos, qHeader->endPos, qHeader->padding);
1120 char* data = ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos;
1121 for (uint32 n=0; n<qHeader->count; n++) {
1123 printf(
" [%u: %llu - %llu] Msg size: %u Time: %s Type: %u.%u.%u\n", n,
1124 (uint64)(data - ((
char*)qHeader) -
sizeof(MessageQueueHeader)),
1125 (uint64)(data - ((
char*)qHeader) -
sizeof(MessageQueueHeader) + ((DataMessageHeader*)data)->size),
1126 ((DataMessageHeader*)data)->size,
PrintTimeString(((DataMessageHeader*)data)->time).c_str(),
1127 (((DataMessageHeader*)data)->type).levels[0],
1128 (((DataMessageHeader*)data)->type).levels[1],
1129 (((DataMessageHeader*)data)->type).levels[2]);
1131 printf(
" [%u: %llu] Msg corrupted\n",
1132 n, (uint64)(data - ((
char*)qHeader) -
sizeof(MessageQueueHeader)));
1135 data += ((DataMessageHeader*)data)->size;
1136 if (data == ((
char*)qHeader) + qHeader->size - qHeader->padding)
1137 data = ((
char*)qHeader) +
sizeof(MessageQueueHeader);
1142bool ProcessMemory::resize(uint64 newMemorySize) {
1144 if (newMemorySize > 100000000) {
1146 printf(
"Memory Error: Process Memory requested size %s denied...\n",
utils::BytifySize((
double)newMemorySize).c_str());
1151 serial = master->incrementProcessShmemSerial();
1154 if (!mutex || !mutex->enter(5000, __FUNCTION__))
1168 memcpy(newHeader, header, (
size_t)header->size);
1169 newHeader->size = newMemorySize;
1173 memorySize = newMemorySize;
1174 master->setProcessShmemSize(memorySize);
1178 if (newMemorySize > 20000000) {
1185bool ProcessMemory::resizeQ(uint16
id, uint64 newSize) {
1186 if (!header->qIndex[
id])
1188 MessageQueueHeader* qHeader = (MessageQueueHeader*) (((
char*)header) + header->qIndex[
id]);
1189 if (qHeader->id !=
id)
1192 uint64 difSize = newSize - qHeader->size;
1193 if (header->size - header->usage < difSize) {
1194 if (!resize(memorySize * 2))
1196 return resizeQ(
id, newSize);
1202 if (header->qIndex[n]) {
1211 char* data = ((
char*)header) + header->qIndex[nextID];
1212 uint64 sizeMove = header->usage - header->qIndex[nextID];
1213 memmove(data+difSize, data, (
size_t)sizeMove);
1216 if (header->qIndex[n])
1217 header->qIndex[n] += difSize;
1222 int64 size = qHeader->endPos - qHeader->startPos;
1223 uint64 firstSize = 0;
1224 uint64 secondSize = 0;
1226 qHeader->endPos = qHeader->startPos = 0;
1227 else if ((size > 0) && qHeader->startPos) {
1229 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1230 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos,
1232 qHeader->endPos = (uint64)size;
1233 qHeader->startPos = 0;
1235 else if (size < 0) {
1236 firstSize = qHeader->size -
sizeof(MessageQueueHeader) - qHeader->startPos - qHeader->padding;
1237 secondSize = qHeader->endPos;
1240 if (difSize > secondSize) {
1243 ((
char*)qHeader) + qHeader->size,
1244 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos,
1248 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + firstSize,
1249 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1250 (
size_t)secondSize);
1253 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1254 ((
char*)qHeader) + qHeader->size,
1259 char* copy = (
char*)malloc((
size_t)firstSize);
1260 memcpy(copy, ((
char*)qHeader) +
sizeof(MessageQueueHeader) + qHeader->startPos, (
size_t)firstSize);
1263 ((
char*)qHeader) +
sizeof(MessageQueueHeader) + firstSize,
1264 ((
char*)qHeader) +
sizeof(MessageQueueHeader),
1265 (
size_t)secondSize);
1267 memcpy(((
char*)qHeader) +
sizeof(MessageQueueHeader), copy, (
size_t)firstSize);
1270 qHeader->endPos = firstSize + secondSize;
1271 qHeader->startPos = 0;
1274 qHeader->size = newSize;
1275 qHeader->padding = 0;
1276 header->usage += difSize;
1292 if (!manager->
create(0)) {
1299 uint32 count = 10000;
1300 uint32 writeCount = 0;
1301 uint32 readCount = 0;
1307 uint32 queueTestThreadID;
1330 unittest::fail(
"Message Queue wait 1000ms didn't actually wait more than %.3fms", (t/1000.0));
1338 const uint32 latIters = 20000;
1339 uint64 singleTotal = 0;
1341 for (n=0; n<latIters; n++) {
1356 if (n && n % 10000 == 0) {
1357 unittest::detail(
"Single threaded message delay[%u]: %.3fus", n, ((
double)t)/(2*10000.0));
1364 double singleLatency = (double)singleTotal / (2.0 * latIters);
1387 uint64 multiTotal = 0;
1389 for (n=0; n<latIters; n++) {
1404 if (n && n % 10000 == 0) {
1405 unittest::detail(
"Multi threaded message delay[%u]: %.3fus", n, ((
double)t)/(2*10000.0));
1411 double multiLatency = (double)multiTotal / (2.0 * latIters);
1423 for (n=0; n<count/4; n++) {
1425 snprintf(str, 128,
"Test%2u", writeCount);
1427 msg->
setTime(
"TestTime", time);
1429 msg->
setTime(
"TestTime2", time);
1442 unittest::fail(
"Queue contains %u messages instead of %u", n, count/4);
1449 for (n=0; n<count/8; n++) {
1455 snprintf(str, 128,
"Test%2u", readCount);
1456 if (strcmp(str, msg->
getString(
"TestEntry")) != 0) {
1462 if (msg->
getTime(
"TestTime") != time) {
1469 if (!cstr || strcmp(str, cstr) != 0) {
1470 unittest::fail(
"Message %u from Queue corrupted string '%s'", readCount, cstr);
1475 if (msg->
getTime(
"TestTime2") != time) {
1476 unittest::fail(
"Message %u from Queue corrupted time '%llu'", readCount, msg->
getTime(
"TestTime2"));
1486 unittest::fail(
"Queue contains %u messages instead of %u", n, count/8);
1493 for (n=0; n<3*count/4; n++) {
1495 snprintf(str, 128,
"Test%2u", writeCount);
1497 msg->
setTime(
"TestTime", time);
1499 msg->
setTime(
"TestTime2", time);
1510 unittest::fail(
"Queue contains %u messages instead of %u", n, 7*count/8);
1517 for (n=0; n<7*count/8; n++) {
1523 snprintf(str, 128,
"Test%2u", readCount);
1524 if (strcmp(str, msg->
getString(
"TestEntry")) != 0) {
1530 if (msg->
getTime(
"TestTime") != time) {
1537 if (!cstr || strcmp(str, cstr) != 0) {
1538 unittest::fail(
"Message %u from Queue corrupted string '%s'", readCount, cstr);
1543 if (msg->
getTime(
"TestTime2") != time) {
1544 unittest::fail(
"Message %u from Queue corrupted time '%llu'", readCount, msg->
getTime(
"TestTime2"));
1561 double writeUs = (double)(
GetTimeNow() - writeStart);
1563 unittest::metric(
"msg_queue_throughput", (
double)count / writeUs * 1e6,
"msg/s",
true);
1763 fprintf(stderr,
"Test Slave could not add Message %u to Queue...\n", c);
1824 fprintf(stderr,
"Test Slave could not add Message %u to Queue...\n", c);
1838 uint32 maxPageCount = 100;
1839 if (!manager->
create(0)) {
1846 uint32 count = 10000;
1847 uint32 writeCount = 0;
1848 uint32 readCount = 0;
1852 uint32 queueTestThreadID;
1864 const uint32 perfIters = 20000;
1865 uint64 dualTotal = 0;
1867 for (n=0; n<perfIters; n++) {
1882 if (n && n % 10000 == 0) {
1883 unittest::detail(
"Dual threaded message delay[%u]: %.3fus", n, ((
double)t)/(2*10000.0));
1891 double elapsedUs = (double)(
GetTimeNow() - perfStart);
1893 double dualLatency = (double)dualTotal / (2.0 * perfIters);
1895 if (elapsedUs > 0.0)
1896 unittest::metric(
"dual_thread_throughput", (
double)perfIters / elapsedUs * 1e6,
"msg/s",
true);
1906 "Process memory queues: signal/command/message queue round-trips and integrity",
"memory");
1908 "Process memory dual-threaded queue latency and throughput",
"memory");
1910 "Process memory circular-queue seeded oracle fuzz (single process)",
"memory",
false);
1915 "Process memory ring: concurrent multi-reader / burst-drain / resize-under-read / "
1916 "blocking-path fuzz (set-equality oracle + read-pointer continuity)",
"memory",
false);
#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.
static bool FuzzTest()
Seeded, oracle-checked fuzz of the circular queue arithmetic (single process).
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).
static bool ConcFuzzTest()
Phase 2: CONCURRENT + cross-process fuzz of the ring (ProcessMemoryConcFuzz.cpp).
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.
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.
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.
uint64 GetProcessMemoryUsage()
Current resident memory usage of this process.
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.
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.