1*74f7f6c6SJacob Faibussowitsch static const char help[] = "Tests PetscDeviceContextMarkIntentFromID().\n\n"; 2*74f7f6c6SJacob Faibussowitsch 3*74f7f6c6SJacob Faibussowitsch #include "petscdevicetestcommon.h" 4*74f7f6c6SJacob Faibussowitsch #include <petscviewer.h> 5*74f7f6c6SJacob Faibussowitsch 6*74f7f6c6SJacob Faibussowitsch #include <petsc/private/cpp/type_traits.hpp> 7*74f7f6c6SJacob Faibussowitsch #include <petsc/private/cpp/array.hpp> 8*74f7f6c6SJacob Faibussowitsch 9*74f7f6c6SJacob Faibussowitsch #include <cstdarg> // std::va_list 10*74f7f6c6SJacob Faibussowitsch #include <vector> // std:vector 11*74f7f6c6SJacob Faibussowitsch #include <unordered_map> // std::take_a_wild_guess 12*74f7f6c6SJacob Faibussowitsch #include <algorithm> // std::find 13*74f7f6c6SJacob Faibussowitsch #include <iterator> // std::distance, std::next 14*74f7f6c6SJacob Faibussowitsch 15*74f7f6c6SJacob Faibussowitsch struct Marker { 16*74f7f6c6SJacob Faibussowitsch PetscMemoryAccessMode mode{}; 17*74f7f6c6SJacob Faibussowitsch 18*74f7f6c6SJacob Faibussowitsch PETSC_NODISCARD PetscErrorCode operator()(PetscDeviceContext dctx, PetscContainer cont) const noexcept 19*74f7f6c6SJacob Faibussowitsch { 20*74f7f6c6SJacob Faibussowitsch const auto obj = reinterpret_cast<PetscObject>(cont); 21*74f7f6c6SJacob Faibussowitsch PetscObjectId id = 0; 22*74f7f6c6SJacob Faibussowitsch const char *name = nullptr; 23*74f7f6c6SJacob Faibussowitsch 24*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 25*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectGetId(obj, &id)); 26*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectGetName(obj, &name)); 27*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextMarkIntentFromID(dctx, id, this->mode, name)); 28*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 29*74f7f6c6SJacob Faibussowitsch } 30*74f7f6c6SJacob Faibussowitsch }; 31*74f7f6c6SJacob Faibussowitsch 32*74f7f6c6SJacob Faibussowitsch static constexpr auto read = Marker{PETSC_MEMORY_ACCESS_READ}; 33*74f7f6c6SJacob Faibussowitsch static constexpr auto write = Marker{PETSC_MEMORY_ACCESS_WRITE}; 34*74f7f6c6SJacob Faibussowitsch static constexpr auto read_write = Marker{PETSC_MEMORY_ACCESS_READ_WRITE}; 35*74f7f6c6SJacob Faibussowitsch static constexpr auto mark_funcs = Petsc::util::make_array(read, write, read_write); 36*74f7f6c6SJacob Faibussowitsch 37*74f7f6c6SJacob Faibussowitsch static PetscErrorCode MarkedObjectMapView(PetscViewer vwr, std::size_t nkeys, const PetscObjectId *keys, const PetscMemoryAccessMode *modes, const std::size_t *ndeps, const PetscEvent **dependencies) 38*74f7f6c6SJacob Faibussowitsch { 39*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 40*74f7f6c6SJacob Faibussowitsch if (!vwr) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &vwr)); 41*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerFlush(vwr)); 42*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushSynchronized(vwr)); 43*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIISynchronizedPrintf(vwr, "Marked Object Map:\n")); 44*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(vwr)); 45*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIISynchronizedPrintf(vwr, "size: %zu\n", nkeys)); 46*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIISynchronizedPrintf(vwr, "entries:\n")); 47*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(vwr)); 48*74f7f6c6SJacob Faibussowitsch for (std::size_t i = 0; i < nkeys; ++i) { 49*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIISynchronizedPrintf(vwr, "id %" PetscInt64_FMT " -> {\n", keys[i])); 50*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(vwr)); 51*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIISynchronizedPrintf(vwr, "mode: %s\n", PetscMemoryAccessModeToString(modes[i]))); 52*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIISynchronizedPrintf(vwr, "dependencies:\n")); 53*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(vwr)); 54*74f7f6c6SJacob Faibussowitsch for (std::size_t j = 0; j < ndeps[i]; ++j) { 55*74f7f6c6SJacob Faibussowitsch const auto event = dependencies[i][j]; 56*74f7f6c6SJacob Faibussowitsch 57*74f7f6c6SJacob Faibussowitsch PetscCall( 58*74f7f6c6SJacob Faibussowitsch PetscViewerASCIISynchronizedPrintf(vwr, "event %zu {dtype: %s, dctx_id: %" PetscInt64_FMT ", dctx_state: %" PetscInt64_FMT ", data: %p, destroy: %p}\n", j, PetscDeviceTypes[event->dtype], event->dctx_id, event->dctx_state, event->data, event->destroy)); 59*74f7f6c6SJacob Faibussowitsch } 60*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(vwr)); 61*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(vwr)); 62*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIISynchronizedPrintf(vwr, "}\n")); 63*74f7f6c6SJacob Faibussowitsch } 64*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(vwr)); 65*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(vwr)); 66*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerFlush(vwr)); 67*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIPopSynchronized(vwr)); 68*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 69*74f7f6c6SJacob Faibussowitsch } 70*74f7f6c6SJacob Faibussowitsch 71*74f7f6c6SJacob Faibussowitsch PETSC_ATTRIBUTE_FORMAT(10, 11) 72*74f7f6c6SJacob Faibussowitsch static PetscErrorCode CheckMarkedObjectMap_Private(PetscBool cond, const char cond_str[], MPI_Comm comm, PetscDeviceContext dctx, std::size_t nkeys, const PetscObjectId *keys, const PetscMemoryAccessMode *modes, const std::size_t *ndeps, const PetscEvent **dependencies, const char *format, ...) 73*74f7f6c6SJacob Faibussowitsch { 74*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 75*74f7f6c6SJacob Faibussowitsch if (PetscUnlikely(!cond)) { 76*74f7f6c6SJacob Faibussowitsch std::array<char, 2048> buf; 77*74f7f6c6SJacob Faibussowitsch std::va_list argp; 78*74f7f6c6SJacob Faibussowitsch std::size_t len; 79*74f7f6c6SJacob Faibussowitsch PetscViewer vwr; 80*74f7f6c6SJacob Faibussowitsch 81*74f7f6c6SJacob Faibussowitsch PetscCallCXX(buf.fill(0)); 82*74f7f6c6SJacob Faibussowitsch va_start(argp, format); 83*74f7f6c6SJacob Faibussowitsch PetscCall(PetscVSNPrintf(buf.data(), buf.size(), format, &len, argp)); 84*74f7f6c6SJacob Faibussowitsch va_end(argp); 85*74f7f6c6SJacob Faibussowitsch PetscCall(PetscViewerASCIIGetStdout(comm, &vwr)); 86*74f7f6c6SJacob Faibussowitsch if (dctx) PetscCall(PetscDeviceContextView(dctx, vwr)); 87*74f7f6c6SJacob Faibussowitsch PetscCall(MarkedObjectMapView(vwr, nkeys, keys, modes, ndeps, dependencies)); 88*74f7f6c6SJacob Faibussowitsch SETERRQ(comm, PETSC_ERR_PLIB, "Condition '%s' failed, marked object map in corrupt state: %s", cond_str, buf.data()); 89*74f7f6c6SJacob Faibussowitsch } 90*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 91*74f7f6c6SJacob Faibussowitsch } 92*74f7f6c6SJacob Faibussowitsch #define CheckMarkedObjectMap(__cond__, ...) CheckMarkedObjectMap_Private((PetscBool)(!!(__cond__)), PetscStringize(__cond__), PETSC_COMM_SELF, dctx, nkeys, keys, modes, ndeps, const_cast<const PetscEvent **>(dependencies), __VA_ARGS__); 93*74f7f6c6SJacob Faibussowitsch 94*74f7f6c6SJacob Faibussowitsch static PetscErrorCode TestAllCombinations(PetscDeviceContext dctx, const std::vector<PetscContainer> &cont) 95*74f7f6c6SJacob Faibussowitsch { 96*74f7f6c6SJacob Faibussowitsch std::vector<PetscObjectId> cont_ids; 97*74f7f6c6SJacob Faibussowitsch PetscObjectId dctx_id; 98*74f7f6c6SJacob Faibussowitsch PetscDeviceType dtype; 99*74f7f6c6SJacob Faibussowitsch 100*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 101*74f7f6c6SJacob Faibussowitsch PetscCallCXX(cont_ids.reserve(cont.size())); 102*74f7f6c6SJacob Faibussowitsch for (auto &&c : cont) { 103*74f7f6c6SJacob Faibussowitsch PetscObjectId id; 104*74f7f6c6SJacob Faibussowitsch 105*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)c, &id)); 106*74f7f6c6SJacob Faibussowitsch PetscCallCXX(cont_ids.emplace_back(id)); 107*74f7f6c6SJacob Faibussowitsch } 108*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectGetId(PetscObjectCast(dctx), &dctx_id)); 109*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 110*74f7f6c6SJacob Faibussowitsch for (auto &&func_i : mark_funcs) { 111*74f7f6c6SJacob Faibussowitsch for (auto &&func_j : mark_funcs) { 112*74f7f6c6SJacob Faibussowitsch for (auto it = cont.cbegin(), next = std::next(it); it != cont.cend(); ++it, ++next) { 113*74f7f6c6SJacob Faibussowitsch std::vector<int> found_keys; 114*74f7f6c6SJacob Faibussowitsch std::size_t nkeys; 115*74f7f6c6SJacob Faibussowitsch PetscObjectId *keys; 116*74f7f6c6SJacob Faibussowitsch PetscMemoryAccessMode *modes; 117*74f7f6c6SJacob Faibussowitsch std::size_t *ndeps; 118*74f7f6c6SJacob Faibussowitsch PetscEvent **dependencies; 119*74f7f6c6SJacob Faibussowitsch 120*74f7f6c6SJacob Faibussowitsch if (next >= cont.cend()) next = cont.cbegin(); 121*74f7f6c6SJacob Faibussowitsch PetscCall(func_i(dctx, *it)); 122*74f7f6c6SJacob Faibussowitsch PetscCall(func_j(dctx, *next)); 123*74f7f6c6SJacob Faibussowitsch PetscCall(PetscGetMarkedObjectMap_Internal(&nkeys, &keys, &modes, &ndeps, &dependencies)); 124*74f7f6c6SJacob Faibussowitsch PetscCallCXX(found_keys.resize(nkeys)); 125*74f7f6c6SJacob Faibussowitsch { 126*74f7f6c6SJacob Faibussowitsch // The underlying marked object map is *unordered*, and hence the order in which we 127*74f7f6c6SJacob Faibussowitsch // get the keys is not necessarily the same as the order of operations. This is 128*74f7f6c6SJacob Faibussowitsch // confounded by the fact that k and knext are not necessarily "linear", i.e. k could 129*74f7f6c6SJacob Faibussowitsch // be 2 while knext is 0. So we need to map these back to linear space so we can loop 130*74f7f6c6SJacob Faibussowitsch // over them. 131*74f7f6c6SJacob Faibussowitsch const auto keys_end = keys + nkeys; 132*74f7f6c6SJacob Faibussowitsch const auto num_expected_keys = std::min(cont.size(), static_cast<std::size_t>(2)); 133*74f7f6c6SJacob Faibussowitsch const auto check_applied_mode = [&](PetscContainer container, PetscMemoryAccessMode mode) { 134*74f7f6c6SJacob Faibussowitsch std::ptrdiff_t key_idx = 0; 135*74f7f6c6SJacob Faibussowitsch PetscObjectId actual_key; 136*74f7f6c6SJacob Faibussowitsch 137*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 138*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)container, &actual_key)); 139*74f7f6c6SJacob Faibussowitsch // search the list of keys from the map for the selected key 140*74f7f6c6SJacob Faibussowitsch key_idx = std::distance(keys, std::find(keys, keys_end, actual_key)); 141*74f7f6c6SJacob Faibussowitsch PetscCheck(key_idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Key index %" PetscCount_FMT " < 0, this indicates keys_begin > keys_end?", key_idx); 142*74f7f6c6SJacob Faibussowitsch found_keys[key_idx]++; 143*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(key_idx < std::distance(keys, keys_end), "marked object map could not find expected key %" PetscInt64_FMT, actual_key)); 144*74f7f6c6SJacob Faibussowitsch // OK found it, now check the rest of the entries are as we expect them to be 145*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(modes[key_idx] == mode, "unexpected mode %s, expected %s", PetscMemoryAccessModeToString(modes[key_idx]), PetscMemoryAccessModeToString(mode))); 146*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(ndeps[key_idx] == 1, "unexpected number of dependencies %zu, expected 1", ndeps[key_idx])); 147*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(dependencies[key_idx][0]->dtype == dtype, "unexpected device type on event: %s, expected %s", PetscDeviceTypes[dependencies[key_idx][0]->dtype], PetscDeviceTypes[dtype])); 148*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 149*74f7f6c6SJacob Faibussowitsch }; 150*74f7f6c6SJacob Faibussowitsch 151*74f7f6c6SJacob Faibussowitsch // if it == next, then even though we might num_expected_keys keys we never "look 152*74f7f6c6SJacob Faibussowitsch // for" the missing key 153*74f7f6c6SJacob Faibussowitsch PetscCheck(cont.size() == 1 || it != next, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Test assumes different inputs, otherwise key check may fail"); 154*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(nkeys == num_expected_keys, "marked object map has %zu keys expected %zu", nkeys, num_expected_keys)); 155*74f7f6c6SJacob Faibussowitsch // check that each function properly applied its mode, it == next if cont.size() = 1, 156*74f7f6c6SJacob Faibussowitsch // i.e. testing identity 157*74f7f6c6SJacob Faibussowitsch if (it != next) PetscCall(check_applied_mode(*it, func_i.mode)); 158*74f7f6c6SJacob Faibussowitsch PetscCall(check_applied_mode(*next, func_j.mode)); 159*74f7f6c6SJacob Faibussowitsch } 160*74f7f6c6SJacob Faibussowitsch // Check that the map contained only keys we were looking for. Any extra keys will have 161*74f7f6c6SJacob Faibussowitsch // zero find count 162*74f7f6c6SJacob Faibussowitsch for (auto it = found_keys.cbegin(); it != found_keys.cend(); ++it) PetscCall(CheckMarkedObjectMap(*it > 0, "Marked Object Map has extra object entry: id %" PetscInt64_FMT, keys[std::distance(found_keys.cbegin(), it)])); 163*74f7f6c6SJacob Faibussowitsch 164*74f7f6c6SJacob Faibussowitsch PetscCall(PetscRestoreMarkedObjectMap_Internal(nkeys, &keys, &modes, &ndeps, &dependencies)); 165*74f7f6c6SJacob Faibussowitsch 166*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 167*74f7f6c6SJacob Faibussowitsch PetscCall(PetscGetMarkedObjectMap_Internal(&nkeys, &keys, &modes, &ndeps, &dependencies)); 168*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(nkeys == 0, "synchronizing device context did not empty dependency map, have %zu keys", nkeys)); 169*74f7f6c6SJacob Faibussowitsch PetscCall(PetscRestoreMarkedObjectMap_Internal(nkeys, &keys, &modes, &ndeps, &dependencies)); 170*74f7f6c6SJacob Faibussowitsch } 171*74f7f6c6SJacob Faibussowitsch } 172*74f7f6c6SJacob Faibussowitsch } 173*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 174*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 175*74f7f6c6SJacob Faibussowitsch } 176*74f7f6c6SJacob Faibussowitsch 177*74f7f6c6SJacob Faibussowitsch template <typename... T> 178*74f7f6c6SJacob Faibussowitsch PETSC_NODISCARD static std::pair<PetscObjectId, std::pair<PetscMemoryAccessMode, std::vector<PetscDeviceContext>>> make_map_entry(PetscObjectId id, PetscMemoryAccessMode mode, T &&...dctxs) 179*74f7f6c6SJacob Faibussowitsch { 180*74f7f6c6SJacob Faibussowitsch return { 181*74f7f6c6SJacob Faibussowitsch id, {mode, {std::forward<T>(dctxs)...}} 182*74f7f6c6SJacob Faibussowitsch }; 183*74f7f6c6SJacob Faibussowitsch } 184*74f7f6c6SJacob Faibussowitsch 185*74f7f6c6SJacob Faibussowitsch static PetscErrorCode CheckMapEqual(std::unordered_map<PetscObjectId, std::pair<PetscMemoryAccessMode, std::vector<PetscDeviceContext>>> expected_map) 186*74f7f6c6SJacob Faibussowitsch { 187*74f7f6c6SJacob Faibussowitsch std::size_t nkeys; 188*74f7f6c6SJacob Faibussowitsch PetscObjectId *keys; 189*74f7f6c6SJacob Faibussowitsch PetscMemoryAccessMode *modes; 190*74f7f6c6SJacob Faibussowitsch std::size_t *ndeps; 191*74f7f6c6SJacob Faibussowitsch PetscEvent **dependencies; 192*74f7f6c6SJacob Faibussowitsch PetscDeviceContext dctx = nullptr; 193*74f7f6c6SJacob Faibussowitsch 194*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 195*74f7f6c6SJacob Faibussowitsch PetscCall(PetscGetMarkedObjectMap_Internal(&nkeys, &keys, &modes, &ndeps, &dependencies)); 196*74f7f6c6SJacob Faibussowitsch { 197*74f7f6c6SJacob Faibussowitsch const auto key_end = keys + nkeys; 198*74f7f6c6SJacob Faibussowitsch auto mode_it = modes; 199*74f7f6c6SJacob Faibussowitsch auto ndep_it = ndeps; 200*74f7f6c6SJacob Faibussowitsch auto dep_it = dependencies; 201*74f7f6c6SJacob Faibussowitsch 202*74f7f6c6SJacob Faibussowitsch for (auto key_it = keys; key_it != key_end; ++key_it, ++mode_it, ++ndep_it, ++dep_it) { 203*74f7f6c6SJacob Faibussowitsch const auto found_it = expected_map.find(*key_it); 204*74f7f6c6SJacob Faibussowitsch 205*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(found_it != expected_map.cend(), "marked object map did not contain key %" PetscInt64_FMT, *key_it)); 206*74f7f6c6SJacob Faibussowitsch { 207*74f7f6c6SJacob Faibussowitsch // must do these here since found_it may be expected_map.cend() 208*74f7f6c6SJacob Faibussowitsch const auto &expected_mode = found_it->second.first; 209*74f7f6c6SJacob Faibussowitsch const auto &expected_dctxs = found_it->second.second; 210*74f7f6c6SJacob Faibussowitsch auto sub_dep_it = *dep_it; 211*74f7f6c6SJacob Faibussowitsch 212*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(expected_mode == *mode_it, "unexpected mode %s, expected %s", PetscMemoryAccessModeToString(expected_mode), PetscMemoryAccessModeToString(*mode_it))); 213*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(expected_dctxs.size() == *ndep_it, "unexpected number of dependencies %zu, expected %zu", *ndep_it, expected_dctxs.size())); 214*74f7f6c6SJacob Faibussowitsch // purposefully hide "dctx" with the loop variable, so we get more detailed output in 215*74f7f6c6SJacob Faibussowitsch // the error message 216*74f7f6c6SJacob Faibussowitsch for (auto &&dctx : expected_dctxs) { 217*74f7f6c6SJacob Faibussowitsch const auto event = *sub_dep_it; 218*74f7f6c6SJacob Faibussowitsch PetscDeviceType dtype; 219*74f7f6c6SJacob Faibussowitsch PetscObjectId id; 220*74f7f6c6SJacob Faibussowitsch 221*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 222*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectGetId(PetscObjectCast(dctx), &id)); 223*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(event->dtype == dtype, "unexpected device type on event: %s, expected %s", PetscDeviceTypes[event->dtype], PetscDeviceTypes[dtype])); 224*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(event->dctx_id == id, "unexpected dctx id on event: %" PetscInt64_FMT ", expected %" PetscInt64_FMT, event->dctx_id, id)); 225*74f7f6c6SJacob Faibussowitsch ++sub_dep_it; 226*74f7f6c6SJacob Faibussowitsch } 227*74f7f6c6SJacob Faibussowitsch } 228*74f7f6c6SJacob Faibussowitsch // remove the found iterator from the map, this ensure we either run out of map (which is 229*74f7f6c6SJacob Faibussowitsch // caught by the fisrt check in the loop), or we run out of keys to check, which is 230*74f7f6c6SJacob Faibussowitsch // caught in the end of the loop 231*74f7f6c6SJacob Faibussowitsch PetscCallCXX(expected_map.erase(found_it)); 232*74f7f6c6SJacob Faibussowitsch } 233*74f7f6c6SJacob Faibussowitsch } 234*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMarkedObjectMap(expected_map.empty(), "Not all keys in marked object map accounted for!")); 235*74f7f6c6SJacob Faibussowitsch PetscCall(PetscRestoreMarkedObjectMap_Internal(nkeys, &keys, &modes, &ndeps, &dependencies)); 236*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 237*74f7f6c6SJacob Faibussowitsch } 238*74f7f6c6SJacob Faibussowitsch 239*74f7f6c6SJacob Faibussowitsch int main(int argc, char *argv[]) 240*74f7f6c6SJacob Faibussowitsch { 241*74f7f6c6SJacob Faibussowitsch PetscContainer x, y, z; 242*74f7f6c6SJacob Faibussowitsch PetscObjectId x_id, y_id, z_id; 243*74f7f6c6SJacob Faibussowitsch PetscDeviceContext dctx_a, dctx_b, dctx_c; 244*74f7f6c6SJacob Faibussowitsch auto container_view = PETSC_FALSE; 245*74f7f6c6SJacob Faibussowitsch const auto create_container = [&](PetscContainer *c, const char name[], PetscObjectId *id) { 246*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 247*74f7f6c6SJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_WORLD, c)); 248*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)(*c), name)); 249*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)(*c), id)); 250*74f7f6c6SJacob Faibussowitsch if (container_view) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Container '%s' -> id %" PetscInt64_FMT "\n", name, *id)); 251*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 252*74f7f6c6SJacob Faibussowitsch }; 253*74f7f6c6SJacob Faibussowitsch const auto sync_all = [&] { 254*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 255*74f7f6c6SJacob Faibussowitsch for (auto &&ctx : {dctx_a, dctx_b, dctx_c}) PetscCall(PetscDeviceContextSynchronize(ctx)); 256*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 257*74f7f6c6SJacob Faibussowitsch }; 258*74f7f6c6SJacob Faibussowitsch 259*74f7f6c6SJacob Faibussowitsch PetscFunctionBeginUser; 260*74f7f6c6SJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, nullptr, help)); 261*74f7f6c6SJacob Faibussowitsch 262*74f7f6c6SJacob Faibussowitsch PetscOptionsBegin(PETSC_COMM_WORLD, nullptr, "Test Options", "Sys"); 263*74f7f6c6SJacob Faibussowitsch PetscCall(PetscOptionsBool("-container_view", "View container names and ID's", nullptr, container_view, &container_view, nullptr)); 264*74f7f6c6SJacob Faibussowitsch PetscOptionsEnd(); 265*74f7f6c6SJacob Faibussowitsch 266*74f7f6c6SJacob Faibussowitsch PetscCall(create_container(&x, "x", &x_id)); 267*74f7f6c6SJacob Faibussowitsch PetscCall(create_container(&y, "y", &y_id)); 268*74f7f6c6SJacob Faibussowitsch PetscCall(create_container(&z, "z", &z_id)); 269*74f7f6c6SJacob Faibussowitsch 270*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextCreate(&dctx_a)); 271*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectSetName(PetscObjectCast(dctx_a), "dctx_a")); 272*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSetStreamType(dctx_a, PETSC_STREAM_DEFAULT_BLOCKING)); 273*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSetFromOptions(PETSC_COMM_WORLD, dctx_a)); 274*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate(dctx_a, &dctx_b)); 275*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectSetName(PetscObjectCast(dctx_b), "dctx_b")); 276*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextDuplicate(dctx_a, &dctx_c)); 277*74f7f6c6SJacob Faibussowitsch PetscCall(PetscObjectSetName(PetscObjectCast(dctx_c), "dctx_c")); 278*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextViewFromOptions(dctx_a, nullptr, "-dctx_a_view")); 279*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextViewFromOptions(dctx_b, nullptr, "-dctx_b_view")); 280*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextViewFromOptions(dctx_c, nullptr, "-dctx_c_view")); 281*74f7f6c6SJacob Faibussowitsch 282*74f7f6c6SJacob Faibussowitsch // ensure they are all idle 283*74f7f6c6SJacob Faibussowitsch PetscCall(sync_all()); 284*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 285*74f7f6c6SJacob Faibussowitsch 286*74f7f6c6SJacob Faibussowitsch // do the bulk combination tests, these test only the very basic combinations for simple 287*74f7f6c6SJacob Faibussowitsch // correctness 288*74f7f6c6SJacob Faibussowitsch PetscCall(TestAllCombinations(dctx_a, {x})); 289*74f7f6c6SJacob Faibussowitsch PetscCall(TestAllCombinations(dctx_a, {x, y, z})); 290*74f7f6c6SJacob Faibussowitsch 291*74f7f6c6SJacob Faibussowitsch // Now do some specific tests, these should test more complicated scenarios. First and 292*74f7f6c6SJacob Faibussowitsch // foremost, ensure they are all idle, and that it does not change the map 293*74f7f6c6SJacob Faibussowitsch PetscCall(sync_all()); 294*74f7f6c6SJacob Faibussowitsch // Map should be empty 295*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 296*74f7f6c6SJacob Faibussowitsch 297*74f7f6c6SJacob Faibussowitsch // Syncing again shouldn't magically fill the map back up 298*74f7f6c6SJacob Faibussowitsch PetscCall(sync_all()); 299*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 300*74f7f6c6SJacob Faibussowitsch 301*74f7f6c6SJacob Faibussowitsch const auto test_multiple_readers = [&](std::array<PetscDeviceContext, 2> readers, std::size_t sync_idx) { 302*74f7f6c6SJacob Faibussowitsch // the reader which synchronizes 303*74f7f6c6SJacob Faibussowitsch const auto sync_reader = readers[sync_idx]; 304*74f7f6c6SJacob Faibussowitsch // the reader that will remain in the map after sync_reader synchronizes 305*74f7f6c6SJacob Faibussowitsch const auto remain_idx = sync_idx + 1 >= readers.size() ? 0 : sync_idx + 1; 306*74f7f6c6SJacob Faibussowitsch const auto remain_reader = readers[remain_idx]; 307*74f7f6c6SJacob Faibussowitsch 308*74f7f6c6SJacob Faibussowitsch PetscFunctionBegin; 309*74f7f6c6SJacob Faibussowitsch for (auto &&ctx : readers) PetscCall(read(ctx, x)); 310*74f7f6c6SJacob Faibussowitsch for (auto &&ctx : readers) PetscCall(read(ctx, y)); 311*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({ 312*74f7f6c6SJacob Faibussowitsch make_map_entry(x_id, PETSC_MEMORY_ACCESS_READ, readers[0], readers[1]), 313*74f7f6c6SJacob Faibussowitsch make_map_entry(y_id, PETSC_MEMORY_ACCESS_READ, readers[0], readers[1]), 314*74f7f6c6SJacob Faibussowitsch })); 315*74f7f6c6SJacob Faibussowitsch // synchronizing sync_reader should remove it from the dependency list -- but leave remain_reader 316*74f7f6c6SJacob Faibussowitsch // intact 317*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(sync_reader)); 318*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({ 319*74f7f6c6SJacob Faibussowitsch make_map_entry(x_id, PETSC_MEMORY_ACCESS_READ, remain_reader), 320*74f7f6c6SJacob Faibussowitsch make_map_entry(y_id, PETSC_MEMORY_ACCESS_READ, remain_reader), 321*74f7f6c6SJacob Faibussowitsch })); 322*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(remain_reader)); 323*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 324*74f7f6c6SJacob Faibussowitsch PetscFunctionReturn(0); 325*74f7f6c6SJacob Faibussowitsch }; 326*74f7f6c6SJacob Faibussowitsch 327*74f7f6c6SJacob Faibussowitsch // Test that multiple readers can simulatenously read -- even if one of them is synchronized 328*74f7f6c6SJacob Faibussowitsch PetscCall(test_multiple_readers({dctx_a, dctx_b}, 0)); 329*74f7f6c6SJacob Faibussowitsch PetscCall(test_multiple_readers({dctx_a, dctx_b}, 1)); 330*74f7f6c6SJacob Faibussowitsch 331*74f7f6c6SJacob Faibussowitsch // Test that sync of unrelated ctx does not affect the map 332*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_a, x)); 333*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_b, y)); 334*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_c)); 335*74f7f6c6SJacob Faibussowitsch // clang-format off 336*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({ 337*74f7f6c6SJacob Faibussowitsch make_map_entry(x_id, PETSC_MEMORY_ACCESS_READ, dctx_a), 338*74f7f6c6SJacob Faibussowitsch make_map_entry(y_id, PETSC_MEMORY_ACCESS_READ, dctx_b) 339*74f7f6c6SJacob Faibussowitsch })); 340*74f7f6c6SJacob Faibussowitsch // clang-format on 341*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_a)); 342*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_b)); 343*74f7f6c6SJacob Faibussowitsch // Now the map is empty again 344*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 345*74f7f6c6SJacob Faibussowitsch 346*74f7f6c6SJacob Faibussowitsch // Test another context writing over two reads 347*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_a, x)); 348*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_b, x)); 349*74f7f6c6SJacob Faibussowitsch // C writing should kick out both A and B 350*74f7f6c6SJacob Faibussowitsch PetscCall(write(dctx_c, x)); 351*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({make_map_entry(x_id, PETSC_MEMORY_ACCESS_WRITE, dctx_c)})); 352*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_c)); 353*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 354*74f7f6c6SJacob Faibussowitsch 355*74f7f6c6SJacob Faibussowitsch // Test that write and synchronize does not interfere with unrelated read 356*74f7f6c6SJacob Faibussowitsch PetscCall(read_write(dctx_a, x)); 357*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_a, y)); 358*74f7f6c6SJacob Faibussowitsch PetscCall(read_write(dctx_b, x)); 359*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_b, y)); 360*74f7f6c6SJacob Faibussowitsch // Synchronizing B here must clear everything *but* A's read on Y! 361*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_b)); 362*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({make_map_entry(y_id, PETSC_MEMORY_ACCESS_READ, dctx_a)})); 363*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_a)); 364*74f7f6c6SJacob Faibussowitsch // Now the map is empty again 365*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 366*74f7f6c6SJacob Faibussowitsch 367*74f7f6c6SJacob Faibussowitsch // Test that implicit stream-dependencies are properly tracked 368*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_a, x)); 369*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_b, y)); 370*74f7f6c6SJacob Faibussowitsch // A waits for B 371*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(dctx_a, dctx_b)); 372*74f7f6c6SJacob Faibussowitsch // Because A waits on B, synchronizing A implicitly implies B read must have finished so the 373*74f7f6c6SJacob Faibussowitsch // map must be empty 374*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_a)); 375*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 376*74f7f6c6SJacob Faibussowitsch 377*74f7f6c6SJacob Faibussowitsch PetscCall(write(dctx_a, x)); 378*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({make_map_entry(x_id, PETSC_MEMORY_ACCESS_WRITE, dctx_a)})); 379*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(dctx_b, dctx_a)); 380*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(dctx_c, dctx_b)); 381*74f7f6c6SJacob Faibussowitsch // We have created the chain C -> B -> A, so synchronizing C should trickle down to synchronize and 382*74f7f6c6SJacob Faibussowitsch // remove A from the map 383*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_c)); 384*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 385*74f7f6c6SJacob Faibussowitsch 386*74f7f6c6SJacob Faibussowitsch // Test that superfluous stream-dependencies are properly ignored 387*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_a, x)); 388*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_b, y)); 389*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextWaitForContext(dctx_c, dctx_b)); 390*74f7f6c6SJacob Faibussowitsch // C waited on B, so synchronizing C should remove B from the map but *not* remove A 391*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_c)); 392*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({make_map_entry(x_id, PETSC_MEMORY_ACCESS_READ, dctx_a)})); 393*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_a)); 394*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 395*74f7f6c6SJacob Faibussowitsch 396*74f7f6c6SJacob Faibussowitsch // Test that read->write correctly wipes out the map 397*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_a, x)); 398*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_b, x)); 399*74f7f6c6SJacob Faibussowitsch PetscCall(read(dctx_c, x)); 400*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({make_map_entry(x_id, PETSC_MEMORY_ACCESS_READ, dctx_a, dctx_b, dctx_c)})); 401*74f7f6c6SJacob Faibussowitsch PetscCall(write(dctx_a, x)); 402*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({make_map_entry(x_id, PETSC_MEMORY_ACCESS_WRITE, dctx_a)})); 403*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx_a)); 404*74f7f6c6SJacob Faibussowitsch PetscCall(CheckMapEqual({})); 405*74f7f6c6SJacob Faibussowitsch 406*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextDestroy(&dctx_a)); 407*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextDestroy(&dctx_b)); 408*74f7f6c6SJacob Faibussowitsch PetscCall(PetscDeviceContextDestroy(&dctx_c)); 409*74f7f6c6SJacob Faibussowitsch 410*74f7f6c6SJacob Faibussowitsch PetscCall(PetscContainerDestroy(&x)); 411*74f7f6c6SJacob Faibussowitsch PetscCall(PetscContainerDestroy(&y)); 412*74f7f6c6SJacob Faibussowitsch PetscCall(PetscContainerDestroy(&z)); 413*74f7f6c6SJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "EXIT_SUCCESS\n")); 414*74f7f6c6SJacob Faibussowitsch PetscCall(PetscFinalize()); 415*74f7f6c6SJacob Faibussowitsch return 0; 416*74f7f6c6SJacob Faibussowitsch } 417*74f7f6c6SJacob Faibussowitsch 418*74f7f6c6SJacob Faibussowitsch /*TEST 419*74f7f6c6SJacob Faibussowitsch 420*74f7f6c6SJacob Faibussowitsch testset: 421*74f7f6c6SJacob Faibussowitsch requires: cxx 422*74f7f6c6SJacob Faibussowitsch output_file: ./output/ExitSuccess.out 423*74f7f6c6SJacob Faibussowitsch test: 424*74f7f6c6SJacob Faibussowitsch requires: !device 425*74f7f6c6SJacob Faibussowitsch suffix: host_no_device 426*74f7f6c6SJacob Faibussowitsch test: 427*74f7f6c6SJacob Faibussowitsch requires: device 428*74f7f6c6SJacob Faibussowitsch args: -default_device_type host 429*74f7f6c6SJacob Faibussowitsch suffix: host_with_device 430*74f7f6c6SJacob Faibussowitsch test: 431*74f7f6c6SJacob Faibussowitsch requires: cuda 432*74f7f6c6SJacob Faibussowitsch args: -default_device_type cuda 433*74f7f6c6SJacob Faibussowitsch suffix: cuda 434*74f7f6c6SJacob Faibussowitsch test: 435*74f7f6c6SJacob Faibussowitsch requires: hip 436*74f7f6c6SJacob Faibussowitsch args: -default_device_type hip 437*74f7f6c6SJacob Faibussowitsch suffix: hip 438*74f7f6c6SJacob Faibussowitsch test: 439*74f7f6c6SJacob Faibussowitsch requires: sycl 440*74f7f6c6SJacob Faibussowitsch args: -default_device_type sycl 441*74f7f6c6SJacob Faibussowitsch suffix: sycl 442*74f7f6c6SJacob Faibussowitsch 443*74f7f6c6SJacob Faibussowitsch TEST*/ 444