Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:11:56

0001 //
0002 //  test_catch2_WaitingTaskChain.cpp
0003 //  CMSSW
0004 //
0005 //  Created by Chris Jones on 7/8/21.
0006 //
0007 
0008 #define CATCH_CONFIG_MAIN
0009 #include "catch.hpp"
0010 
0011 #include "oneapi/tbb/global_control.h"
0012 
0013 #include "FWCore/Concurrency/interface/chain_first.h"
0014 #include "FWCore/Concurrency/interface/FinalWaitingTask.h"
0015 
0016 TEST_CASE("Test chain::first", "[chain::first]") {
0017   oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, 1);
0018 
0019   SECTION("no explicit exception handling") {
0020     SECTION("first | lastTask") {
0021       std::atomic<int> count{0};
0022 
0023       oneapi::tbb::task_group group;
0024       edm::FinalWaitingTask waitTask{group};
0025       {
0026         using namespace edm::waiting_task::chain;
0027         auto h = first([&count](edm::WaitingTaskHolder h) {
0028                    ++count;
0029                    REQUIRE(count.load() == 1);
0030                  }) |
0031                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0032 
0033         h.doneWaiting(std::exception_ptr());
0034       }
0035       waitTask.waitNoThrow();
0036       REQUIRE(count.load() == 1);
0037       REQUIRE(waitTask.done());
0038       REQUIRE(not waitTask.exceptionPtr());
0039     }
0040 
0041     SECTION("first | then | lastTask") {
0042       std::atomic<int> count{0};
0043 
0044       oneapi::tbb::task_group group;
0045       edm::FinalWaitingTask waitTask{group};
0046       {
0047         using namespace edm::waiting_task::chain;
0048         auto h = first([&count](auto h) {
0049                    ++count;
0050                    REQUIRE(count.load() == 1);
0051                  }) |
0052                  then([&count](auto h) {
0053                    ++count;
0054                    REQUIRE(count.load() == 2);
0055                  }) |
0056                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0057 
0058         h.doneWaiting(std::exception_ptr());
0059       }
0060       waitTask.waitNoThrow();
0061       REQUIRE(count.load() == 2);
0062       REQUIRE(waitTask.done());
0063       REQUIRE(not waitTask.exceptionPtr());
0064     }
0065 
0066     SECTION("first | then | then | lastTask") {
0067       std::atomic<int> count{0};
0068 
0069       oneapi::tbb::task_group group;
0070       edm::FinalWaitingTask waitTask{group};
0071       {
0072         using namespace edm::waiting_task::chain;
0073         auto h = first([&count](auto h) {
0074                    ++count;
0075                    REQUIRE(count.load() == 1);
0076                  }) |
0077                  then([&count](auto h) {
0078                    ++count;
0079                    REQUIRE(count.load() == 2);
0080                  }) |
0081                  then([&count](auto h) {
0082                    ++count;
0083                    REQUIRE(count.load() == 3);
0084                  }) |
0085                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0086 
0087         h.doneWaiting(std::exception_ptr());
0088       }
0089       waitTask.waitNoThrow();
0090       REQUIRE(count.load() == 3);
0091       REQUIRE(waitTask.done());
0092       REQUIRE(not waitTask.exceptionPtr());
0093     }
0094 
0095     SECTION("first | then | then | runLast") {
0096       std::atomic<int> count{0};
0097 
0098       oneapi::tbb::task_group group;
0099       edm::FinalWaitingTask waitTask{group};
0100       {
0101         using namespace edm::waiting_task::chain;
0102         first([&count](auto h) {
0103           ++count;
0104           REQUIRE(count.load() == 1);
0105         }) | then([&count](auto h) {
0106           ++count;
0107           REQUIRE(count.load() == 2);
0108         }) | then([&count](auto h) {
0109           ++count;
0110           REQUIRE(count.load() == 3);
0111         }) | runLast(edm::WaitingTaskHolder(group, &waitTask));
0112       }
0113       waitTask.waitNoThrow();
0114       REQUIRE(count.load() == 3);
0115       REQUIRE(waitTask.done());
0116       REQUIRE(not waitTask.exceptionPtr());
0117     }
0118 
0119     SECTION("exception -> first | lastTask") {
0120       std::atomic<int> count{0};
0121 
0122       oneapi::tbb::task_group group;
0123       edm::FinalWaitingTask waitTask{group};
0124       {
0125         using namespace edm::waiting_task::chain;
0126         auto h = first([&count](edm::WaitingTaskHolder h) {
0127                    ++count;
0128                    REQUIRE(false);
0129                  }) |
0130                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0131 
0132         h.doneWaiting(std::make_exception_ptr(std::exception()));
0133       }
0134       waitTask.waitNoThrow();
0135       REQUIRE(count.load() == 0);
0136       REQUIRE(waitTask.done());
0137       REQUIRE(waitTask.exceptionPtr());
0138     }
0139 
0140     SECTION("first(exception) | lastTask") {
0141       std::atomic<int> count{0};
0142 
0143       oneapi::tbb::task_group group;
0144       edm::FinalWaitingTask waitTask{group};
0145       {
0146         using namespace edm::waiting_task::chain;
0147         auto h = first([&count](edm::WaitingTaskHolder h) {
0148                    ++count;
0149                    REQUIRE(count.load() == 1);
0150                    throw std::exception();
0151                  }) |
0152                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0153 
0154         h.doneWaiting(std::exception_ptr());
0155       }
0156       waitTask.waitNoThrow();
0157       REQUIRE(count.load() == 1);
0158       REQUIRE(waitTask.done());
0159       REQUIRE(waitTask.exceptionPtr());
0160     }
0161 
0162     SECTION("first(exception) | then | then | lastTask") {
0163       std::atomic<int> count{0};
0164 
0165       oneapi::tbb::task_group group;
0166       edm::FinalWaitingTask waitTask{group};
0167       {
0168         using namespace edm::waiting_task::chain;
0169         auto h = first([&count](auto h) {
0170                    ++count;
0171                    REQUIRE(count.load() == 1);
0172                    throw std::exception();
0173                  }) |
0174                  then([&count](auto h) {
0175                    ++count;
0176                    REQUIRE(false);
0177                  }) |
0178                  then([&count](auto h) {
0179                    ++count;
0180                    REQUIRE(false);
0181                  }) |
0182                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0183 
0184         h.doneWaiting(std::exception_ptr());
0185       }
0186       waitTask.waitNoThrow();
0187       REQUIRE(count.load() == 1);
0188       REQUIRE(waitTask.done());
0189       REQUIRE(waitTask.exceptionPtr());
0190     }
0191   }
0192 
0193   SECTION("then with exception handler testing") {
0194     SECTION("first | lastTask") {
0195       std::atomic<int> count{0};
0196 
0197       oneapi::tbb::task_group group;
0198       edm::FinalWaitingTask waitTask{group};
0199       {
0200         using namespace edm::waiting_task::chain;
0201         auto h = first([&count](std::exception_ptr const* iPtr, edm::WaitingTaskHolder h) {
0202                    REQUIRE(iPtr == nullptr);
0203                    ++count;
0204                    REQUIRE(count.load() == 1);
0205                  }) |
0206                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0207 
0208         h.doneWaiting(std::exception_ptr());
0209       }
0210       waitTask.waitNoThrow();
0211       REQUIRE(count.load() == 1);
0212       REQUIRE(waitTask.done());
0213       REQUIRE(not waitTask.exceptionPtr());
0214     }
0215 
0216     SECTION("first | then | lastTask") {
0217       std::atomic<int> count{0};
0218 
0219       oneapi::tbb::task_group group;
0220       edm::FinalWaitingTask waitTask{group};
0221       {
0222         using namespace edm::waiting_task::chain;
0223         auto h = first([&count](std::exception_ptr const* iPtr, auto h) {
0224                    REQUIRE(iPtr == nullptr);
0225                    ++count;
0226                    REQUIRE(count.load() == 1);
0227                  }) |
0228                  then([&count](std::exception_ptr const* iPtr, auto h) {
0229                    REQUIRE(iPtr == nullptr);
0230                    ++count;
0231                    REQUIRE(count.load() == 2);
0232                  }) |
0233                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0234 
0235         h.doneWaiting(std::exception_ptr());
0236       }
0237       waitTask.waitNoThrow();
0238       REQUIRE(count.load() == 2);
0239       REQUIRE(waitTask.done());
0240       REQUIRE(not waitTask.exceptionPtr());
0241     }
0242 
0243     SECTION("first | then | then | lastTask") {
0244       std::atomic<int> count{0};
0245 
0246       oneapi::tbb::task_group group;
0247       edm::FinalWaitingTask waitTask{group};
0248       {
0249         using namespace edm::waiting_task::chain;
0250         auto h = first([&count](std::exception_ptr const* iPtr, auto h) {
0251                    REQUIRE(iPtr == nullptr);
0252                    ++count;
0253                    REQUIRE(count.load() == 1);
0254                  }) |
0255                  then([&count](std::exception_ptr const* iPtr, auto h) {
0256                    REQUIRE(iPtr == nullptr);
0257                    ++count;
0258                    REQUIRE(count.load() == 2);
0259                  }) |
0260                  then([&count](std::exception_ptr const* iPtr, auto h) {
0261                    REQUIRE(iPtr == nullptr);
0262                    ++count;
0263                    REQUIRE(count.load() == 3);
0264                  }) |
0265                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0266 
0267         h.doneWaiting(std::exception_ptr());
0268       }
0269       waitTask.waitNoThrow();
0270       REQUIRE(count.load() == 3);
0271       REQUIRE(waitTask.done());
0272       REQUIRE(not waitTask.exceptionPtr());
0273     }
0274 
0275     SECTION("exception -> first | lastTask") {
0276       std::atomic<int> count{0};
0277 
0278       oneapi::tbb::task_group group;
0279       edm::FinalWaitingTask waitTask{group};
0280       {
0281         using namespace edm::waiting_task::chain;
0282         auto h = first([&count](std::exception_ptr const* iPtr, edm::WaitingTaskHolder h) {
0283                    REQUIRE(iPtr != nullptr);
0284                    ++count;
0285                    REQUIRE(count.load() == 1);
0286                  }) |
0287                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0288 
0289         h.doneWaiting(std::make_exception_ptr(std::exception()));
0290       }
0291       waitTask.waitNoThrow();
0292       REQUIRE(count.load() == 1);
0293       REQUIRE(waitTask.done());
0294       REQUIRE(not waitTask.exceptionPtr());
0295     }
0296 
0297     SECTION("exception -> first | then | lastTask") {
0298       std::atomic<int> count{0};
0299 
0300       oneapi::tbb::task_group group;
0301       edm::FinalWaitingTask waitTask{group};
0302       {
0303         using namespace edm::waiting_task::chain;
0304         auto h = first([&count](std::exception_ptr const* iPtr, edm::WaitingTaskHolder h) {
0305                    REQUIRE(iPtr != nullptr);
0306                    ++count;
0307                    REQUIRE(count.load() == 1);
0308                    h.doneWaiting(*iPtr);
0309                  }) |
0310                  then([&count](std::exception_ptr const* iPtr, auto h) {
0311                    REQUIRE(iPtr != nullptr);
0312                    ++count;
0313                    REQUIRE(count.load() == 2);
0314                  }) |
0315                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0316 
0317         h.doneWaiting(std::make_exception_ptr(std::exception()));
0318       }
0319       waitTask.waitNoThrow();
0320       REQUIRE(count.load() == 2);
0321       REQUIRE(waitTask.done());
0322       REQUIRE(not waitTask.exceptionPtr());
0323     }
0324   }
0325 
0326   SECTION("ifException.else testing") {
0327     SECTION("first | lastTask") {
0328       std::atomic<int> count{0};
0329       std::atomic<int> exceptCount{0};
0330 
0331       oneapi::tbb::task_group group;
0332       edm::FinalWaitingTask waitTask{group};
0333       {
0334         using namespace edm::waiting_task::chain;
0335         auto h = first(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0336                          ++exceptCount;
0337                          REQUIRE(false);
0338                        }).else_([&count](edm::WaitingTaskHolder h) {
0339                    ++count;
0340                    REQUIRE(count.load() == 1);
0341                  })) |
0342                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0343 
0344         h.doneWaiting(std::exception_ptr());
0345       }
0346       waitTask.waitNoThrow();
0347       REQUIRE(exceptCount.load() == 0);
0348       REQUIRE(count.load() == 1);
0349       REQUIRE(waitTask.done());
0350       REQUIRE(not waitTask.exceptionPtr());
0351     }
0352 
0353     SECTION("first | then | lastTask") {
0354       std::atomic<int> count{0};
0355       std::atomic<int> exceptCount{0};
0356 
0357       oneapi::tbb::task_group group;
0358       edm::FinalWaitingTask waitTask{group};
0359       {
0360         using namespace edm::waiting_task::chain;
0361         auto h = first(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0362                          ++exceptCount;
0363                          REQUIRE(false);
0364                        }).else_([&count](auto h) {
0365                    ++count;
0366                    REQUIRE(count.load() == 1);
0367                  })) |
0368                  then(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0369                         ++exceptCount;
0370                         REQUIRE(false);
0371                       }).else_([&count](auto h) {
0372                    ++count;
0373                    REQUIRE(count.load() == 2);
0374                  })) |
0375                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0376 
0377         h.doneWaiting(std::exception_ptr());
0378       }
0379       waitTask.waitNoThrow();
0380       REQUIRE(exceptCount.load() == 0);
0381       REQUIRE(count.load() == 2);
0382       REQUIRE(waitTask.done());
0383       REQUIRE(not waitTask.exceptionPtr());
0384     }
0385 
0386     SECTION("first | then | then | lastTask") {
0387       std::atomic<int> count{0};
0388       std::atomic<int> exceptCount{0};
0389 
0390       oneapi::tbb::task_group group;
0391       edm::FinalWaitingTask waitTask{group};
0392       {
0393         using namespace edm::waiting_task::chain;
0394         auto h = first(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0395                          ++exceptCount;
0396                          REQUIRE(false);
0397                        }).else_([&count](auto h) {
0398                    ++count;
0399                    REQUIRE(count.load() == 1);
0400                  })) |
0401                  then(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0402                         ++exceptCount;
0403                         REQUIRE(false);
0404                       }).else_([&count](auto h) {
0405                    ++count;
0406                    REQUIRE(count.load() == 2);
0407                  })) |
0408                  then(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0409                         ++exceptCount;
0410                         REQUIRE(false);
0411                       }).else_([&count](auto h) {
0412                    ++count;
0413                    REQUIRE(count.load() == 3);
0414                  })) |
0415                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0416 
0417         h.doneWaiting(std::exception_ptr());
0418       }
0419       waitTask.waitNoThrow();
0420       REQUIRE(exceptCount.load() == 0);
0421       REQUIRE(count.load() == 3);
0422       REQUIRE(waitTask.done());
0423       REQUIRE(not waitTask.exceptionPtr());
0424     }
0425 
0426     SECTION("exception -> first | then | then | lastTask") {
0427       std::atomic<int> count{0};
0428       std::atomic<int> exceptCount{0};
0429 
0430       oneapi::tbb::task_group group;
0431       edm::FinalWaitingTask waitTask{group};
0432       {
0433         using namespace edm::waiting_task::chain;
0434         auto h = first(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0435                          ++exceptCount;
0436                          REQUIRE(exceptCount.load() == 1);
0437                        }).else_([&count](auto h) {
0438                    ++count;
0439                    REQUIRE(false);
0440                  })) |
0441                  then(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0442                         ++exceptCount;
0443                         REQUIRE(exceptCount.load() == 2);
0444                       }).else_([&count](auto h) {
0445                    ++count;
0446                    REQUIRE(false);
0447                  })) |
0448                  then(ifException([&exceptCount](std::exception_ptr const& iPtr) {
0449                         ++exceptCount;
0450                         REQUIRE(exceptCount.load() == 3);
0451                       }).else_([&count](auto h) {
0452                    ++count;
0453                    REQUIRE(false);
0454                  })) |
0455                  lastTask(edm::WaitingTaskHolder(group, &waitTask));
0456 
0457         h.doneWaiting(std::make_exception_ptr(std::exception()));
0458       }
0459       waitTask.waitNoThrow();
0460       REQUIRE(exceptCount.load() == 3);
0461       REQUIRE(count.load() == 0);
0462       REQUIRE(waitTask.done());
0463       REQUIRE(waitTask.exceptionPtr());
0464     }
0465   }
0466 
0467   SECTION("ifThen testing") {
0468     SECTION("first | ifThen(true) | then | runLast") {
0469       std::atomic<int> count{0};
0470 
0471       oneapi::tbb::task_group group;
0472       edm::FinalWaitingTask waitTask{group};
0473       {
0474         using namespace edm::waiting_task::chain;
0475         first([&count](auto h) {
0476           ++count;
0477           REQUIRE(count.load() == 1);
0478         }) | ifThen(true, [&count](auto h) {
0479           ++count;
0480           REQUIRE(count.load() == 2);
0481         }) | then([&count](auto h) {
0482           ++count;
0483           REQUIRE(count.load() == 3);
0484         }) | runLast(edm::WaitingTaskHolder(group, &waitTask));
0485       }
0486       waitTask.waitNoThrow();
0487       REQUIRE(count.load() == 3);
0488       REQUIRE(waitTask.done());
0489       REQUIRE(not waitTask.exceptionPtr());
0490     }
0491 
0492     SECTION("first | ifThen(false) | then | runLast") {
0493       std::atomic<int> count{0};
0494 
0495       oneapi::tbb::task_group group;
0496       edm::FinalWaitingTask waitTask{group};
0497       {
0498         using namespace edm::waiting_task::chain;
0499         first([&count](auto h) {
0500           ++count;
0501           REQUIRE(count.load() == 1);
0502         }) | ifThen(false, [&count](auto h) {
0503           ++count;
0504           REQUIRE(false);
0505         }) | then([&count](auto h) {
0506           ++count;
0507           REQUIRE(count.load() == 2);
0508         }) | runLast(edm::WaitingTaskHolder(group, &waitTask));
0509       }
0510       waitTask.waitNoThrow();
0511       REQUIRE(count.load() == 2);
0512       REQUIRE(waitTask.done());
0513       REQUIRE(not waitTask.exceptionPtr());
0514     }
0515   }
0516 }