10 rng(
std::random_device{}()),
20 return "ProprioceptionStressTest";
29 defs->optional(properties.robotName,
31 "The name of the robot to test with (e.g., 'Armar6', 'Armar7')");
33 defs->optional(properties.numJoints,
35 "Number of mock joints to generate for testing");
37 defs->optional(properties.writeFrequencyHz,
39 "Frequency of write operations in Hz (0 = disabled)");
41 defs->optional(properties.readFrequencyHz,
43 "Frequency of read operations in Hz (0 = disabled)");
45 defs->optional(properties.numParallelReads,
47 "Number of parallel read threads (for testing shared mutexes)");
49 defs->optional(properties.numParallelWrites,
50 "p.numParallelWrites",
51 "Number of parallel write threads (for testing concurrent writes)");
53 defs->optional(properties.numExtraFloats,
55 "Number of extra float values to write per snapshot");
57 defs->optional(properties.numExtraLongs,
59 "Number of extra long values to write per snapshot");
61 defs->optional(properties.statisticsIntervalSec,
62 "p.statisticsIntervalSec",
63 "How often to print statistics (in seconds)");
65 defs->optional(properties.verboseLogging,
67 "Enable verbose logging of each read/write operation");
75 ARMARX_INFO <<
"Initializing ProprioceptionStressTest component";
77 ARMARX_INFO <<
" Number of joints: " << properties.numJoints;
78 ARMARX_INFO <<
" Write frequency: " << properties.writeFrequencyHz <<
" Hz"
79 <<
" (x" << properties.numParallelWrites <<
" threads)";
80 ARMARX_INFO <<
" Read frequency: " << properties.readFrequencyHz <<
" Hz"
81 <<
" (x" << properties.numParallelReads <<
" threads)";
91 robotReader.connect(
mns);
92 robotWriter.connect(
mns);
96 memoryWriter =
mns.useWriter(constants::memoryName);
101 startTime = std::chrono::steady_clock::now();
104 if (properties.writeFrequencyHz > 0 && properties.numParallelWrites > 0)
106 ARMARX_INFO <<
"Starting " << properties.numParallelWrites <<
" write task(s) at "
107 << properties.writeFrequencyHz <<
" Hz each";
109 for (
int i = 0; i < properties.numParallelWrites; ++i)
115 writeTasks.push_back(task);
120 ARMARX_INFO <<
"Write operations disabled (frequency = 0 or numParallelWrites = 0)";
124 if (properties.readFrequencyHz > 0 && properties.numParallelReads > 0)
126 ARMARX_INFO <<
"Starting " << properties.numParallelReads <<
" read task(s) at "
127 << properties.readFrequencyHz <<
" Hz each";
129 for (
int i = 0; i < properties.numParallelReads; ++i)
135 readTasks.push_back(task);
140 ARMARX_INFO <<
"Read operations disabled (frequency = 0 or numParallelReads = 0)";
144 if (properties.statisticsIntervalSec > 0)
146 ARMARX_INFO <<
"Starting statistics task (interval: "
147 << properties.statisticsIntervalSec <<
" seconds)";
151 while (statsTask && !statsTask->isStopped())
166 ARMARX_INFO <<
"Disconnecting ProprioceptionStressTest...";
169 for (
auto& task : writeTasks)
179 for (
auto& task : readTasks)
198 ARMARX_INFO <<
"ProprioceptionStressTest disconnected";
204 ARMARX_INFO <<
"Exiting ProprioceptionStressTest component";
208 ProprioceptionStressTest::writeLoop()
212 while (!writeTasks.empty())
217 auto proprioception = generateMockProprioceptionData();
221 bool success = storeProprioceptionWithExtras(
222 proprioception, properties.robotName, properties.robotName,
timestamp);
228 if (properties.verboseLogging)
231 <<
": Stored proprioception data with "
232 << proprioception.joints.position.size() <<
" joints, "
233 << proprioception.extraFloats.size() <<
" extraFloats, "
234 << proprioception.extraLongs.size() <<
" extraLongs at "
235 <<
timestamp.toMicroSecondsSinceEpoch() <<
" us";
242 << (writeCount.load() + writeErrorCount.load()) <<
")";
245 catch (
const std::exception& e)
248 ARMARX_ERROR <<
"Exception during write operation: " << e.what();
251 metronome.waitForNextTick();
256 ProprioceptionStressTest::readLoop()
260 while (!readTasks.empty())
266 auto proprioception = robotReader.queryProprioception(properties.robotName,
timestamp);
270 if (proprioception.has_value())
274 if (properties.verboseLogging)
276 const auto& joints = proprioception->joints.position;
278 <<
": Retrieved proprioception data with " << joints.size()
279 <<
" joints at " <<
timestamp.toMicroSecondsSinceEpoch() <<
" us";
286 if (properties.verboseLogging)
289 <<
": No proprioception data available at "
290 <<
timestamp.toMicroSecondsSinceEpoch() <<
" us";
294 catch (
const std::exception& e)
297 ARMARX_ERROR <<
"Exception during read operation: " << e.what();
300 metronome.waitForNextTick();
304 arondto::Proprioception
305 ProprioceptionStressTest::generateMockProprioceptionData()
307 arondto::Proprioception proprioception;
310 for (
int i = 0; i < properties.numJoints; ++i)
312 std::string jointName =
"Joint_" + std::to_string(i);
313 float angle = jointAngleDist(rng);
314 proprioception.joints.position[jointName] =
angle;
318 for (
int i = 0; i < properties.numExtraFloats; ++i)
320 std::string key =
"extraFloat_" + std::to_string(i);
321 float value = jointAngleDist(rng);
322 proprioception.extraFloats[key] =
value;
326 for (
int i = 0; i < properties.numExtraLongs; ++i)
328 std::string key =
"extraLong_" + std::to_string(i);
329 long value =
static_cast<long>(jointAngleDist(rng) * 1000);
330 proprioception.extraLongs[key] =
value;
333 return proprioception;
337 ProprioceptionStressTest::storeProprioceptionWithExtras(
338 const arondto::Proprioception& proprioception,
339 const std::string& robotTypeName,
340 const std::string& robotName,
343 using namespace armem::robot_state;
346 const auto providerId = armem::MemoryID(
347 constants::memoryName, constants::proprioceptionCoreSegment, robotTypeName);
348 const auto entityID = providerId.withEntityName(robotName).withTimestamp(
timestamp);
351 armem::EntityUpdate
update;
352 update.entityID = entityID;
353 update.instancesData = {proprioception.toAron()};
357 armem::EntityUpdateResult updateResult = memoryWriter.commit(update);
369 ProprioceptionStressTest::printStatistics()
371 const auto now = std::chrono::steady_clock::now();
372 const auto elapsedSec =
373 std::chrono::duration_cast<std::chrono::duration<double>>(now - startTime).count();
375 const uint64_t writes = writeCount.load();
376 const uint64_t writeErrors = writeErrorCount.load();
377 const uint64_t reads = readCount.load();
378 const uint64_t readSuccess = readSuccessCount.load();
379 const uint64_t readFailure = readFailureCount.load();
381 const double writeRate = (elapsedSec > 0) ? (writes / elapsedSec) : 0.0;
382 const double readRate = (elapsedSec > 0) ? (reads / elapsedSec) : 0.0;
383 const double readSuccessRate = (reads > 0) ? (100.0 * readSuccess / reads) : 0.0;
386 <<
"========================================\n"
387 <<
" ProprioceptionStressTest Statistics\n"
388 <<
"========================================\n"
389 <<
"Elapsed time: " << std::fixed << std::setprecision(2) << elapsedSec
391 <<
"Robot: " << properties.robotName <<
"\n"
392 <<
"----------------------------------------\n"
393 <<
"WRITE Operations:\n"
394 <<
" Total writes: " << writes <<
"\n"
395 <<
" Write errors: " << writeErrors <<
"\n"
396 <<
" Write rate: " << std::fixed << std::setprecision(2) << writeRate
398 <<
"----------------------------------------\n"
399 <<
"READ Operations:\n"
400 <<
" Total reads: " << reads <<
"\n"
401 <<
" Successful reads: " << readSuccess <<
"\n"
402 <<
" Failed reads: " << readFailure <<
"\n"
403 <<
" Read rate: " << std::fixed << std::setprecision(2) << readRate
405 <<
" Success rate: " << std::fixed << std::setprecision(1)
406 << readSuccessRate <<
" %\n"
407 <<
"========================================";