[5706] | 1 | #ifndef PROCESSING_RATE_H |
---|
| 2 | #define PROCESSING_RATE_H |
---|
| 3 | |
---|
| 4 | #include <string> |
---|
| 5 | #include <assert.h> |
---|
[5755] | 6 | #include <boost/rational.hpp> |
---|
[5706] | 7 | |
---|
| 8 | namespace kernel { |
---|
| 9 | |
---|
[5782] | 10 | // Processing rate attributes are required for all stream set bindings. They describe |
---|
| 11 | // the relationship between processed items (inputs) and produced items (outputs). |
---|
[5706] | 12 | // |
---|
[5782] | 13 | // For example, the 3-to-4 kernel converts every 3 input items into 4 output items. |
---|
| 14 | // Thus it has a FixedRate(3) for its input stream and FixedRate(4) for its output |
---|
| 15 | // stream. Processing these every 3 items individually would be time consuming. Instead |
---|
| 16 | // the kernel processes a strides' worth of "iterations" and automatically scales the |
---|
| 17 | // FixedRates accordingly. |
---|
[5706] | 18 | // |
---|
[5782] | 19 | // NOTE: fixed and bounded rates should be the smallest number of input items for the |
---|
| 20 | // smallest number of output items that can be logically produced by a kernel. |
---|
[5706] | 21 | |
---|
[5782] | 22 | |
---|
| 23 | |
---|
| 24 | |
---|
[5706] | 25 | struct ProcessingRate { |
---|
| 26 | |
---|
[5755] | 27 | friend struct Binding; |
---|
| 28 | |
---|
[5706] | 29 | enum class KindId { |
---|
[5985] | 30 | Fixed, Bounded, Unknown, Relative, PopCount, NegatedPopCount |
---|
[5706] | 31 | }; |
---|
| 32 | |
---|
[5755] | 33 | using RateValue = boost::rational<unsigned>; |
---|
| 34 | |
---|
[5706] | 35 | KindId getKind() const { return mKind; } |
---|
| 36 | |
---|
[5755] | 37 | RateValue getRate() const { |
---|
| 38 | return mLowerBound; |
---|
[5706] | 39 | } |
---|
| 40 | |
---|
[5755] | 41 | RateValue getLowerBound() const { |
---|
| 42 | return mLowerBound; |
---|
[5706] | 43 | } |
---|
| 44 | |
---|
[5755] | 45 | RateValue getUpperBound() const { |
---|
| 46 | return mUpperBound; |
---|
[5706] | 47 | } |
---|
| 48 | |
---|
| 49 | const std::string & getReference() const { |
---|
[5985] | 50 | assert (hasReference()); |
---|
[5706] | 51 | return mReference; |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | bool isFixed() const { |
---|
| 55 | return mKind == KindId::Fixed; |
---|
| 56 | } |
---|
| 57 | |
---|
| 58 | bool isBounded() const { |
---|
| 59 | return mKind == KindId::Bounded; |
---|
| 60 | } |
---|
| 61 | |
---|
[5755] | 62 | bool isRelative() const { |
---|
| 63 | return mKind == KindId::Relative; |
---|
[5706] | 64 | } |
---|
| 65 | |
---|
[5755] | 66 | bool isPopCount() const { |
---|
| 67 | return mKind == KindId::PopCount; |
---|
| 68 | } |
---|
| 69 | |
---|
[5985] | 70 | bool isNegatedPopCount() const { |
---|
| 71 | return mKind == KindId::NegatedPopCount; |
---|
| 72 | } |
---|
| 73 | |
---|
[5706] | 74 | bool isUnknown() const { |
---|
| 75 | return mKind == KindId::Unknown; |
---|
| 76 | } |
---|
| 77 | |
---|
[5985] | 78 | bool hasReference() const { |
---|
| 79 | return isRelative() || isPopCount() || isNegatedPopCount(); |
---|
| 80 | } |
---|
| 81 | |
---|
[5706] | 82 | bool isDerived() const { |
---|
[5985] | 83 | return isRelative(); |
---|
[5706] | 84 | } |
---|
| 85 | |
---|
| 86 | bool operator == (const ProcessingRate & other) const { |
---|
[5755] | 87 | return mKind == other.mKind && mLowerBound == other.mLowerBound && mUpperBound == other.mUpperBound && mReference == other.mReference; |
---|
[5706] | 88 | } |
---|
| 89 | |
---|
| 90 | bool operator != (const ProcessingRate & other) const { |
---|
| 91 | return !(*this == other); |
---|
| 92 | } |
---|
| 93 | |
---|
| 94 | friend ProcessingRate FixedRate(const unsigned); |
---|
| 95 | friend ProcessingRate BoundedRate(const unsigned, const unsigned); |
---|
| 96 | friend ProcessingRate UnknownRate(const unsigned); |
---|
| 97 | friend ProcessingRate RateEqualTo(std::string); |
---|
[5985] | 98 | friend ProcessingRate PopcountOf(std::string); |
---|
| 99 | friend ProcessingRate PopcountOfNot(std::string); |
---|
[5706] | 100 | |
---|
[5755] | 101 | ProcessingRate(ProcessingRate &&) = default; |
---|
| 102 | ProcessingRate(const ProcessingRate &) = default; |
---|
| 103 | ProcessingRate & operator = (const ProcessingRate & other) = default; |
---|
[5706] | 104 | |
---|
[5755] | 105 | protected: |
---|
[5985] | 106 | ProcessingRate(const KindId k, const RateValue lb, const RateValue ub, const std::string && ref = "") |
---|
| 107 | : mKind(k) |
---|
| 108 | , mLowerBound(lb) |
---|
| 109 | , mUpperBound(ub) |
---|
| 110 | , mReference(ref) { |
---|
| 111 | assert (isFixed() ? mUpperBound == mLowerBound : (isBounded() ? mUpperBound > mLowerBound : mUpperBound >= mLowerBound)); |
---|
| 112 | } |
---|
[5706] | 113 | private: |
---|
[5985] | 114 | const KindId mKind; |
---|
| 115 | const RateValue mLowerBound; |
---|
| 116 | const RateValue mUpperBound; |
---|
| 117 | const std::string mReference; |
---|
[5706] | 118 | }; |
---|
| 119 | |
---|
| 120 | inline ProcessingRate FixedRate(const unsigned rate = 1) { |
---|
| 121 | return ProcessingRate(ProcessingRate::KindId::Fixed, rate, rate); |
---|
| 122 | } |
---|
| 123 | |
---|
| 124 | inline ProcessingRate BoundedRate(const unsigned lower, const unsigned upper) { |
---|
[5756] | 125 | using RateValue = boost::rational<unsigned>; |
---|
[5706] | 126 | if (lower == upper) { |
---|
| 127 | return FixedRate(lower); |
---|
| 128 | } else { |
---|
[5756] | 129 | return ProcessingRate(ProcessingRate::KindId::Bounded, RateValue(lower), RateValue(upper)); |
---|
[5706] | 130 | } |
---|
| 131 | } |
---|
| 132 | |
---|
[5755] | 133 | /** |
---|
| 134 | * @brief UnknownRate |
---|
| 135 | * |
---|
| 136 | * The produced item count per stride should never be dependent on an unknown rate input stream. |
---|
| 137 | */ |
---|
[5706] | 138 | inline ProcessingRate UnknownRate(const unsigned lower = 0) { |
---|
| 139 | return ProcessingRate(ProcessingRate::KindId::Unknown, lower, 0); |
---|
| 140 | } |
---|
| 141 | |
---|
| 142 | inline ProcessingRate RateEqualTo(std::string ref) { |
---|
[5985] | 143 | return ProcessingRate(ProcessingRate::KindId::Relative, 1, 1, std::move(ref)); |
---|
[5706] | 144 | } |
---|
| 145 | |
---|
[5985] | 146 | inline ProcessingRate PopcountOf(std::string ref) { |
---|
| 147 | return ProcessingRate(ProcessingRate::KindId::PopCount, 0, 1, std::move(ref)); |
---|
[5706] | 148 | } |
---|
| 149 | |
---|
[5985] | 150 | inline ProcessingRate PopcountOfNot(std::string ref) { |
---|
| 151 | return ProcessingRate(ProcessingRate::KindId::NegatedPopCount, 0, 1, std::move(ref)); |
---|
| 152 | } |
---|
| 153 | |
---|
[5755] | 154 | ProcessingRate::RateValue lcm(const ProcessingRate::RateValue & x, const ProcessingRate::RateValue & y); |
---|
| 155 | |
---|
| 156 | ProcessingRate::RateValue gcd(const ProcessingRate::RateValue & x, const ProcessingRate::RateValue & y); |
---|
| 157 | |
---|
[5782] | 158 | unsigned ceiling(const ProcessingRate::RateValue & r); |
---|
| 159 | |
---|
[5755] | 160 | } |
---|
| 161 | |
---|
[5706] | 162 | #endif // PROCESSING_RATE_H |
---|