brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.1 KiB · 342ff7e Raw
485 lines · cpp
1//===- OmptAsserter.cpp - Asserter-related implementations ------*- 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/// Implements all asserter-related class methods, like: notifications, handling11/// of groups or determination of the testcase state.12///13//===----------------------------------------------------------------------===//14 15#include "OmptAsserter.h"16#include "Logging.h"17 18#include <algorithm>19 20using namespace omptest;21using namespace internal;22 23// Initialize static members24std::mutex OmptAsserter::StaticMemberAccessMutex;25std::weak_ptr<OmptEventGroupInterface>26    OmptAsserter::EventGroupInterfaceInstance;27std::weak_ptr<logging::Logger> OmptAsserter::LoggingInstance;28 29OmptAsserter::OmptAsserter() {30  // Protect static members access31  std::lock_guard<std::mutex> Lock(StaticMemberAccessMutex);32 33  // Upgrade OmptEventGroupInterface weak_ptr to shared_ptr34  {35    EventGroups = EventGroupInterfaceInstance.lock();36    if (!EventGroups) {37      // Coordinator doesn't exist or was previously destroyed, create a new38      // one.39      EventGroups = std::make_shared<OmptEventGroupInterface>();40      // Store a weak reference to it41      EventGroupInterfaceInstance = EventGroups;42    }43    // EventGroups is now a valid shared_ptr, either to a new or existing44    // instance.45  }46 47  // Upgrade logging::Logger weak_ptr to shared_ptr48  {49    Log = LoggingInstance.lock();50    if (!Log) {51      // Coordinator doesn't exist or was previously destroyed, create a new52      // one.53      Log = std::make_shared<logging::Logger>();54      // Store a weak reference to it55      LoggingInstance = Log;56    }57    // Log is now a valid shared_ptr, either to a new or existing instance.58  }59}60 61void OmptListener::setActive(bool Enabled) { Active = Enabled; }62 63bool OmptListener::isActive() { return Active; }64 65bool OmptListener::isSuppressedEventType(EventTy EvTy) {66  return SuppressedEvents.find(EvTy) != SuppressedEvents.end();67}68 69void OmptListener::permitEvent(EventTy EvTy) { SuppressedEvents.erase(EvTy); }70 71void OmptListener::suppressEvent(EventTy EvTy) {72  SuppressedEvents.insert(EvTy);73}74 75void OmptAsserter::insert(OmptAssertEvent &&AE) {76  assert(false && "Base class 'insert' has undefined semantics.");77}78 79void OmptAsserter::notify(OmptAssertEvent &&AE) {80  // Ignore notifications while inactive81  if (!isActive() || isSuppressedEventType(AE.getEventType()))82    return;83 84  this->notifyImpl(std::move(AE));85}86 87AssertState OmptAsserter::checkState() { return State; }88 89bool OmptAsserter::verifyEventGroups(const OmptAssertEvent &ExpectedEvent,90                                     const OmptAssertEvent &ObservedEvent) {91  assert(ExpectedEvent.getEventType() == ObservedEvent.getEventType() &&92         "Type mismatch: Expected != Observed event type");93  assert(EventGroups && "Missing EventGroups interface");94 95  // Ignore all events within "default" group96  auto GroupName = ExpectedEvent.getEventGroup();97 98  if (GroupName == "default")99    return true;100 101  // Get a pointer to the observed internal event102  auto Event = ObservedEvent.getEvent();103 104  switch (Event->Type) {105  case EventTy::Target:106    if (auto E = static_cast<const internal::Target *>(Event)) {107      if (E->Endpoint == ompt_scope_begin) {108        // Add new group since we entered a Target Region109        EventGroups->addActiveEventGroup(GroupName,110                                         AssertEventGroup{E->TargetId});111      } else if (E->Endpoint == ompt_scope_end) {112        // Deprecate group since we return from a Target Region113        EventGroups->deprecateActiveEventGroup(GroupName);114      }115      return true;116    }117    return false;118  case EventTy::TargetEmi:119    if (auto E = static_cast<const internal::TargetEmi *>(Event)) {120      if (E->Endpoint == ompt_scope_begin) {121        // Add new group since we entered a Target Region122        EventGroups->addActiveEventGroup(123            GroupName, AssertEventGroup{E->TargetData->value});124      } else if (E->Endpoint == ompt_scope_end) {125        // Deprecate group since we return from a Target Region126        EventGroups->deprecateActiveEventGroup(GroupName);127      }128      return true;129    }130    return false;131  case EventTy::TargetDataOp:132    if (auto E = static_cast<const internal::TargetDataOp *>(Event))133      return EventGroups->checkActiveEventGroups(GroupName,134                                                 AssertEventGroup{E->TargetId});135 136    return false;137  case EventTy::TargetDataOpEmi:138    if (auto E = static_cast<const internal::TargetDataOpEmi *>(Event))139      return EventGroups->checkActiveEventGroups(140          GroupName, AssertEventGroup{E->TargetData->value});141 142    return false;143  case EventTy::TargetSubmit:144    if (auto E = static_cast<const internal::TargetSubmit *>(Event))145      return EventGroups->checkActiveEventGroups(GroupName,146                                                 AssertEventGroup{E->TargetId});147 148    return false;149  case EventTy::TargetSubmitEmi:150    if (auto E = static_cast<const internal::TargetSubmitEmi *>(Event))151      return EventGroups->checkActiveEventGroups(152          GroupName, AssertEventGroup{E->TargetData->value});153 154    return false;155  case EventTy::BufferRecord:156    // BufferRecords are delivered asynchronously: also check deprecated groups.157    if (auto E = static_cast<const internal::BufferRecord *>(Event))158      return (EventGroups->checkActiveEventGroups(159                  GroupName, AssertEventGroup{E->Record.target_id}) ||160              EventGroups->checkDeprecatedEventGroups(161                  GroupName, AssertEventGroup{E->Record.target_id}));162    return false;163  // Some event types do not need any handling164  case EventTy::ThreadBegin:165  case EventTy::ThreadEnd:166  case EventTy::ParallelBegin:167  case EventTy::ParallelEnd:168  case EventTy::Work:169  case EventTy::Dispatch:170  case EventTy::TaskCreate:171  case EventTy::Dependences:172  case EventTy::TaskDependence:173  case EventTy::TaskSchedule:174  case EventTy::ImplicitTask:175  case EventTy::Masked:176  case EventTy::SyncRegion:177  case EventTy::MutexAcquire:178  case EventTy::Mutex:179  case EventTy::NestLock:180  case EventTy::Flush:181  case EventTy::Cancel:182  case EventTy::DeviceInitialize:183  case EventTy::DeviceFinalize:184  case EventTy::DeviceLoad:185  case EventTy::DeviceUnload:186  case EventTy::BufferRequest:187  case EventTy::BufferComplete:188  case EventTy::BufferRecordDeallocation:189    return true;190  // Some event types must not be encountered191  case EventTy::None:192  case EventTy::AssertionSyncPoint:193  case EventTy::AssertionSuspend:194  default:195    Log->log("Observed invalid event type: " + Event->toString(),196             logging::Level::Critical);197    __builtin_unreachable();198  }199 200  return true;201}202 203void OmptAsserter::setOperationMode(AssertMode Mode) { OperationMode = Mode; }204 205void OmptSequencedAsserter::insert(OmptAssertEvent &&AE) {206  std::lock_guard<std::mutex> Lock(AssertMutex);207  Events.emplace_back(std::move(AE));208}209 210void OmptSequencedAsserter::notifyImpl(OmptAssertEvent &&AE) {211  std::lock_guard<std::mutex> Lock(AssertMutex);212  // Ignore notifications while inactive, or for suppressed events213  if (Events.empty() || !isActive() || isSuppressedEventType(AE.getEventType()))214    return;215 216  ++NumNotifications;217 218  // Note: Order of these checks has semantic meaning.219  // (1) Synchronization points should fail if there are remaining events,220  // otherwise pass. (2) Regular notification while no further events are221  // expected: fail. (3) Assertion suspension relies on a next expected event222  // being available. (4) All other cases are considered 'regular' and match the223  // next expected against the observed event. (5+6) Depending on the state /224  // mode we signal failure if no other check has done already, or signaled pass225  // by early-exit.226  if (consumeSyncPoint(AE) ||               // Handle observed SyncPoint event227      checkExcessNotify(AE) ||              // Check for remaining expected228      consumeSuspend() ||                   // Handle requested suspend229      consumeRegularEvent(AE) ||            // Handle regular event230      AssertionSuspended ||                 // Ignore fail, if suspended231      OperationMode == AssertMode::Relaxed) // Ignore fail, if Relaxed op-mode232    return;233 234  Log->logEventMismatch("[OmptSequencedAsserter] The events are not equal",235                        Events[NextEvent], AE);236  State = AssertState::Fail;237}238 239bool OmptSequencedAsserter::consumeSyncPoint(240    const omptest::OmptAssertEvent &AE) {241  if (AE.getEventType() == EventTy::AssertionSyncPoint) {242    auto NumRemainingEvents = getRemainingEventCount();243    // Upon encountering a SyncPoint, all events should have been processed244    if (NumRemainingEvents == 0)245      return true;246 247    Log->logEventMismatch(248        "[OmptSequencedAsserter] Encountered SyncPoint while still awaiting " +249            std::to_string(NumRemainingEvents) + " events. Asserted " +250            std::to_string(NumSuccessfulAsserts) + "/" +251            std::to_string(Events.size()) + " events successfully.",252        AE);253    State = AssertState::Fail;254    return true;255  }256 257  // Nothing to process: continue.258  return false;259}260 261bool OmptSequencedAsserter::checkExcessNotify(262    const omptest::OmptAssertEvent &AE) {263  if (NextEvent >= Events.size()) {264    // If we are not expecting any more events and passively asserting: return265    if (AssertionSuspended)266      return true;267 268    Log->logEventMismatch(269        "[OmptSequencedAsserter] Too many events to check (" +270            std::to_string(NumNotifications) + "). Asserted " +271            std::to_string(NumSuccessfulAsserts) + "/" +272            std::to_string(Events.size()) + " events successfully.",273        AE);274    State = AssertState::Fail;275    return true;276  }277 278  // Remaining expected events present: continue.279  return false;280}281 282bool OmptSequencedAsserter::consumeSuspend() {283  // On AssertionSuspend -- enter 'passive' assertion.284  // Since we may encounter multiple, successive AssertionSuspend events, loop285  // until we hit the next non-AssertionSuspend event.286  while (Events[NextEvent].getEventType() == EventTy::AssertionSuspend) {287    AssertionSuspended = true;288    // We just hit the very last event: indicate early exit.289    if (++NextEvent >= Events.size())290      return true;291  }292 293  // Continue with remaining notification logic.294  return false;295}296 297bool OmptSequencedAsserter::consumeRegularEvent(298    const omptest::OmptAssertEvent &AE) {299  // If we are actively asserting, increment the event counter.300  // Otherwise: If passively asserting, we will keep waiting for a match.301  auto &E = Events[NextEvent];302  if (E == AE && verifyEventGroups(E, AE)) {303    if (E.getEventExpectedState() == ObserveState::Always) {304      ++NumSuccessfulAsserts;305    } else if (E.getEventExpectedState() == ObserveState::Never) {306      Log->logEventMismatch(307          "[OmptSequencedAsserter] Encountered forbidden event", E, AE);308      State = AssertState::Fail;309    }310 311    // Return to active assertion312    if (AssertionSuspended)313      AssertionSuspended = false;314 315    // Match found, increment index and indicate early exit (success).316    ++NextEvent;317    return true;318  }319 320  // Continue with remaining notification logic.321  return false;322}323 324size_t OmptSequencedAsserter::getRemainingEventCount() {325  return std::count_if(Events.begin(), Events.end(),326                       [](const omptest::OmptAssertEvent &E) {327                         return E.getEventExpectedState() ==328                                ObserveState::Always;329                       }) -330         NumSuccessfulAsserts;331}332 333AssertState OmptSequencedAsserter::checkState() {334  // This is called after the testcase executed.335  // Once reached the number of successful notifications should be equal to the336  // number of expected events. However, there may still be excluded as well as337  // special asserter events remaining in the sequence.338  for (size_t i = NextEvent; i < Events.size(); ++i) {339    auto &E = Events[i];340    if (E.getEventExpectedState() == ObserveState::Always) {341      State = AssertState::Fail;342      Log->logEventMismatch("[OmptSequencedAsserter] Expected event was not "343                            "encountered (Remaining events: " +344                                std::to_string(getRemainingEventCount()) + ")",345                            E);346      break;347    }348  }349 350  return State;351}352 353void OmptEventAsserter::insert(OmptAssertEvent &&AE) {354  std::lock_guard<std::mutex> Lock(AssertMutex);355  Events.emplace_back(std::move(AE));356}357 358void OmptEventAsserter::notifyImpl(OmptAssertEvent &&AE) {359  std::lock_guard<std::mutex> Lock(AssertMutex);360  if (Events.empty() || !isActive() || isSuppressedEventType(AE.getEventType()))361    return;362 363  if (NumEvents == 0)364    NumEvents = Events.size();365 366  ++NumNotifications;367 368  if (AE.getEventType() == EventTy::AssertionSyncPoint) {369    auto NumRemainingEvents = getRemainingEventCount();370    // Upon encountering a SyncPoint, all events should have been processed371    if (NumRemainingEvents == 0)372      return;373 374    Log->logEventMismatch(375        "[OmptEventAsserter] Encountered SyncPoint while still awaiting " +376            std::to_string(NumRemainingEvents) + " events. Asserted " +377            std::to_string(NumSuccessfulAsserts) + " events successfully.",378        AE);379    State = AssertState::Fail;380    return;381  }382 383  for (size_t i = 0; i < Events.size(); ++i) {384    auto &E = Events[i];385    if (E == AE && verifyEventGroups(E, AE)) {386      if (E.getEventExpectedState() == ObserveState::Always) {387        Events.erase(Events.begin() + i);388        ++NumSuccessfulAsserts;389      } else if (E.getEventExpectedState() == ObserveState::Never) {390        Log->logEventMismatch("[OmptEventAsserter] Encountered forbidden event",391                              E, AE);392        State = AssertState::Fail;393      }394      return;395    }396  }397 398  if (OperationMode == AssertMode::Strict) {399    Log->logEventMismatch("[OmptEventAsserter] Too many events to check (" +400                              std::to_string(NumNotifications) +401                              "). Asserted " +402                              std::to_string(NumSuccessfulAsserts) +403                              " events successfully. (Remaining events: " +404                              std::to_string(getRemainingEventCount()) + ")",405                          AE);406    State = AssertState::Fail;407    return;408  }409}410 411size_t OmptEventAsserter::getRemainingEventCount() {412  return std::count_if(413      Events.begin(), Events.end(), [](const omptest::OmptAssertEvent &E) {414        return E.getEventExpectedState() == ObserveState::Always;415      });416}417 418AssertState OmptEventAsserter::checkState() {419  // This is called after the testcase executed.420  // Once reached no more expected events should be in the queue421  for (const auto &E : Events) {422    // Check if any of the remaining events were expected to be observed423    if (E.getEventExpectedState() == ObserveState::Always) {424      State = AssertState::Fail;425      Log->logEventMismatch("[OmptEventAsserter] Expected event was not "426                            "encountered (Remaining events: " +427                                std::to_string(getRemainingEventCount()) + ")",428                            E);429      break;430    }431  }432 433  return State;434}435 436void OmptEventReporter::notify(OmptAssertEvent &&AE) {437  if (!isActive() || isSuppressedEventType(AE.getEventType()))438    return;439 440  // Prepare notification, containing the newline to avoid stream interleaving.441  auto Notification{AE.toString()};442  Notification.push_back('\n');443  OutStream << Notification;444}445 446bool OmptEventGroupInterface::addActiveEventGroup(447    const std::string &GroupName, omptest::AssertEventGroup Group) {448  std::lock_guard<std::mutex> Lock(GroupMutex);449  auto EventGroup = ActiveEventGroups.find(GroupName);450  if (EventGroup != ActiveEventGroups.end() &&451      EventGroup->second.TargetRegion == Group.TargetRegion)452    return false;453  ActiveEventGroups.emplace(GroupName, Group);454  return true;455}456 457bool OmptEventGroupInterface::deprecateActiveEventGroup(458    const std::string &GroupName) {459  std::lock_guard<std::mutex> Lock(GroupMutex);460  auto EventGroup = ActiveEventGroups.find(GroupName);461  auto DeprecatedEventGroup = DeprecatedEventGroups.find(GroupName);462  if (EventGroup == ActiveEventGroups.end() &&463      DeprecatedEventGroup != DeprecatedEventGroups.end())464    return false;465  DeprecatedEventGroups.emplace(GroupName, EventGroup->second);466  ActiveEventGroups.erase(GroupName);467  return true;468}469 470bool OmptEventGroupInterface::checkActiveEventGroups(471    const std::string &GroupName, omptest::AssertEventGroup Group) {472  std::lock_guard<std::mutex> Lock(GroupMutex);473  auto EventGroup = ActiveEventGroups.find(GroupName);474  return (EventGroup != ActiveEventGroups.end() &&475          EventGroup->second.TargetRegion == Group.TargetRegion);476}477 478bool OmptEventGroupInterface::checkDeprecatedEventGroups(479    const std::string &GroupName, omptest::AssertEventGroup Group) {480  std::lock_guard<std::mutex> Lock(GroupMutex);481  auto EventGroup = DeprecatedEventGroups.find(GroupName);482  return (EventGroup != DeprecatedEventGroups.end() &&483          EventGroup->second.TargetRegion == Group.TargetRegion);484}485