brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.3 KiB · d129049 Raw
332 lines · cpp
1 2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#include "kmp.h"11#include "kmp_i18n.h"12#include "kmp_io.h"13#include "kmp_str.h"14#if OMPT_SUPPORT15#include "ompt-specific.h"16#endif17 18/*!19@ingroup CANCELLATION20@param loc_ref location of the original task directive21@param gtid Global thread ID of encountering thread22@param cncl_kind Cancellation kind (parallel, for, sections, taskgroup)23 24@return returns true if the cancellation request has been activated and the25execution thread needs to proceed to the end of the canceled region.26 27Request cancellation of the binding OpenMP region.28*/29kmp_int32 __kmpc_cancel(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 cncl_kind) {30  kmp_info_t *this_thr = __kmp_threads[gtid];31 32  KC_TRACE(10, ("__kmpc_cancel: T#%d request %d OMP_CANCELLATION=%d\n", gtid,33                cncl_kind, __kmp_omp_cancellation));34 35  KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);36  KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||37                   cncl_kind == cancel_sections ||38                   cncl_kind == cancel_taskgroup);39  KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);40 41  if (__kmp_omp_cancellation) {42    switch (cncl_kind) {43    case cancel_parallel:44    case cancel_loop:45    case cancel_sections:46      // cancellation requests for parallel and worksharing constructs47      // are handled through the team structure48      {49        kmp_team_t *this_team = this_thr->th.th_team;50        KMP_DEBUG_ASSERT(this_team);51        kmp_int32 old = cancel_noreq;52        this_team->t.t_cancel_request.compare_exchange_strong(old, cncl_kind);53        if (old == cancel_noreq || old == cncl_kind) {54// we do not have a cancellation request in this team or we do have55// one that matches the current request -> cancel56#if OMPT_SUPPORT && OMPT_OPTIONAL57          if (ompt_enabled.ompt_callback_cancel) {58            ompt_data_t *task_data;59            __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,60                                          NULL);61            ompt_cancel_flag_t type = ompt_cancel_parallel;62            if (cncl_kind == cancel_parallel)63              type = ompt_cancel_parallel;64            else if (cncl_kind == cancel_loop)65              type = ompt_cancel_loop;66            else if (cncl_kind == cancel_sections)67              type = ompt_cancel_sections;68            ompt_callbacks.ompt_callback(ompt_callback_cancel)(69                task_data, type | ompt_cancel_activated,70                OMPT_GET_RETURN_ADDRESS(0));71          }72#endif // OMPT_SUPPORT && OMPT_OPTIONAL73          return 1 /* true */;74        }75        break;76      }77    case cancel_taskgroup:78      // cancellation requests for a task group79      // are handled through the taskgroup structure80      {81        kmp_taskdata_t *task;82        kmp_taskgroup_t *taskgroup;83 84        task = this_thr->th.th_current_task;85        KMP_DEBUG_ASSERT(task);86 87        taskgroup = task->td_taskgroup;88        if (taskgroup) {89          kmp_int32 old = cancel_noreq;90          taskgroup->cancel_request.compare_exchange_strong(old, cncl_kind);91          if (old == cancel_noreq || old == cncl_kind) {92// we do not have a cancellation request in this taskgroup or we do93// have one that matches the current request -> cancel94#if OMPT_SUPPORT && OMPT_OPTIONAL95            if (ompt_enabled.ompt_callback_cancel) {96              ompt_data_t *task_data;97              __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,98                                            NULL);99              ompt_callbacks.ompt_callback(ompt_callback_cancel)(100                  task_data, ompt_cancel_taskgroup | ompt_cancel_activated,101                  OMPT_GET_RETURN_ADDRESS(0));102            }103#endif104            return 1 /* true */;105          }106        } else {107          // TODO: what needs to happen here?108          // the specification disallows cancellation w/o taskgroups109          // so we might do anything here, let's abort for now110          KMP_ASSERT(0 /* false */);111        }112      }113      break;114    default:115      KMP_ASSERT(0 /* false */);116    }117  }118 119  // ICV OMP_CANCELLATION=false, so we ignored this cancel request120  KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);121  return 0 /* false */;122}123 124/*!125@ingroup CANCELLATION126@param loc_ref location of the original task directive127@param gtid Global thread ID of encountering thread128@param cncl_kind Cancellation kind (parallel, for, sections, taskgroup)129 130@return returns true if a matching cancellation request has been flagged in the131RTL and the encountering thread has to cancel..132 133Cancellation point for the encountering thread.134*/135kmp_int32 __kmpc_cancellationpoint(ident_t *loc_ref, kmp_int32 gtid,136                                   kmp_int32 cncl_kind) {137  kmp_info_t *this_thr = __kmp_threads[gtid];138 139  KC_TRACE(10,140           ("__kmpc_cancellationpoint: T#%d request %d OMP_CANCELLATION=%d\n",141            gtid, cncl_kind, __kmp_omp_cancellation));142 143  KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);144  KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||145                   cncl_kind == cancel_sections ||146                   cncl_kind == cancel_taskgroup);147  KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);148 149  if (__kmp_omp_cancellation) {150    switch (cncl_kind) {151    case cancel_parallel:152    case cancel_loop:153    case cancel_sections:154      // cancellation requests for parallel and worksharing constructs155      // are handled through the team structure156      {157        kmp_team_t *this_team = this_thr->th.th_team;158        KMP_DEBUG_ASSERT(this_team);159        if (this_team->t.t_cancel_request) {160          if (cncl_kind == this_team->t.t_cancel_request) {161// the request in the team structure matches the type of162// cancellation point so we can cancel163#if OMPT_SUPPORT && OMPT_OPTIONAL164            if (ompt_enabled.ompt_callback_cancel) {165              ompt_data_t *task_data;166              __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,167                                            NULL);168              ompt_cancel_flag_t type = ompt_cancel_parallel;169              if (cncl_kind == cancel_parallel)170                type = ompt_cancel_parallel;171              else if (cncl_kind == cancel_loop)172                type = ompt_cancel_loop;173              else if (cncl_kind == cancel_sections)174                type = ompt_cancel_sections;175              ompt_callbacks.ompt_callback(ompt_callback_cancel)(176                  task_data, type | ompt_cancel_detected,177                  OMPT_GET_RETURN_ADDRESS(0));178            }179#endif180            return 1 /* true */;181          }182          KMP_ASSERT(0 /* false */);183        } else {184          // we do not have a cancellation request pending, so we just185          // ignore this cancellation point186          return 0;187        }188        break;189      }190    case cancel_taskgroup:191      // cancellation requests for a task group192      // are handled through the taskgroup structure193      {194        kmp_taskdata_t *task;195        kmp_taskgroup_t *taskgroup;196 197        task = this_thr->th.th_current_task;198        KMP_DEBUG_ASSERT(task);199 200        taskgroup = task->td_taskgroup;201        if (taskgroup) {202// return the current status of cancellation for the taskgroup203#if OMPT_SUPPORT && OMPT_OPTIONAL204          if (ompt_enabled.ompt_callback_cancel &&205              !!taskgroup->cancel_request) {206            ompt_data_t *task_data;207            __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,208                                          NULL);209            ompt_callbacks.ompt_callback(ompt_callback_cancel)(210                task_data, ompt_cancel_taskgroup | ompt_cancel_detected,211                OMPT_GET_RETURN_ADDRESS(0));212          }213#endif214          return !!taskgroup->cancel_request;215        } else {216          // if a cancellation point is encountered by a task that does not217          // belong to a taskgroup, it is OK to ignore it218          return 0 /* false */;219        }220      }221    default:222      KMP_ASSERT(0 /* false */);223    }224  }225 226  // ICV OMP_CANCELLATION=false, so we ignore the cancellation point227  KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);228  return 0 /* false */;229}230 231/*!232@ingroup CANCELLATION233@param loc_ref location of the original task directive234@param gtid Global thread ID of encountering thread235 236@return returns true if a matching cancellation request has been flagged in the237RTL and the encountering thread has to cancel..238 239Barrier with cancellation point to send threads from the barrier to the240end of the parallel region.  Needs a special code pattern as documented241in the design document for the cancellation feature.242*/243kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32 gtid) {244  int ret = 0 /* false */;245  kmp_info_t *this_thr = __kmp_threads[gtid];246  kmp_team_t *this_team = this_thr->th.th_team;247 248  KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);249 250  // call into the standard barrier251  __kmpc_barrier(loc, gtid);252 253  // if cancellation is active, check cancellation flag254  if (__kmp_omp_cancellation) {255    // depending on which construct to cancel, check the flag and256    // reset the flag257    switch (KMP_ATOMIC_LD_RLX(&(this_team->t.t_cancel_request))) {258    case cancel_parallel:259      ret = 1;260      // ensure that threads have checked the flag, when261      // leaving the above barrier262      __kmpc_barrier(loc, gtid);263      this_team->t.t_cancel_request = cancel_noreq;264      // the next barrier is the fork/join barrier, which265      // synchronizes the threads leaving here266      break;267    case cancel_loop:268    case cancel_sections:269      ret = 1;270      // ensure that threads have checked the flag, when271      // leaving the above barrier272      __kmpc_barrier(loc, gtid);273      this_team->t.t_cancel_request = cancel_noreq;274      // synchronize the threads again to make sure we do not have any run-away275      // threads that cause a race on the cancellation flag276      __kmpc_barrier(loc, gtid);277      break;278    case cancel_taskgroup:279      // this case should not occur280      KMP_ASSERT(0 /* false */);281      break;282    case cancel_noreq:283      // do nothing284      break;285    default:286      KMP_ASSERT(0 /* false */);287    }288  }289 290  return ret;291}292 293/*!294@ingroup CANCELLATION295@param loc_ref location of the original task directive296@param gtid Global thread ID of encountering thread297 298@return returns true if a matching cancellation request has been flagged in the299RTL and the encountering thread has to cancel..300 301Query function to query the current status of cancellation requests.302Can be used to implement the following pattern:303 304if (kmp_get_cancellation_status(kmp_cancel_parallel)) {305    perform_cleanup();306    #pragma omp cancellation point parallel307}308*/309int __kmp_get_cancellation_status(int cancel_kind) {310  if (__kmp_omp_cancellation) {311    kmp_info_t *this_thr = __kmp_entry_thread();312 313    switch (cancel_kind) {314    case cancel_parallel:315    case cancel_loop:316    case cancel_sections: {317      kmp_team_t *this_team = this_thr->th.th_team;318      return this_team->t.t_cancel_request == cancel_kind;319    }320    case cancel_taskgroup: {321      kmp_taskdata_t *task;322      kmp_taskgroup_t *taskgroup;323      task = this_thr->th.th_current_task;324      taskgroup = task->td_taskgroup;325      return taskgroup && taskgroup->cancel_request;326    }327    }328  }329 330  return 0 /* false */;331}332