brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.4 KiB · 1a83f62 Raw
505 lines · cpp
1//===- OmptTester.cpp - ompTest OMPT tool implementation --------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file represents the core implementation file for the ompTest library.11/// It provides the actual OMPT tool implementation: registers callbacks, etc.12/// OMPT callbacks are passed to their corresponding handler, which in turn13/// notifies all registered asserters.14///15//===----------------------------------------------------------------------===//16 17#include "OmptTester.h"18 19#include <atomic>20#include <cassert>21#include <cstdlib>22#include <cstring>23 24using namespace omptest;25 26// Callback handler, which receives and relays OMPT callbacks27extern OmptCallbackHandler *Handler;28 29// EventListener, which actually prints the OMPT events30static OmptEventReporter *EventReporter;31 32// From openmp/runtime/test/ompt/callback.h33#define register_ompt_callback_t(name, type)                                   \34  do {                                                                         \35    type f_##name = &on_##name;                                                \36    if (ompt_set_callback(name, (ompt_callback_t)f_##name) == ompt_set_never)  \37      printf("0: Could not register callback '" #name "'\n");                  \38  } while (0)39 40#define register_ompt_callback(name) register_ompt_callback_t(name, name##_t)41 42#define OMPT_BUFFER_REQUEST_SIZE 25643 44#ifdef OPENMP_LIBOMPTEST_BUILD_STANDALONE45std::vector<std::pair<std::string, TestSuite>> TestRegistrar::Tests;46#endif47 48static std::atomic<ompt_id_t> NextOpId{0x8000000000000001};49static bool UseEMICallbacks = false;50static bool UseTracing = false;51static bool RunAsTestSuite = false;52static bool ColoredLog = false;53 54// OMPT entry point handles55static ompt_set_trace_ompt_t ompt_set_trace_ompt = 0;56static ompt_start_trace_t ompt_start_trace = 0;57static ompt_flush_trace_t ompt_flush_trace = 0;58static ompt_stop_trace_t ompt_stop_trace = 0;59static ompt_get_record_ompt_t ompt_get_record_ompt = 0;60static ompt_advance_buffer_cursor_t ompt_advance_buffer_cursor = 0;61static ompt_get_record_type_t ompt_get_record_type_fn = 0;62 63// OMPT device side tracing: Currently traced devices64typedef std::unordered_set<ompt_device_t *> OmptDeviceSetTy;65typedef std::unique_ptr<OmptDeviceSetTy> OmptDeviceSetPtrTy;66static OmptDeviceSetPtrTy TracedDevices;67 68// OMPT callbacks69 70// Trace record callbacks71static void on_ompt_callback_buffer_request(int device_num,72                                            ompt_buffer_t **buffer,73                                            size_t *bytes) {74  *bytes = OMPT_BUFFER_REQUEST_SIZE;75  *buffer = malloc(*bytes);76  OmptCallbackHandler::get().handleBufferRequest(device_num, buffer, bytes);77}78 79// Note: This callback must handle a null begin cursor. Currently,80// ompt_get_record_ompt, print_record_ompt, and81// ompt_advance_buffer_cursor handle a null cursor.82static void on_ompt_callback_buffer_complete(83    int device_num, ompt_buffer_t *buffer,84    size_t bytes, /* bytes returned in this callback */85    ompt_buffer_cursor_t begin, int buffer_owned) {86  OmptCallbackHandler::get().handleBufferComplete(device_num, buffer, bytes,87                                                  begin, buffer_owned);88 89  int Status = 1;90  ompt_buffer_cursor_t CurrentPos = begin;91  while (Status) {92    ompt_record_ompt_t *Record = ompt_get_record_ompt(buffer, CurrentPos);93    if (ompt_get_record_type_fn(buffer, CurrentPos) != ompt_record_ompt) {94      printf("Warning: received non-ompt type buffer object\n");95    }96    // TODO: Sometimes it may happen that the retrieved record may be null?!97    // Only handle non-null records98    if (Record != nullptr)99      OmptCallbackHandler::get().handleBufferRecord(Record);100    Status = ompt_advance_buffer_cursor(/*device=*/NULL, buffer, bytes,101                                        CurrentPos, &CurrentPos);102  }103  if (buffer_owned) {104    OmptCallbackHandler::get().handleBufferRecordDeallocation(buffer);105    free(buffer);106  }107}108 109static ompt_set_result_t set_trace_ompt(ompt_device_t *Device) {110  if (!ompt_set_trace_ompt)111    return ompt_set_error;112 113  if (UseEMICallbacks) {114    ompt_set_trace_ompt(Device, /*enable=*/1,115                        /*etype=*/ompt_callback_target_emi);116    ompt_set_trace_ompt(Device, /*enable=*/1,117                        /*etype=*/ompt_callback_target_data_op_emi);118    ompt_set_trace_ompt(Device, /*enable=*/1,119                        /*etype=*/ompt_callback_target_submit_emi);120  } else {121    ompt_set_trace_ompt(Device, /*enable=*/1, /*etype=*/ompt_callback_target);122    ompt_set_trace_ompt(Device, /*enable=*/1,123                        /*etype=*/ompt_callback_target_data_op);124    ompt_set_trace_ompt(Device, /*enable=*/1,125                        /*etype=*/ompt_callback_target_submit);126  }127 128  return ompt_set_always;129}130 131/////// HOST-RELATED //////132 133static void on_ompt_callback_thread_begin(ompt_thread_t thread_type,134                                          ompt_data_t *thread_data) {135  OmptCallbackHandler::get().handleThreadBegin(thread_type, thread_data);136}137 138static void on_ompt_callback_thread_end(ompt_data_t *thread_data) {139  OmptCallbackHandler::get().handleThreadEnd(thread_data);140}141 142static void on_ompt_callback_parallel_begin(143    ompt_data_t *encountering_task_data,144    const ompt_frame_t *encountering_task_frame, ompt_data_t *parallel_data,145    unsigned int requested_parallelism, int flags, const void *codeptr_ra) {146  OmptCallbackHandler::get().handleParallelBegin(147      encountering_task_data, encountering_task_frame, parallel_data,148      requested_parallelism, flags, codeptr_ra);149}150 151static void on_ompt_callback_parallel_end(ompt_data_t *parallel_data,152                                          ompt_data_t *encountering_task_data,153                                          int flags, const void *codeptr_ra) {154  OmptCallbackHandler::get().handleParallelEnd(155      parallel_data, encountering_task_data, flags, codeptr_ra);156}157 158static void159on_ompt_callback_task_create(ompt_data_t *encountering_task_data,160                             const ompt_frame_t *encountering_task_frame,161                             ompt_data_t *new_task_data, int flags,162                             int has_dependences, const void *codeptr_ra) {163  OmptCallbackHandler::get().handleTaskCreate(164      encountering_task_data, encountering_task_frame, new_task_data, flags,165      has_dependences, codeptr_ra);166}167 168static void on_ompt_callback_task_schedule(ompt_data_t *prior_task_data,169                                           ompt_task_status_t prior_task_status,170                                           ompt_data_t *next_task_data) {171  OmptCallbackHandler::get().handleTaskSchedule(172      prior_task_data, prior_task_status, next_task_data);173}174 175static void on_ompt_callback_implicit_task(ompt_scope_endpoint_t endpoint,176                                           ompt_data_t *parallel_data,177                                           ompt_data_t *task_data,178                                           unsigned int actual_parallelism,179                                           unsigned int index, int flags) {180  OmptCallbackHandler::get().handleImplicitTask(181      endpoint, parallel_data, task_data, actual_parallelism, index, flags);182}183 184// Callbacks as of Table 19.4, which are not considered required for a minimal185// conforming OMPT implementation.186static void on_ompt_callback_work(ompt_work_t work_type,187                                  ompt_scope_endpoint_t endpoint,188                                  ompt_data_t *parallel_data,189                                  ompt_data_t *task_data, uint64_t count,190                                  const void *codeptr_ra) {191  OmptCallbackHandler::get().handleWork(work_type, endpoint, parallel_data,192                                        task_data, count, codeptr_ra);193}194 195static void on_ompt_callback_dispatch(ompt_data_t *parallel_data,196                                      ompt_data_t *task_data,197                                      ompt_dispatch_t kind,198                                      ompt_data_t instance) {199  OmptCallbackHandler::get().handleDispatch(parallel_data, task_data, kind,200                                            instance);201}202 203static void on_ompt_callback_sync_region(ompt_sync_region_t kind,204                                         ompt_scope_endpoint_t endpoint,205                                         ompt_data_t *parallel_data,206                                         ompt_data_t *task_data,207                                         const void *codeptr_ra) {208  OmptCallbackHandler::get().handleSyncRegion(kind, endpoint, parallel_data,209                                              task_data, codeptr_ra);210}211 212/////// DEVICE-RELATED //////213 214// Synchronous callbacks215static void on_ompt_callback_device_initialize(int device_num, const char *type,216                                               ompt_device_t *device,217                                               ompt_function_lookup_t lookup,218                                               const char *documentation) {219  OmptCallbackHandler::get().handleDeviceInitialize(device_num, type, device,220                                                    lookup, documentation);221  if (!UseTracing)222    return;223 224  if (!lookup) {225    printf("Trace collection disabled on device %d\n", device_num);226    return;227  }228 229  ompt_set_trace_ompt = (ompt_set_trace_ompt_t)lookup("ompt_set_trace_ompt");230  ompt_start_trace = (ompt_start_trace_t)lookup("ompt_start_trace");231  ompt_flush_trace = (ompt_flush_trace_t)lookup("ompt_flush_trace");232  ompt_stop_trace = (ompt_stop_trace_t)lookup("ompt_stop_trace");233  ompt_get_record_ompt = (ompt_get_record_ompt_t)lookup("ompt_get_record_ompt");234  ompt_advance_buffer_cursor =235      (ompt_advance_buffer_cursor_t)lookup("ompt_advance_buffer_cursor");236 237  ompt_get_record_type_fn =238      (ompt_get_record_type_t)lookup("ompt_get_record_type");239  if (!ompt_get_record_type_fn) {240    printf("Warning: No function ompt_get_record_type found in device "241           "callbacks\n");242  }243 244  static bool IsDeviceMapInitialized = false;245  if (!IsDeviceMapInitialized) {246    TracedDevices = std::make_unique<OmptDeviceSetTy>();247    IsDeviceMapInitialized = true;248  }249 250  set_trace_ompt(device);251 252  // In many scenarios, this is a good place to start the253  // trace. If start_trace is called from the main program before this254  // callback is dispatched, the start_trace handle will be null. This255  // is because this device_init callback is invoked during the first256  // target construct implementation.257 258  start_trace(device);259}260 261static void on_ompt_callback_device_finalize(int device_num) {262  OmptCallbackHandler::get().handleDeviceFinalize(device_num);263}264 265static void on_ompt_callback_device_load(int device_num, const char *filename,266                                         int64_t offset_in_file,267                                         void *vma_in_file, size_t bytes,268                                         void *host_addr, void *device_addr,269                                         uint64_t module_id) {270  OmptCallbackHandler::get().handleDeviceLoad(271      device_num, filename, offset_in_file, vma_in_file, bytes, host_addr,272      device_addr, module_id);273}274 275static void on_ompt_callback_device_unload(int device_num, uint64_t module_id) {276  OmptCallbackHandler::get().handleDeviceUnload(device_num, module_id);277}278 279static void on_ompt_callback_target_data_op(280    ompt_id_t target_id, ompt_id_t host_op_id, ompt_target_data_op_t optype,281    void *src_addr, int src_device_num, void *dest_addr, int dest_device_num,282    size_t bytes, const void *codeptr_ra) {283  OmptCallbackHandler::get().handleTargetDataOp(284      target_id, host_op_id, optype, src_addr, src_device_num, dest_addr,285      dest_device_num, bytes, codeptr_ra);286}287 288static void on_ompt_callback_target(ompt_target_t kind,289                                    ompt_scope_endpoint_t endpoint,290                                    int device_num, ompt_data_t *task_data,291                                    ompt_id_t target_id,292                                    const void *codeptr_ra) {293  OmptCallbackHandler::get().handleTarget(kind, endpoint, device_num, task_data,294                                          target_id, codeptr_ra);295}296 297static void on_ompt_callback_target_submit(ompt_id_t target_id,298                                           ompt_id_t host_op_id,299                                           unsigned int requested_num_teams) {300  OmptCallbackHandler::get().handleTargetSubmit(target_id, host_op_id,301                                                requested_num_teams);302}303 304static void on_ompt_callback_target_data_op_emi(305    ompt_scope_endpoint_t endpoint, ompt_data_t *target_task_data,306    ompt_data_t *target_data, ompt_id_t *host_op_id,307    ompt_target_data_op_t optype, void *src_addr, int src_device_num,308    void *dest_addr, int dest_device_num, size_t bytes,309    const void *codeptr_ra) {310  assert(codeptr_ra != 0 && "Unexpected null codeptr");311  // Both src and dest must not be null312  // However, for omp_target_alloc only the END call holds a value for one of313  // the two entries314  if (optype != ompt_target_data_alloc)315    assert((src_addr != 0 || dest_addr != 0) && "Both src and dest addr null");316  if (endpoint == ompt_scope_begin)317    *host_op_id = NextOpId.fetch_add(1, std::memory_order_relaxed);318  OmptCallbackHandler::get().handleTargetDataOpEmi(319      endpoint, target_task_data, target_data, host_op_id, optype, src_addr,320      src_device_num, dest_addr, dest_device_num, bytes, codeptr_ra);321}322 323static void on_ompt_callback_target_emi(ompt_target_t kind,324                                        ompt_scope_endpoint_t endpoint,325                                        int device_num, ompt_data_t *task_data,326                                        ompt_data_t *target_task_data,327                                        ompt_data_t *target_data,328                                        const void *codeptr_ra) {329  assert(codeptr_ra != 0 && "Unexpected null codeptr");330  if (endpoint == ompt_scope_begin)331    target_data->value = NextOpId.fetch_add(1, std::memory_order_relaxed);332  OmptCallbackHandler::get().handleTargetEmi(kind, endpoint, device_num,333                                             task_data, target_task_data,334                                             target_data, codeptr_ra);335}336 337static void on_ompt_callback_target_submit_emi(338    ompt_scope_endpoint_t endpoint, ompt_data_t *target_data,339    ompt_id_t *host_op_id, unsigned int requested_num_teams) {340  OmptCallbackHandler::get().handleTargetSubmitEmi(341      endpoint, target_data, host_op_id, requested_num_teams);342}343 344static void on_ompt_callback_target_map(ompt_id_t target_id,345                                        unsigned int nitems, void **host_addr,346                                        void **device_addr, size_t *bytes,347                                        unsigned int *mapping_flags,348                                        const void *codeptr_ra) {349  assert(0 && "Target map callback is unimplemented");350}351 352static void on_ompt_callback_target_map_emi(ompt_data_t *target_data,353                                            unsigned int nitems,354                                            void **host_addr,355                                            void **device_addr, size_t *bytes,356                                            unsigned int *mapping_flags,357                                            const void *codeptr_ra) {358  assert(0 && "Target map emi callback is unimplemented");359}360 361/// Load the value of a given boolean environmental variable.362bool getBoolEnvironmentVariable(const char *VariableName) {363  if (VariableName == nullptr)364    return false;365  if (const char *EnvValue = std::getenv(VariableName)) {366    std::string S{EnvValue};367    for (auto &C : S)368      C = (char)std::tolower(C);369    if (S == "1" || S == "on" || S == "true" || S == "yes")370      return true;371  }372  return false;373}374 375/// Called by the OMP runtime to initialize the OMPT376int ompt_initialize(ompt_function_lookup_t lookup, int initial_device_num,377                    ompt_data_t *tool_data) {378  ompt_set_callback_t ompt_set_callback = nullptr;379  ompt_set_callback = (ompt_set_callback_t)lookup("ompt_set_callback");380  if (!ompt_set_callback)381    return 0; // failure382 383  UseEMICallbacks = getBoolEnvironmentVariable("OMPTEST_USE_OMPT_EMI");384  UseTracing = getBoolEnvironmentVariable("OMPTEST_USE_OMPT_TRACING");385  RunAsTestSuite = getBoolEnvironmentVariable("OMPTEST_RUN_AS_TESTSUITE");386  ColoredLog = getBoolEnvironmentVariable("OMPTEST_LOG_COLORED");387 388  register_ompt_callback(ompt_callback_thread_begin);389  register_ompt_callback(ompt_callback_thread_end);390  register_ompt_callback(ompt_callback_parallel_begin);391  register_ompt_callback(ompt_callback_parallel_end);392  register_ompt_callback(ompt_callback_work);393  register_ompt_callback(ompt_callback_dispatch);394  register_ompt_callback(ompt_callback_task_create);395  // register_ompt_callback(ompt_callback_dependences);396  // register_ompt_callback(ompt_callback_task_dependence);397  register_ompt_callback(ompt_callback_task_schedule);398  register_ompt_callback(ompt_callback_implicit_task);399  // register_ompt_callback(ompt_callback_masked);400  register_ompt_callback(ompt_callback_sync_region);401  // register_ompt_callback(ompt_callback_mutex_acquire);402  // register_ompt_callback(ompt_callback_mutex);403  // register_ompt_callback(ompt_callback_nestLock);404  // register_ompt_callback(ompt_callback_flush);405  // register_ompt_callback(ompt_callback_cancel);406  register_ompt_callback(ompt_callback_device_initialize);407  register_ompt_callback(ompt_callback_device_finalize);408  register_ompt_callback(ompt_callback_device_load);409  register_ompt_callback(ompt_callback_device_unload);410 411  if (UseEMICallbacks) {412    register_ompt_callback(ompt_callback_target_emi);413    register_ompt_callback(ompt_callback_target_submit_emi);414    register_ompt_callback(ompt_callback_target_data_op_emi);415    register_ompt_callback(ompt_callback_target_map_emi);416  } else {417    register_ompt_callback(ompt_callback_target);418    register_ompt_callback(ompt_callback_target_submit);419    register_ompt_callback(ompt_callback_target_data_op);420    register_ompt_callback(ompt_callback_target_map);421  }422 423  // Construct & subscribe the reporter, so it gets notified of events424  EventReporter = new OmptEventReporter();425  OmptCallbackHandler::get().subscribe(EventReporter);426 427  if (RunAsTestSuite)428    EventReporter->setActive(false);429 430  return 1; // success431}432 433void ompt_finalize(ompt_data_t *tool_data) {434  assert(Handler && "Callback handler should be present at this point");435  assert(EventReporter && "EventReporter should be present at this point");436  delete Handler;437  delete EventReporter;438}439 440#ifdef __cplusplus441extern "C" {442#endif443/// Called from the OMP Runtime to start / initialize the tool444ompt_start_tool_result_t *ompt_start_tool(unsigned int omp_version,445                                          const char *runtime_version) {446  static ompt_start_tool_result_t ompt_start_tool_result = {447      &ompt_initialize, &ompt_finalize, {0}};448  return &ompt_start_tool_result;449}450 451int start_trace(ompt_device_t *Device) {452  if (!ompt_start_trace)453    return 0;454 455  // Start tracing this device (add to set)456  assert(TracedDevices->find(Device) == TracedDevices->end() &&457         "Device already present in the map");458  TracedDevices->insert(Device);459 460  return ompt_start_trace(Device, &on_ompt_callback_buffer_request,461                          &on_ompt_callback_buffer_complete);462}463 464int flush_trace(ompt_device_t *Device) {465  if (!ompt_flush_trace)466    return 0;467  return ompt_flush_trace(Device);468}469 470int flush_traced_devices() {471  if (!ompt_flush_trace || TracedDevices == nullptr)472    return 0;473 474  size_t NumFlushedDevices = 0;475  for (auto Device : *TracedDevices)476    if (ompt_flush_trace(Device) == 1)477      ++NumFlushedDevices;478 479  // Provide time to process triggered assert events480  std::this_thread::sleep_for(std::chrono::milliseconds(1));481 482  return (NumFlushedDevices == TracedDevices->size());483}484 485int stop_trace(ompt_device_t *Device) {486  if (!ompt_stop_trace)487    return 0;488 489  // Stop tracing this device (erase from set)490  assert(TracedDevices->find(Device) != TracedDevices->end() &&491         "Device not present in the map");492  TracedDevices->erase(Device);493 494  return ompt_stop_trace(Device);495}496 497// This is primarily used to stop unwanted prints from happening.498void libomptest_global_eventreporter_set_active(bool State) {499  assert(EventReporter && "EventReporter should be present at this point");500  EventReporter->setActive(State);501}502#ifdef __cplusplus503}504#endif505