#include "domain/control_logic_model.h" #include "domain/register_repository.h" #include "domain/virtual_register_repository.h" #include "services/software_logic_executor.h" #include #include #include #include #include #include namespace { LogicNode contact(const std::string &id, int address) { return {id, ContactNodeConfig{ RegisterAddress{RegisterArea::M, address}, ContactMode::NormallyOpen}, true}; } LogicNode coil(const std::string &id, int address) { return {id, CoilNodeConfig{ RegisterAddress{RegisterArea::M, address}, CoilMode::Normal}, true}; } ControlLogic makeLogic(int index, int rung_count = 1) { ControlLogic logic; logic.id = "logic-" + std::to_string(index); logic.name = logic.id; logic.enabled = true; for (int rung_index = 0; rung_index < rung_count; ++rung_index) { const int object_index = index * rung_count + rung_index; LadderRung rung; rung.id = "rung-" + std::to_string(index) + "-" + std::to_string(rung_index); rung.name = rung.id; for (int column = 0; column < ProjectLimits::kMaximumConditionColumns; ++column) { rung.cells.push_back({ rung.id + "-cell-" + std::to_string(column), column == 0 ? LadderCellKind::Node : LadderCellKind::Wire, column == 0 ? std::optional{contact( "contact-" + std::to_string(object_index), object_index)} : std::nullopt}); } rung.output = coil( "coil-" + std::to_string(object_index), object_index + 1000); logic.rungs.push_back(std::move(rung)); } return logic; } class PerformanceTests final : public QObject { Q_OBJECT private slots: void initTestCase() { qInfo().noquote() << QStringLiteral("性能测试开始:以下 RESULT 的耗时均为平均每次执行时间"); qInfo().noquote() << QStringLiteral("测试项目 1:工程上限规模的软件扫描"); qInfo().noquote() << QStringLiteral("测试项目 2:超出工程上限的扫描压力测试"); qInfo().noquote() << QStringLiteral("测试项目 3:4001 个虚拟 M 地址的边界读写"); qInfo().noquote() << QStringLiteral("测试项目 4:256 个连续 D 字的轮询规模读写"); } void softwareExecutor_scansMaximumValidProject() { std::vector logics; logics.reserve(ProjectLimits::kMaximumControlLogics); for (std::size_t index = 0; index < ProjectLimits::kMaximumControlLogics; ++index) { logics.push_back(makeLogic( static_cast(index), 64)); } SoftwareLogicExecutor executor; VirtualRegisterRepository repository; QVERIFY(executor.validate(logics).succeeded); QVERIFY(executor.executeScan(logics, repository).succeeded); QBENCHMARK { executor.executeScan(logics, repository); } QVERIFY(executor.executeScan(logics, repository).succeeded); } void softwareExecutor_scansStressProject() { std::vector logics; logics.reserve(100); for (int index = 0; index < 100; ++index) { logics.push_back(makeLogic(index)); } SoftwareLogicExecutor executor; VirtualRegisterRepository repository; QVERIFY(executor.validate(logics).succeeded); QBENCHMARK { executor.executeScan(logics, repository); } QVERIFY(executor.executeScan(logics, repository).succeeded); } void virtualRepository_handlesBoundaryBitWorkload() { VirtualRegisterRepository repository; for (int index = 0; index <= RegisterAddress::kMaximumIndex; ++index) { QVERIFY(repository.writeBit( {RegisterArea::M, index}, (index % 2) == 0) .succeeded); QVERIFY(repository.readBit({RegisterArea::M, index}).succeeded); } QBENCHMARK { for (int index = 0; index <= RegisterAddress::kMaximumIndex; ++index) { repository.writeBit( {RegisterArea::M, index}, (index % 2) == 0); repository.readBit({RegisterArea::M, index}); } } QVERIFY(repository.readBit({RegisterArea::M, 0}).succeeded); QVERIFY(repository.readBit({RegisterArea::M, RegisterAddress::kMaximumIndex}).succeeded); } void virtualRepository_handlesPollSizedWordBlocks() { const int word_count = static_cast(ProjectLimits::kMaximumPollAddresses); std::vector values(static_cast(word_count)); for (int index = 0; index < word_count; ++index) { values[static_cast(index)] = static_cast(index); } VirtualRegisterRepository repository; QVERIFY(repository.writeWords( {RegisterArea::D, 0}, values) .succeeded); QVERIFY(repository.readWords( {RegisterArea::D, 0}, word_count) .succeeded); QBENCHMARK { repository.writeWords({RegisterArea::D, 0}, values); repository.readWords({RegisterArea::D, 0}, word_count); } const WordsReadResult result = repository.readWords( {RegisterArea::D, 0}, word_count); QVERIFY(result.succeeded && result.values == values); } void cleanupTestCase() { qInfo().noquote() << QStringLiteral("性能测试结束:请结合上方四项 RESULT 和最后的 Totals 判断结果"); } }; } // namespace QTEST_APPLESS_MAIN(PerformanceTests) #include "performance_tests.moc"