综合平台编程器项目的远程存储
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

197 рядки
6.1 KiB

  1. #include "domain/control_logic_model.h"
  2. #include "domain/register_repository.h"
  3. #include "domain/virtual_register_repository.h"
  4. #include "services/software_logic_executor.h"
  5. #include <QDebug>
  6. #include <QTest>
  7. #include <cstdint>
  8. #include <string>
  9. #include <utility>
  10. #include <vector>
  11. namespace
  12. {
  13. LogicNode contact(const std::string &id, int address)
  14. {
  15. return {id,
  16. ContactNodeConfig{
  17. RegisterAddress{RegisterArea::M, address},
  18. ContactMode::NormallyOpen},
  19. true};
  20. }
  21. LogicNode coil(const std::string &id, int address)
  22. {
  23. return {id,
  24. CoilNodeConfig{
  25. RegisterAddress{RegisterArea::M, address},
  26. CoilMode::Normal},
  27. true};
  28. }
  29. ControlLogic makeLogic(int index, int rung_count = 1)
  30. {
  31. ControlLogic logic;
  32. logic.id = "logic-" + std::to_string(index);
  33. logic.name = logic.id;
  34. logic.enabled = true;
  35. for (int rung_index = 0; rung_index < rung_count; ++rung_index)
  36. {
  37. const int object_index = index * rung_count + rung_index;
  38. LadderRung rung;
  39. rung.id = "rung-" + std::to_string(index) + "-"
  40. + std::to_string(rung_index);
  41. rung.name = rung.id;
  42. for (int column = 0;
  43. column < ProjectLimits::kMaximumConditionColumns;
  44. ++column)
  45. {
  46. rung.cells.push_back({
  47. rung.id + "-cell-" + std::to_string(column),
  48. column == 0 ? LadderCellKind::Node : LadderCellKind::Wire,
  49. column == 0
  50. ? std::optional<LogicNode>{contact(
  51. "contact-" + std::to_string(object_index),
  52. object_index)}
  53. : std::nullopt});
  54. }
  55. rung.output = coil(
  56. "coil-" + std::to_string(object_index), object_index + 1000);
  57. logic.rungs.push_back(std::move(rung));
  58. }
  59. return logic;
  60. }
  61. class PerformanceTests final : public QObject
  62. {
  63. Q_OBJECT
  64. private slots:
  65. void initTestCase()
  66. {
  67. qInfo().noquote()
  68. << QStringLiteral("性能测试开始:以下 RESULT 的耗时均为平均每次执行时间");
  69. qInfo().noquote()
  70. << QStringLiteral("测试项目 1:工程上限规模的软件扫描");
  71. qInfo().noquote()
  72. << QStringLiteral("测试项目 2:超出工程上限的扫描压力测试");
  73. qInfo().noquote()
  74. << QStringLiteral("测试项目 3:4001 个虚拟 M 地址的边界读写");
  75. qInfo().noquote()
  76. << QStringLiteral("测试项目 4:256 个连续 D 字的轮询规模读写");
  77. }
  78. void softwareExecutor_scansMaximumValidProject()
  79. {
  80. std::vector<ControlLogic> logics;
  81. logics.reserve(ProjectLimits::kMaximumControlLogics);
  82. for (std::size_t index = 0;
  83. index < ProjectLimits::kMaximumControlLogics;
  84. ++index)
  85. {
  86. logics.push_back(makeLogic(
  87. static_cast<int>(index), 64));
  88. }
  89. SoftwareLogicExecutor executor;
  90. VirtualRegisterRepository repository;
  91. QVERIFY(executor.validate(logics).succeeded);
  92. QVERIFY(executor.executeScan(logics, repository).succeeded);
  93. QBENCHMARK
  94. {
  95. executor.executeScan(logics, repository);
  96. }
  97. QVERIFY(executor.executeScan(logics, repository).succeeded);
  98. }
  99. void softwareExecutor_scansStressProject()
  100. {
  101. std::vector<ControlLogic> logics;
  102. logics.reserve(100);
  103. for (int index = 0; index < 100; ++index)
  104. {
  105. logics.push_back(makeLogic(index));
  106. }
  107. SoftwareLogicExecutor executor;
  108. VirtualRegisterRepository repository;
  109. QVERIFY(executor.validate(logics).succeeded);
  110. QBENCHMARK
  111. {
  112. executor.executeScan(logics, repository);
  113. }
  114. QVERIFY(executor.executeScan(logics, repository).succeeded);
  115. }
  116. void virtualRepository_handlesBoundaryBitWorkload()
  117. {
  118. VirtualRegisterRepository repository;
  119. for (int index = 0; index <= RegisterAddress::kMaximumIndex; ++index)
  120. {
  121. QVERIFY(repository.writeBit(
  122. {RegisterArea::M, index}, (index % 2) == 0)
  123. .succeeded);
  124. QVERIFY(repository.readBit({RegisterArea::M, index}).succeeded);
  125. }
  126. QBENCHMARK
  127. {
  128. for (int index = 0; index <= RegisterAddress::kMaximumIndex; ++index)
  129. {
  130. repository.writeBit(
  131. {RegisterArea::M, index}, (index % 2) == 0);
  132. repository.readBit({RegisterArea::M, index});
  133. }
  134. }
  135. QVERIFY(repository.readBit({RegisterArea::M, 0}).succeeded);
  136. QVERIFY(repository.readBit({RegisterArea::M, RegisterAddress::kMaximumIndex}).succeeded);
  137. }
  138. void virtualRepository_handlesPollSizedWordBlocks()
  139. {
  140. const int word_count = static_cast<int>(ProjectLimits::kMaximumPollAddresses);
  141. std::vector<std::int16_t> values(static_cast<std::size_t>(word_count));
  142. for (int index = 0; index < word_count; ++index)
  143. {
  144. values[static_cast<std::size_t>(index)] =
  145. static_cast<std::int16_t>(index);
  146. }
  147. VirtualRegisterRepository repository;
  148. QVERIFY(repository.writeWords(
  149. {RegisterArea::D, 0}, values)
  150. .succeeded);
  151. QVERIFY(repository.readWords(
  152. {RegisterArea::D, 0}, word_count)
  153. .succeeded);
  154. QBENCHMARK
  155. {
  156. repository.writeWords({RegisterArea::D, 0}, values);
  157. repository.readWords({RegisterArea::D, 0}, word_count);
  158. }
  159. const WordsReadResult result = repository.readWords(
  160. {RegisterArea::D, 0}, word_count);
  161. QVERIFY(result.succeeded && result.values == values);
  162. }
  163. void cleanupTestCase()
  164. {
  165. qInfo().noquote()
  166. << QStringLiteral("性能测试结束:请结合上方四项 RESULT 和最后的 Totals 判断结果");
  167. }
  168. };
  169. } // namespace
  170. QTEST_APPLESS_MAIN(PerformanceTests)
  171. #include "performance_tests.moc"