//===- OmptAsserter.h - Asserter-related classes, enums, etc. ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// Contains all asserter-related class declarations and important enums. /// //===----------------------------------------------------------------------===// #ifndef OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTASSERTER_H #define OPENMP_TOOLS_OMPTEST_INCLUDE_OMPTASSERTER_H #include "Logging.h" #include "OmptAssertEvent.h" #include #include #include #include #include #include namespace omptest { // Forward declaration. class OmptEventGroupInterface; enum class AssertMode { Strict, Relaxed }; enum class AssertState { Pass, Fail }; /// General base class for the subscriber/notification pattern in /// OmptCallbackHandler. Derived classes need to implement the notify method. class OmptListener { public: virtual ~OmptListener() = default; /// Called for each registered OMPT event of the OmptCallbackHandler virtual void notify(omptest::OmptAssertEvent &&AE) = 0; /// Control whether this asserter should be considered 'active'. void setActive(bool Enabled); /// Check if this asserter is considered 'active'. bool isActive(); /// Check if the given event type is from the set of suppressed event types. bool isSuppressedEventType(omptest::internal::EventTy EvTy); /// Remove the given event type to the set of suppressed events. void permitEvent(omptest::internal::EventTy EvTy); /// Add the given event type to the set of suppressed events. void suppressEvent(omptest::internal::EventTy EvTy); private: bool Active{true}; // Add event types to the set of suppressed events by default. std::set SuppressedEvents{ omptest::internal::EventTy::ThreadBegin, omptest::internal::EventTy::ThreadEnd, omptest::internal::EventTy::ParallelBegin, omptest::internal::EventTy::ParallelEnd, omptest::internal::EventTy::Work, omptest::internal::EventTy::Dispatch, omptest::internal::EventTy::TaskCreate, omptest::internal::EventTy::Dependences, omptest::internal::EventTy::TaskDependence, omptest::internal::EventTy::TaskSchedule, omptest::internal::EventTy::ImplicitTask, omptest::internal::EventTy::Masked, omptest::internal::EventTy::SyncRegion, omptest::internal::EventTy::MutexAcquire, omptest::internal::EventTy::Mutex, omptest::internal::EventTy::NestLock, omptest::internal::EventTy::Flush, omptest::internal::EventTy::Cancel}; }; /// Base class for asserting on OMPT events class OmptAsserter : public OmptListener { public: OmptAsserter(); virtual ~OmptAsserter() = default; /// Add an event to the asserter's internal data structure. virtual void insert(omptest::OmptAssertEvent &&AE); /// Called from the CallbackHandler with a corresponding AssertEvent to which /// callback was handled. void notify(omptest::OmptAssertEvent &&AE) override; /// Implemented in subclasses to implement what should actually be done with /// the notification. virtual void notifyImpl(omptest::OmptAssertEvent &&AE) = 0; /// Get the number of currently remaining events, with: ObserveState::Always. virtual size_t getRemainingEventCount() = 0; /// Get the total number of received, effective notifications. int getNotificationCount() { return NumNotifications; } /// Get the total number of successful assertion checks. int getSuccessfulAssertionCount() { return NumSuccessfulAsserts; } /// Get the asserter's current operationmode: e.g.: Strict or Relaxed. AssertMode getOperationMode() { return OperationMode; } /// Return the asserter's current state. omptest::AssertState getState() { return State; } /// Determine and return the asserter's state. virtual omptest::AssertState checkState(); /// Accessor for the event group interface. std::shared_ptr getEventGroups() const { return EventGroups; } /// Accessor for the event group interface. std::shared_ptr getLog() const { return Log; } /// Check the observed events' group association. If the event indicates the /// begin/end of an OpenMP target region, we will create/deprecate the /// expected event's group. Return true if the expected event group exists /// (and is active), otherwise: false. Note: BufferRecords may also match with /// deprecated groups as they may be delivered asynchronously. bool verifyEventGroups(const omptest::OmptAssertEvent &ExpectedEvent, const omptest::OmptAssertEvent &ObservedEvent); /// Set the asserter's mode of operation w.r.t. assertion. void setOperationMode(AssertMode Mode); protected: /// The asserter's current state. omptest::AssertState State{omptest::AssertState::Pass}; /// Mutex to avoid data races w.r.t. event notifications and/or insertions. std::mutex AssertMutex; /// Pointer to the OmptEventGroupInterface. std::shared_ptr EventGroups{nullptr}; /// Pointer to the logging instance. std::shared_ptr Log{nullptr}; /// Operation mode during assertion / notification. AssertMode OperationMode{AssertMode::Strict}; /// The total number of effective notifications. For example, if specific /// notifications are to be ignored, they will not count towards this total. int NumNotifications{0}; /// The number of successful assertion checks. int NumSuccessfulAsserts{0}; private: /// Mutex for creating/accessing the singleton members static std::mutex StaticMemberAccessMutex; /// Static member to manage the singleton event group interface instance static std::weak_ptr EventGroupInterfaceInstance; /// Static member to manage the singleton logging instance static std::weak_ptr LoggingInstance; }; /// Class that can assert in a sequenced fashion, i.e., events have to occur in /// the order they were registered class OmptSequencedAsserter : public OmptAsserter { public: OmptSequencedAsserter() : OmptAsserter(), NextEvent(0) {} /// Add the event to the in-sequence set of events that the asserter should /// check for. void insert(omptest::OmptAssertEvent &&AE) override; /// Implements the asserter's actual logic virtual void notifyImpl(omptest::OmptAssertEvent &&AE) override; size_t getRemainingEventCount() override; omptest::AssertState checkState() override; bool AssertionSuspended{false}; protected: /// Notification helper function, implementing SyncPoint logic. Returns true /// in case of consumed event, indicating early exit of notification. bool consumeSyncPoint(const omptest::OmptAssertEvent &AE); /// Notification helper function, implementing excess event notification /// logic. Returns true when no more events were expected, indicating early /// exit of notification. bool checkExcessNotify(const omptest::OmptAssertEvent &AE); /// Notification helper function, implementing Suspend logic. Returns true /// in case of consumed event, indicating early exit of notification. bool consumeSuspend(); /// Notification helper function, implementing regular event notification /// logic. Returns true when a matching event was encountered, indicating /// early exit of notification. bool consumeRegularEvent(const omptest::OmptAssertEvent &AE); public: /// Index of the next, expected event. size_t NextEvent{0}; std::vector Events{}; }; /// Class that asserts with set semantics, i.e., unordered struct OmptEventAsserter : public OmptAsserter { OmptEventAsserter() : OmptAsserter(), NumEvents(0), Events() {} /// Add the event to the set of events that the asserter should check for. void insert(omptest::OmptAssertEvent &&AE) override; /// Implements the asserter's logic virtual void notifyImpl(omptest::OmptAssertEvent &&AE) override; size_t getRemainingEventCount() override; omptest::AssertState checkState() override; size_t NumEvents{0}; /// For now use vector (but do set semantics) // TODO std::unordered_set? std::vector Events{}; }; /// Class that reports the occurred events class OmptEventReporter : public OmptListener { public: OmptEventReporter(std::ostream &OutStream = std::cout) : OutStream(OutStream) {} /// Called from the CallbackHandler with a corresponding AssertEvent to which /// callback was handled. void notify(omptest::OmptAssertEvent &&AE) override; private: std::ostream &OutStream; }; /// This class provides the members and methods to manage event groups and /// SyncPoints in conjunction with asserters. Most importantly it maintains a /// coherent view of active and past events or SyncPoints. class OmptEventGroupInterface { public: OmptEventGroupInterface() = default; ~OmptEventGroupInterface() = default; /// Non-copyable and non-movable OmptEventGroupInterface(const OmptEventGroupInterface &) = delete; OmptEventGroupInterface &operator=(const OmptEventGroupInterface &) = delete; OmptEventGroupInterface(OmptEventGroupInterface &&) = delete; OmptEventGroupInterface &operator=(OmptEventGroupInterface &&) = delete; /// Add given group to the set of active event groups. Effectively connecting /// the given groupname (expected) with a target region id (observed). bool addActiveEventGroup(const std::string &GroupName, omptest::AssertEventGroup Group); /// Move given group from the set of active event groups to the set of /// previously active event groups. bool deprecateActiveEventGroup(const std::string &GroupName); /// Check if given group is currently part of the active event groups. bool checkActiveEventGroups(const std::string &GroupName, omptest::AssertEventGroup Group); /// Check if given group is currently part of the deprecated event groups. bool checkDeprecatedEventGroups(const std::string &GroupName, omptest::AssertEventGroup Group); private: mutable std::mutex GroupMutex; std::map ActiveEventGroups{}; std::map DeprecatedEventGroups{}; std::set EncounteredSyncPoints{}; }; } // namespace omptest #endif