15 rng(
std::random_device{}()),
25 return "ProprioceptionStressTest";
34 defs->optional(properties.robotName,
36 "The name of the robot to test with (e.g., 'Armar6', 'Armar7')");
38 defs->optional(properties.numJoints,
40 "Number of mock joints to generate for testing");
42 defs->optional(properties.writeFrequencyHz,
44 "Frequency of write operations in Hz (0 = disabled)");
46 defs->optional(properties.readFrequencyHz,
48 "Frequency of read operations in Hz (0 = disabled)");
50 defs->optional(properties.numParallelReads,
52 "Number of parallel read threads (for testing shared mutexes)");
54 defs->optional(properties.numParallelWrites,
55 "p.numParallelWrites",
56 "Number of parallel write threads (for testing concurrent writes)");
58 defs->optional(properties.numExtraFloats,
60 "Number of extra float values to write per snapshot");
62 defs->optional(properties.numExtraLongs,
64 "Number of extra long values to write per snapshot");
66 defs->optional(properties.statisticsIntervalSec,
67 "p.statisticsIntervalSec",
68 "How often to print statistics (in seconds)");
70 defs->optional(properties.verboseLogging,
72 "Enable verbose logging of each read/write operation");
80 ARMARX_INFO <<
"Initializing ProprioceptionStressTest component";
82 ARMARX_INFO <<
" Number of joints: " << properties.numJoints;
83 ARMARX_INFO <<
" Write frequency: " << properties.writeFrequencyHz <<
" Hz"
84 <<
" (x" << properties.numParallelWrites <<
" threads)";
85 ARMARX_INFO <<
" Read frequency: " << properties.readFrequencyHz <<
" Hz"
86 <<
" (x" << properties.numParallelReads <<
" threads)";
96 robotReader.connect(
mns);
97 robotWriter.connect(
mns);
101 memoryWriter =
mns.useWriter(constants::memoryName);
106 startTime = std::chrono::steady_clock::now();
109 if (properties.writeFrequencyHz > 0 && properties.numParallelWrites > 0)
111 ARMARX_INFO <<
"Starting " << properties.numParallelWrites <<
" write task(s) at "
112 << properties.writeFrequencyHz <<
" Hz each";
114 for (
int i = 0; i < properties.numParallelWrites; ++i)
120 writeTasks.push_back(task);
125 ARMARX_INFO <<
"Write operations disabled (frequency = 0 or numParallelWrites = 0)";
129 if (properties.readFrequencyHz > 0 && properties.numParallelReads > 0)
131 ARMARX_INFO <<
"Starting " << properties.numParallelReads <<
" read task(s) at "
132 << properties.readFrequencyHz <<
" Hz each";
134 for (
int i = 0; i < properties.numParallelReads; ++i)
140 readTasks.push_back(task);
145 ARMARX_INFO <<
"Read operations disabled (frequency = 0 or numParallelReads = 0)";
149 if (properties.statisticsIntervalSec > 0)
151 ARMARX_INFO <<
"Starting statistics task (interval: "
152 << properties.statisticsIntervalSec <<
" seconds)";
156 while (statsTask && !statsTask->isStopped())
171 ARMARX_INFO <<
"Disconnecting ProprioceptionStressTest...";
174 for (
auto& task : writeTasks)
184 for (
auto& task : readTasks)
203 ARMARX_INFO <<
"ProprioceptionStressTest disconnected";
209 ARMARX_INFO <<
"Exiting ProprioceptionStressTest component";
213 ProprioceptionStressTest::writeLoop()
217 while (!writeTasks.empty())
222 auto proprioception = generateMockProprioceptionData();
226 bool success = storeProprioceptionWithExtras(
227 proprioception, properties.robotName, properties.robotName,
timestamp);
233 if (properties.verboseLogging)
236 <<
": Stored proprioception data with "
237 << proprioception.joints.position.size() <<
" joints, "
238 << proprioception.extraFloats.size() <<
" extraFloats, "
239 << proprioception.extraLongs.size() <<
" extraLongs at "
240 <<
timestamp.toMicroSecondsSinceEpoch() <<
" us";
247 << (writeCount.load() + writeErrorCount.load()) <<
")";
250 catch (
const std::exception& e)
253 ARMARX_ERROR <<
"Exception during write operation: " << e.what();
256 metronome.waitForNextTick();
261 ProprioceptionStressTest::readLoop()
265 while (!readTasks.empty())
271 auto proprioception = robotReader.queryProprioception(properties.robotName,
timestamp);
275 if (proprioception.has_value())
279 if (properties.verboseLogging)
281 const auto& joints = proprioception->joints.position;
283 <<
": Retrieved proprioception data with " << joints.size()
284 <<
" joints at " <<
timestamp.toMicroSecondsSinceEpoch() <<
" us";
291 if (properties.verboseLogging)
294 <<
": No proprioception data available at "
295 <<
timestamp.toMicroSecondsSinceEpoch() <<
" us";
299 catch (
const std::exception& e)
302 ARMARX_ERROR <<
"Exception during read operation: " << e.what();
305 metronome.waitForNextTick();
309 arondto::Proprioception
310 ProprioceptionStressTest::generateMockProprioceptionData()
312 arondto::Proprioception proprioception;
315 for (
int i = 0; i < properties.numJoints; ++i)
317 std::string jointName =
"Joint_" + std::to_string(i);
318 float angle = jointAngleDist(rng);
319 proprioception.joints.position[jointName] =
angle;
323 for (
int i = 0; i < properties.numExtraFloats; ++i)
325 std::string key =
"extraFloat_" + std::to_string(i);
326 float value = jointAngleDist(rng);
327 proprioception.extraFloats[key] =
value;
331 for (
int i = 0; i < properties.numExtraLongs; ++i)
333 std::string key =
"extraLong_" + std::to_string(i);
334 long value =
static_cast<long>(jointAngleDist(rng) * 1000);
335 proprioception.extraLongs[key] =
value;
338 return proprioception;
342 ProprioceptionStressTest::storeProprioceptionWithExtras(
343 const arondto::Proprioception& proprioception,
344 const std::string& robotTypeName,
345 const std::string& robotName,
348 using namespace armem::robot_state;
351 const auto providerId = armem::MemoryID(
352 constants::memoryName, constants::proprioceptionCoreSegment, robotTypeName);
353 const auto entityID = providerId.withEntityName(robotName).withTimestamp(
timestamp);
356 armem::EntityUpdate
update;
357 update.entityID = entityID;
358 update.instancesData = {proprioception.toAron()};
362 armem::EntityUpdateResult updateResult = memoryWriter.commit(update);
374 ProprioceptionStressTest::printStatistics()
376 const auto now = std::chrono::steady_clock::now();
377 const auto elapsedSec =
378 std::chrono::duration_cast<std::chrono::duration<double>>(now - startTime).count();
380 const uint64_t writes = writeCount.load();
381 const uint64_t writeErrors = writeErrorCount.load();
382 const uint64_t reads = readCount.load();
383 const uint64_t readSuccess = readSuccessCount.load();
384 const uint64_t readFailure = readFailureCount.load();
386 const double writeRate = (elapsedSec > 0) ? (writes / elapsedSec) : 0.0;
387 const double readRate = (elapsedSec > 0) ? (reads / elapsedSec) : 0.0;
388 const double readSuccessRate = (reads > 0) ? (100.0 * readSuccess / reads) : 0.0;
391 <<
"========================================\n"
392 <<
" ProprioceptionStressTest Statistics\n"
393 <<
"========================================\n"
394 <<
"Elapsed time: " << std::fixed << std::setprecision(2) << elapsedSec
396 <<
"Robot: " << properties.robotName <<
"\n"
397 <<
"----------------------------------------\n"
398 <<
"WRITE Operations:\n"
399 <<
" Total writes: " << writes <<
"\n"
400 <<
" Write errors: " << writeErrors <<
"\n"
401 <<
" Write rate: " << std::fixed << std::setprecision(2) << writeRate
403 <<
"----------------------------------------\n"
404 <<
"READ Operations:\n"
405 <<
" Total reads: " << reads <<
"\n"
406 <<
" Successful reads: " << readSuccess <<
"\n"
407 <<
" Failed reads: " << readFailure <<
"\n"
408 <<
" Read rate: " << std::fixed << std::setprecision(2) << readRate
410 <<
" Success rate: " << std::fixed << std::setprecision(1)
411 << readSuccessRate <<
" %\n"
412 <<
"========================================";