blob: 23d6dfeb7cd40479ccec19cd309e89e5f20b4b04 [file] [log] [blame]
//===- 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 <cassert>
#include <iostream>
#include <map>
#include <mutex>
#include <set>
#include <vector>
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<omptest::internal::EventTy> 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<OmptEventGroupInterface> getEventGroups() const {
return EventGroups;
}
/// Accessor for the event group interface.
std::shared_ptr<logging::Logger> 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<OmptEventGroupInterface> EventGroups{nullptr};
/// Pointer to the logging instance.
std::shared_ptr<logging::Logger> 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<OmptEventGroupInterface> EventGroupInterfaceInstance;
/// Static member to manage the singleton logging instance
static std::weak_ptr<logging::Logger> 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<omptest::OmptAssertEvent> 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<omptest::OmptAssertEvent> 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<std::string, omptest::AssertEventGroup> ActiveEventGroups{};
std::map<std::string, omptest::AssertEventGroup> DeprecatedEventGroups{};
std::set<std::string> EncounteredSyncPoints{};
};
} // namespace omptest
#endif