diff --git a/arcane/src/arcane/accelerator/core/RunCommand.cc b/arcane/src/arcane/accelerator/core/RunCommand.cc index d741f9cdd..070170735 100644 --- a/arcane/src/arcane/accelerator/core/RunCommand.cc +++ b/arcane/src/arcane/accelerator/core/RunCommand.cc @@ -31,6 +31,7 @@ RunCommand:: RunCommand(const RunQueue& run_queue) : m_p(run_queue._getCommandImpl()) { + m_p->m_has_living_run_command = true; } /*---------------------------------------------------------------------------*/ @@ -39,6 +40,8 @@ RunCommand(const RunQueue& run_queue) RunCommand:: ~RunCommand() { + m_p->m_has_living_run_command = false; + m_p->_notifyDestroyRunCommand(); } /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/accelerator/core/RunCommand.h b/arcane/src/arcane/accelerator/core/RunCommand.h index 94dc18a59..4e70bea0d 100644 --- a/arcane/src/arcane/accelerator/core/RunCommand.h +++ b/arcane/src/arcane/accelerator/core/RunCommand.h @@ -57,8 +57,10 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunCommand public: + RunCommand(RunCommand&& command) = delete; RunCommand(const RunCommand&) = delete; RunCommand& operator=(const RunCommand&) = delete; + RunCommand& operator=(RunCommand&&) = delete; public: @@ -132,7 +134,6 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunCommand private: - //RunQueue m_run_queue; impl::RunCommandImpl* m_p; }; diff --git a/arcane/src/arcane/accelerator/core/RunCommandImpl.cc b/arcane/src/arcane/accelerator/core/RunCommandImpl.cc index 439daa5e7..e0e19b4b4 100644 --- a/arcane/src/arcane/accelerator/core/RunCommandImpl.cc +++ b/arcane/src/arcane/accelerator/core/RunCommandImpl.cc @@ -156,6 +156,7 @@ notifyEndLaunchKernel() // TODO: utiliser la bonne stream en séquentiel m_stop_event->recordQueue(stream); stream->notifyEndLaunchKernel(*this); + m_queue->_addRunningCommand(this); } /*---------------------------------------------------------------------------*/ @@ -221,6 +222,8 @@ _reset() m_loop_one_exec_stat.reset(); m_loop_one_exec_stat_ptr = nullptr; m_has_been_launched = false; + m_has_living_run_command = false; + m_may_be_put_in_pool = false; } /*---------------------------------------------------------------------------*/ @@ -288,6 +291,20 @@ _getOrCreateReduceMemoryImpl() return new ReduceMemoryImpl(this); } +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/*! + * \brief Méthode appelée quand l'instance RunCommand associée est détruite. + */ +void RunCommandImpl:: +_notifyDestroyRunCommand() +{ + // Si la commande n'a pas été lancé, il faut la remettre dans le pool + // des commandes de la file (sinon on aura une fuite mémoire) + if (!m_has_been_launched || m_may_be_put_in_pool) + m_queue->_putInCommandPool(this); +} + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/accelerator/core/RunQueue.cc b/arcane/src/arcane/accelerator/core/RunQueue.cc index 4376ba4dd..fd10dac76 100644 --- a/arcane/src/arcane/accelerator/core/RunQueue.cc +++ b/arcane/src/arcane/accelerator/core/RunQueue.cc @@ -361,6 +361,29 @@ memoryRessource() const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +void RunQueue:: +setConcurrentCommandCreation(bool v) +{ + _checkNotNull(); + if (isAcceleratorPolicy()) + ARCANE_FATAL("setting concurrent command creation is not supported for RunQueue running on accelerator"); + m_p->setConcurrentCommandCreation(v); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool RunQueue:: +isConcurrentCommandCreation() const +{ + if (m_p) + return m_p->isConcurrentCommandCreation(); + return false; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + extern "C++" ePointerAccessibility getPointerAccessibility(RunQueue* queue, const void* ptr, PointerAttribute* ptr_attr) { diff --git a/arcane/src/arcane/accelerator/core/RunQueue.h b/arcane/src/arcane/accelerator/core/RunQueue.h index 965365761..52954a7eb 100644 --- a/arcane/src/arcane/accelerator/core/RunQueue.h +++ b/arcane/src/arcane/accelerator/core/RunQueue.h @@ -192,6 +192,22 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunQueue eMemoryRessource memoryRessource() const; //!@} + public: + + /*! + * \brief Indique si on autorise la création de RunCommand pour cette instance + * depuis plusieurs threads. + * + * Cela nécessite d'utiliser un verrou (comme std::mutex) et peut dégrader les + * performances. Le défaut est \a false. + * + * Cette méthode n'est pas supportée pour les files qui sont associées + * à des accélérateurs (isAcceleratorPolicy()==true) + */ + void setConcurrentCommandCreation(bool v); + //! Indique si la création concurrente de plusieurs RunCommand est autorisée + bool isConcurrentCommandCreation() const; + public: /*! @@ -209,6 +225,10 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunQueue ARCANE_DEPRECATED_REASON("Y2024: Use toCudaNativeStream(), toHipNativeStream() or toSyclNativeStream() instead") void* platformStream() const; + public: + + impl::RunQueueImpl* _internalImpl() const; + private: // Les méthodes de création sont réservée à Runner. @@ -224,7 +244,6 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunQueue impl::IRunnerRuntime* _internalRuntime() const; impl::IRunQueueStream* _internalStream() const; impl::RunCommandImpl* _getCommandImpl() const; - impl::RunQueueImpl* _internalImpl() const; void _checkNotNull() const; // Pour VariableViewBase diff --git a/arcane/src/arcane/accelerator/core/RunQueueImpl.cc b/arcane/src/arcane/accelerator/core/RunQueueImpl.cc index 7f18fa078..582f7f8df 100644 --- a/arcane/src/arcane/accelerator/core/RunQueueImpl.cc +++ b/arcane/src/arcane/accelerator/core/RunQueueImpl.cc @@ -15,6 +15,7 @@ #include "arcane/utils/FatalErrorException.h" #include "arcane/utils/MemoryUtils.h" +#include "arcane/utils/SmallArray.h" #include "arcane/accelerator/core/internal/IRunnerRuntime.h" #include "arcane/accelerator/core/internal/IRunQueueStream.h" @@ -26,6 +27,8 @@ #include "arcane/accelerator/core/DeviceId.h" #include "arcane/accelerator/core/RunQueueEvent.h" +#include + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -35,6 +38,36 @@ namespace Arcane::Accelerator::impl /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +//! Verrou pour le pool de RunCommand en multi-thread. +class RunQueueImpl::Lock +{ + public: + + explicit Lock(RunQueueImpl* p) + { + if (p->m_use_pool_mutex) { + m_mutex = p->m_pool_mutex.get(); + if (m_mutex) { + m_mutex->lock(); + } + } + } + ~Lock() + { + if (m_mutex) + m_mutex->unlock(); + } + Lock(const Lock&) = delete; + Lock& operator=(const Lock&) = delete; + + private: + + std::mutex* m_mutex = nullptr; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + RunQueueImpl:: RunQueueImpl(RunnerImpl* runner_impl, Int32 id, const RunQueueBuildInfo& bi) : m_runner_impl(runner_impl) @@ -51,11 +84,40 @@ RunQueueImpl(RunnerImpl* runner_impl, Int32 id, const RunQueueBuildInfo& bi) RunQueueImpl:: ~RunQueueImpl() { + delete m_queue_stream; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void RunQueueImpl:: +_freeCommandsInPool() +{ + bool is_check = arcaneIsCheck(); + std::unordered_set command_set; while (!m_run_command_pool.empty()) { - RunCommand::_internalDestroyImpl(m_run_command_pool.top()); + RunCommandImpl* c = m_run_command_pool.top(); + if (is_check) { + if (command_set.find(c) != command_set.end()) + std::cerr << "Command is present several times in the command pool\n"; + command_set.insert(c); + } + RunCommand::_internalDestroyImpl(c); m_run_command_pool.pop(); } - delete m_queue_stream; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void RunQueueImpl:: +_destroy(RunQueueImpl* q) +{ + q->_freeCommandsInPool(); + delete q; } /*---------------------------------------------------------------------------*/ @@ -180,19 +242,19 @@ create(RunnerImpl* r, const RunQueueBuildInfo& bi) RunCommandImpl* RunQueueImpl:: _internalCreateOrGetRunCommandImpl() { - auto& pool = m_run_command_pool; RunCommandImpl* p = nullptr; - // TODO: rendre thread-safe - if (!pool.empty()) { - p = pool.top(); - pool.pop(); + { + auto& pool = m_run_command_pool; + Lock my_lock(this); + if (!pool.empty()) { + p = pool.top(); + pool.pop(); + } } - else { + if (!p) p = RunCommand::_internalCreateImpl(this); - } p->_reset(); - m_active_run_command_list.add(p); return p; } @@ -207,11 +269,75 @@ _internalCreateOrGetRunCommandImpl() void RunQueueImpl:: _internalFreeRunningCommands() { - for (RunCommandImpl* p : m_active_run_command_list) { - p->notifyEndExecuteKernel(); - m_run_command_pool.push(p); + SmallArray command_list; + if (m_use_pool_mutex) { + // Recopie les commandes dans un tableau local car m_active_run_command_list + // peut être modifié par un autre thread. + { + Lock my_lock(this); + for (RunCommandImpl* p : m_active_run_command_list) { + command_list.add(p); + } + m_active_run_command_list.clear(); + } + for (RunCommandImpl* p : command_list) { + p->notifyEndExecuteKernel(); + } + { + Lock my_lock(this); + for (RunCommandImpl* p : command_list) { + _checkPutCommandInPoolNoLock(p); + } + } } - m_active_run_command_list.clear(); + else { + for (RunCommandImpl* p : m_active_run_command_list) { + p->notifyEndExecuteKernel(); + _checkPutCommandInPoolNoLock(p); + } + m_active_run_command_list.clear(); + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/*! + * \brief Remet la commande dans le pool si possible. + * + * On ne remet pas la commande dans le pool tant qu'il y a une RunCommand + * qui y fait référence. Dans ce cas la commande sera remise dans le pool + * lors de l'appel au destructeur de RunCommand. Cela est nécessaire pour + * gérer le cas où une RunCommand est créée mais n'est jamais utilisée car + * dans ce cas elle ne sera jamais dans m_active_run_command_list et ne + * sera pas traitée lors de l'appel à _internalFreeRunningCommands(). + */ +void RunQueueImpl:: +_checkPutCommandInPoolNoLock(RunCommandImpl* p) +{ + if (p->m_has_living_run_command) + p->m_may_be_put_in_pool = true; + else + m_run_command_pool.push(p); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void RunQueueImpl:: +_addRunningCommand(RunCommandImpl* p) +{ + Lock my_lock(this); + m_active_run_command_list.add(p); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void RunQueueImpl:: +_putInCommandPool(RunCommandImpl* p) +{ + Lock my_lock(this); + m_run_command_pool.push(p); } /*---------------------------------------------------------------------------*/ @@ -246,6 +372,27 @@ _reset(RunQueueImpl* p) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +void RunQueueImpl:: +setConcurrentCommandCreation(bool v) +{ + m_use_pool_mutex = v; + if (!m_pool_mutex.get()) + m_pool_mutex = std::make_unique(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void RunQueueImpl:: +dumpStats(std::ostream& ostr) const +{ + ostr << "nb_pool=" << m_run_command_pool.size() + << " nb_active=" << m_active_run_command_list.size() << "\n"; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + } // namespace Arcane::Accelerator::impl /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/accelerator/core/Runner.cc b/arcane/src/arcane/accelerator/core/Runner.cc index e35250bf6..fd541c62d 100644 --- a/arcane/src/arcane/accelerator/core/Runner.cc +++ b/arcane/src/arcane/accelerator/core/Runner.cc @@ -141,7 +141,8 @@ _freePool() { RunQueueImplStack& s = m_run_queue_pool; while (!s.empty()) { - delete s.top(); + RunQueueImpl* q = s.top(); + RunQueueImpl::_destroy(q); s.pop(); } } diff --git a/arcane/src/arcane/accelerator/core/internal/RunCommandImpl.h b/arcane/src/arcane/accelerator/core/internal/RunCommandImpl.h index 1ea547bdf..f1d0f9a16 100644 --- a/arcane/src/arcane/accelerator/core/internal/RunCommandImpl.h +++ b/arcane/src/arcane/accelerator/core/internal/RunCommandImpl.h @@ -120,12 +120,19 @@ class RunCommandImpl */ bool m_is_allow_reuse_command = false; + //! Indique si une RunCommand a une référence sur cette instance. + bool m_has_living_run_command = false; + + //! Indique si on peut remettre la commande dans le pool associé à la RunQueue. + bool m_may_be_put_in_pool = false; + private: void _freePools(); void _reset(); void _init(); IRunQueueEventImpl* _createEvent(); + void _notifyDestroyRunCommand(); }; /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/accelerator/core/internal/RunQueueImpl.h b/arcane/src/arcane/accelerator/core/internal/RunQueueImpl.h index d62311e9e..a9b9f3b7e 100644 --- a/arcane/src/arcane/accelerator/core/internal/RunQueueImpl.h +++ b/arcane/src/arcane/accelerator/core/internal/RunQueueImpl.h @@ -21,6 +21,7 @@ #include #include +#include /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -45,12 +46,15 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunQueueImpl friend class RunQueueImplStack; friend class RunnerImpl; + class Lock; + private: RunQueueImpl(RunnerImpl* runner_impl, Int32 id, const RunQueueBuildInfo& bi); - public: + private: + // Il faut utiliser _destroy() pour détruire l'instance. ~RunQueueImpl(); public: @@ -78,6 +82,11 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunQueueImpl void recordEvent(RunQueueEvent& event); void waitEvent(RunQueueEvent& event); + void setConcurrentCommandCreation(bool v); + bool isConcurrentCommandCreation() const { return m_use_pool_mutex; } + + void dumpStats(std::ostream& ostr) const; + public: void addRef() @@ -101,7 +110,12 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunQueueImpl bool _isInPool() const { return m_is_in_pool; } void _release(); void _setDefaultMemoryRessource(); + void _addRunningCommand(RunCommandImpl* p); + void _putInCommandPool(RunCommandImpl* p); + void _freeCommandsInPool(); + void _checkPutCommandInPoolNoLock(RunCommandImpl* p); static RunQueueImpl* _reset(RunQueueImpl* p); + static void _destroy(RunQueueImpl* q); private: @@ -123,6 +137,10 @@ class ARCANE_ACCELERATOR_CORE_EXPORT RunQueueImpl bool m_is_async = false; //! Ressource mémoire par défaut eMemoryRessource m_memory_ressource = eMemoryRessource::Unknown; + + // Mutex pour les commandes (actif si \a m_use_pool_mutex est vrai) + std::unique_ptr m_pool_mutex; + bool m_use_pool_mutex = false; }; /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index 1095d32c9..335f5c15f 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -296,6 +296,15 @@ file(COPY ${TEST_PATH}/data/test_output_continue_hydro3_cartesian_small_4shm # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- +macro(arcane_add_accelerator_test_all_policies TEST_NAME CASE_FILE) + arcane_add_test_sequential(${TEST_NAME} ${CASE_FILE} ${ARGN}) + arcane_add_test_sequential_task(${TEST_NAME} ${CASE_FILE} 4 ${ARGN}) + arcane_add_accelerator_test_sequential(${TEST_NAME} ${CASE_FILE} ${ARGN}) +endmacro() + +# ---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- + message(STATUS "ADD AUTOMATED TESTS") ARCANE_ADD_TEST_SEQUENTIAL(utils1 testUtils-1.arc) ARCANE_ADD_TEST_SEQUENTIAL(json1 testJSON-1.arc) @@ -365,12 +374,13 @@ add_test(dump_database ${ARCANE_TEST_DRIVER} launch -We,STDENV_CODE_NAME,Arcane # ---------------------------------------------------------------------------- if (ARCANE_HAS_ACCELERATOR_API) - arcane_add_test_sequential(standalone_accelerator_testsum dummy.arc "-A,StandaloneAcceleratorMethod=TestSum") - arcane_add_test_sequential(standalone_accelerator_testbinop dummy.arc "-A,StandaloneAcceleratorMethod=TestBinOp") - arcane_add_accelerator_test_sequential(standalone_accelerator_testsum dummy.arc "-A,StandaloneAcceleratorMethod=TestSum") + arcane_add_accelerator_test_all_policies(standalone_accelerator_testsum dummy.arc "-A,StandaloneAcceleratorMethod=TestSum") + arcane_add_accelerator_test_all_policies(standalone_accelerator_testbinop dummy.arc "-A,StandaloneAcceleratorMethod=TestBinOp") + # arcane_add_accelerator_test_sequential(standalone_accelerator_testsum dummy.arc "-A,StandaloneAcceleratorMethod=TestSum") + #arcane_add_accelerator_test_sequential(standalone_accelerator_testbinop dummy.arc "-A,StandaloneAcceleratorMethod=TestBinOp") + #arcane_add_accelerator_test_sequential(standalone_accelerator_testemptykernel dummy.arc "-A,StandaloneAcceleratorMethod=TestEmptyKernel") + arcane_add_accelerator_test_all_policies(standalone_accelerator_testemptykernel dummy.arc "-A,StandaloneAcceleratorMethod=TestEmptyKernel") arcane_add_accelerator_test_sequential(standalone_accelerator_testsum_hostpinned dummy.arc "-A,StandaloneAcceleratorMethod=TestSum" "-We,ARCANE_DEFAULT_DATA_MEMORY_RESOURCE,HostPinned") - arcane_add_accelerator_test_sequential(standalone_accelerator_testbinop dummy.arc "-A,StandaloneAcceleratorMethod=TestBinOp") - arcane_add_accelerator_test_sequential(standalone_accelerator_testemptykernel dummy.arc "-A,StandaloneAcceleratorMethod=TestEmptyKernel") endif() arcane_add_test_sequential(standalone_subdomain1 dummy.arc "-A,StandaloneSubDomainMethod=Test1") @@ -781,12 +791,6 @@ if (HDF5_FOUND) ARCANE_ADD_TEST_PARALLEL(hydro1_checkpoint_3proc_rep4 testHydro-1-checkpoint.arc 12 -c 2 -m 25 -R 4) endif() -macro(arcane_add_accelerator_test_all_policies TEST_NAME CASE_FILE) - arcane_add_test_sequential(${TEST_NAME} ${CASE_FILE}) - arcane_add_test_sequential_task(${TEST_NAME} ${CASE_FILE} 4) - arcane_add_accelerator_test_sequential(${TEST_NAME} ${CASE_FILE}) -endmacro() - if (ARCANE_HAS_ACCELERATOR_API) arcane_add_test_sequential(numarray1 testNumArray-1.arc) arcane_add_test_sequential_task(numarray1 testNumArray-1.arc 4) diff --git a/arcane/src/arcane/tests/accelerator/ArcaneTestStandaloneAcceleratorMng.cc b/arcane/src/arcane/tests/accelerator/ArcaneTestStandaloneAcceleratorMng.cc index 3d05ea869..8f2ae7e62 100644 --- a/arcane/src/arcane/tests/accelerator/ArcaneTestStandaloneAcceleratorMng.cc +++ b/arcane/src/arcane/tests/accelerator/ArcaneTestStandaloneAcceleratorMng.cc @@ -18,6 +18,7 @@ #include "arcane/accelerator/core/RunQueue.h" #include "arcane/accelerator/core/Runner.h" #include "arcane/accelerator/core/DeviceMemoryInfo.h" +#include "arcane/accelerator/core/internal/RunQueueImpl.h" #include "arcane/accelerator/NumArrayViews.h" #include "arcane/accelerator/RunCommandLoop.h" @@ -163,23 +164,59 @@ void _testBinOp(IAcceleratorMng* acc_mng) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -void _testEmptyKernel(IAcceleratorMng* acc_mng) +RunQueue* +_testEmptyKernelHelper(IAcceleratorMng* acc_mng, bool use_async, bool use_concurrent, bool use_no_launch_command) { // Lance un kernel vide pour évaluer le coup du lancement. - int nb_value = 2000; int nb_iteration = 10000; - auto queue = Accelerator::makeQueue(acc_mng->defaultRunner()); - queue.setAsync(true); + auto queue = makeQueue(acc_mng->defaultRunner()); + RunQueue* q2 = new RunQueue(queue); + if (use_async) + queue.setAsync(true); + if (use_concurrent) + queue.setConcurrentCommandCreation(use_concurrent); Int64 xbegin = platform::getRealTimeNS(); for (int i = 0; i < nb_iteration; ++i) { auto command = makeCommand(queue); - command << RUNCOMMAND_LOOP1(, nb_value){}; + if (!use_no_launch_command) + command << RUNCOMMAND_SINGLE(){}; } Int64 xend = platform::getRealTimeNS(); queue.barrier(); Int64 xend2 = platform::getRealTimeNS(); - std::cout << "Time1 = " << (xend - xbegin) / nb_iteration << " Time2=" << (xend2 - xbegin) / nb_iteration << "\n"; + std::cout << "Time " + << (use_async ? "ASYNC " : "SYNC ") + << (use_concurrent ? " CONCURRENT " : " ") + << (use_no_launch_command ? " NOLAUNCH " : " LAUNCH "); + + std::cout << "Time1 (us) = " << std::setw(6) << (xend - xbegin) / 1000 << " Time2=" << std::setw(6) << (xend2 - xbegin) / 1000; + std::cout << " Time1/Iter (ns) = " << std::setw(6) << (xend - xbegin) / nb_iteration << " Time2=" << std::setw(6) << (xend2 - xbegin) / nb_iteration; + std::cout << "\n"; + queue._internalImpl()->dumpStats(std::cout); + std::cout << "\n"; + return q2; +} + +void _testEmptyKernel(IAcceleratorMng* acc_mng) +{ + // On garde les références sur les files créées pour ne pas les + // réutiliser. Cela permet d'avoir des mesures fiables sur les temps. + Runner runner = acc_mng->runner(); + UniqueArray queues; + queues.reserve(8); + queues.add(_testEmptyKernelHelper(acc_mng, false, false, false)); + queues.add(_testEmptyKernelHelper(acc_mng, false, false, true)); + queues.add(_testEmptyKernelHelper(acc_mng, true, false, false)); + queues.add(_testEmptyKernelHelper(acc_mng, true, false, true)); + if (!isAcceleratorPolicy(runner.executionPolicy())) { + queues.add(_testEmptyKernelHelper(acc_mng, false, true, false)); + queues.add(_testEmptyKernelHelper(acc_mng, false, true, true)); + queues.add(_testEmptyKernelHelper(acc_mng, true, true, false)); + queues.add(_testEmptyKernelHelper(acc_mng, true, true, true)); + } + for (RunQueue* q : queues) + delete q; } /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/tests/accelerator/MeshMaterialAcceleratorUnitTest.cc b/arcane/src/arcane/tests/accelerator/MeshMaterialAcceleratorUnitTest.cc index be48d5a82..3c1461013 100644 --- a/arcane/src/arcane/tests/accelerator/MeshMaterialAcceleratorUnitTest.cc +++ b/arcane/src/arcane/tests/accelerator/MeshMaterialAcceleratorUnitTest.cc @@ -93,7 +93,7 @@ class MeshMaterialAcceleratorUnitTest private: - ax::Runner* m_runner = nullptr; + ax::Runner m_runner; IMeshMaterialMng* m_mm_mng; IMeshEnvironment* m_env1; @@ -131,7 +131,7 @@ class MeshMaterialAcceleratorUnitTest void _executeTest4(Integer nb_z, bool use_new_impl); void _executeTest5(Integer nb_z, MatCellVectorView mat); void _executeTest6(); - void _executeTest7(); + void _executeTest7(RunQueue& queue); void _checkEnvValues1(); void _checkMatValues1(); void _checkEnvironmentValues(); @@ -181,8 +181,7 @@ MeshMaterialAcceleratorUnitTest:: void MeshMaterialAcceleratorUnitTest:: initializeTest() { - m_runner = subDomain()->acceleratorMng()->defaultRunner(); - + m_runner = subDomain()->acceleratorMng()->runner(); m_mm_mng = IMeshMaterialMng::getReference(mesh()); // Lit les infos des matériaux du JDD et les enregistre dans le gestionnaire @@ -349,7 +348,25 @@ executeTest() } { _executeTest6(); - _executeTest7(); + } + { + RunQueue queue = makeQueue(m_runner); + if (!queue.isAcceleratorPolicy()) { + // Le mode concurrent n'est pas supporté avec les accélérateurs + // (uniquement le multi-threading ou le séquentiel) + queue.setConcurrentCommandCreation(true); + if (!queue.isConcurrentCommandCreation()) + ARCANE_FATAL("Can not create concurrent commands"); + // Teste l'exécution multhread de la création de MatCellVector/EnvCellVector + ParallelLoopOptions loop_options; + loop_options.setGrainSize(1); + arcaneParallelFor(1, 20, loop_options, + [&](Integer a, Integer n) { + for (Int32 i = a; i < (a + n); ++i) + _executeTest7(queue); + }); + } + _executeTest7(queue); } } @@ -925,12 +942,10 @@ _executeTest6() * \brief Tests passages CellVector vers EnvCellVectorView ou MatCellVectorView */ void MeshMaterialAcceleratorUnitTest:: -_executeTest7() +_executeTest7(RunQueue& queue) { ValueChecker vc(A_FUNCINFO); - auto queue = makeQueue(m_runner); - // Créé un CellVector contenant une maille sur 2 IItemFamily* cell_family = mesh()->cellFamily(); const Int32 nb_cell_to_add = cell_family->maxLocalId() / 2;