[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 { |
---|
[5755] | 30 | Fixed, Bounded, Unknown, Relative, PopCount |
---|
[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 | assert (isFixed() || isRelative()); |
---|
| 39 | return mLowerBound; |
---|
[5706] | 40 | } |
---|
| 41 | |
---|
[5755] | 42 | RateValue getLowerBound() const { |
---|
[5706] | 43 | assert (isFixed() || isBounded() || isUnknown()); |
---|
[5755] | 44 | return mLowerBound; |
---|
[5706] | 45 | } |
---|
| 46 | |
---|
[5755] | 47 | RateValue getUpperBound() const { |
---|
[5706] | 48 | assert (isFixed() || isBounded()); |
---|
[5755] | 49 | assert (isFixed() ? mUpperBound == mLowerBound : mUpperBound > mLowerBound); |
---|
| 50 | return mUpperBound; |
---|
[5706] | 51 | } |
---|
| 52 | |
---|
| 53 | const std::string & getReference() const { |
---|
[5755] | 54 | assert (isRelative()); |
---|
[5706] | 55 | return mReference; |
---|
| 56 | } |
---|
| 57 | |
---|
| 58 | bool isFixed() const { |
---|
| 59 | return mKind == KindId::Fixed; |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | bool isBounded() const { |
---|
| 63 | return mKind == KindId::Bounded; |
---|
| 64 | } |
---|
| 65 | |
---|
[5755] | 66 | bool isRelative() const { |
---|
| 67 | return mKind == KindId::Relative; |
---|
[5706] | 68 | } |
---|
| 69 | |
---|
[5755] | 70 | bool isPopCount() const { |
---|
| 71 | return mKind == KindId::PopCount; |
---|
| 72 | } |
---|
| 73 | |
---|
[5706] | 74 | bool isUnknown() const { |
---|
| 75 | return mKind == KindId::Unknown; |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | bool isDerived() const { |
---|
[5755] | 79 | return isRelative(); // isFixed() || |
---|
[5706] | 80 | } |
---|
| 81 | |
---|
| 82 | bool operator == (const ProcessingRate & other) const { |
---|
[5755] | 83 | return mKind == other.mKind && mLowerBound == other.mLowerBound && mUpperBound == other.mUpperBound && mReference == other.mReference; |
---|
[5706] | 84 | } |
---|
| 85 | |
---|
| 86 | bool operator != (const ProcessingRate & other) const { |
---|
| 87 | return !(*this == other); |
---|
| 88 | } |
---|
| 89 | |
---|
| 90 | friend ProcessingRate FixedRate(const unsigned); |
---|
| 91 | friend ProcessingRate BoundedRate(const unsigned, const unsigned); |
---|
| 92 | friend ProcessingRate UnknownRate(const unsigned); |
---|
| 93 | friend ProcessingRate RateEqualTo(std::string); |
---|
[5755] | 94 | friend ProcessingRate PopcountOf(std::string, const ProcessingRate::RateValue); |
---|
[5706] | 95 | |
---|
[5755] | 96 | ProcessingRate(ProcessingRate &&) = default; |
---|
| 97 | ProcessingRate(const ProcessingRate &) = default; |
---|
| 98 | ProcessingRate & operator = (const ProcessingRate & other) = default; |
---|
[5706] | 99 | |
---|
[5755] | 100 | protected: |
---|
| 101 | ProcessingRate(const KindId k, const unsigned n, const unsigned m, const std::string && ref = "") : mKind(k), mLowerBound(n), mUpperBound(m), mReference(ref) {} |
---|
| 102 | ProcessingRate(const KindId k, const RateValue n, const RateValue m, const std::string && ref = "") : mKind(k), mLowerBound(n), mUpperBound(m), mReference(ref) {} |
---|
[5706] | 103 | private: |
---|
| 104 | KindId mKind; |
---|
[5755] | 105 | RateValue mLowerBound; |
---|
| 106 | RateValue mUpperBound; |
---|
[5706] | 107 | std::string mReference; |
---|
| 108 | }; |
---|
| 109 | |
---|
| 110 | inline ProcessingRate FixedRate(const unsigned rate = 1) { |
---|
| 111 | return ProcessingRate(ProcessingRate::KindId::Fixed, rate, rate); |
---|
| 112 | } |
---|
| 113 | |
---|
| 114 | inline ProcessingRate BoundedRate(const unsigned lower, const unsigned upper) { |
---|
[5756] | 115 | using RateValue = boost::rational<unsigned>; |
---|
[5706] | 116 | if (lower == upper) { |
---|
| 117 | return FixedRate(lower); |
---|
| 118 | } else { |
---|
[5756] | 119 | return ProcessingRate(ProcessingRate::KindId::Bounded, RateValue(lower), RateValue(upper)); |
---|
[5706] | 120 | } |
---|
| 121 | } |
---|
| 122 | |
---|
[5755] | 123 | /** |
---|
| 124 | * @brief UnknownRate |
---|
| 125 | * |
---|
| 126 | * The produced item count per stride should never be dependent on an unknown rate input stream. |
---|
| 127 | */ |
---|
[5706] | 128 | inline ProcessingRate UnknownRate(const unsigned lower = 0) { |
---|
| 129 | return ProcessingRate(ProcessingRate::KindId::Unknown, lower, 0); |
---|
| 130 | } |
---|
| 131 | |
---|
| 132 | inline ProcessingRate RateEqualTo(std::string ref) { |
---|
[5755] | 133 | return ProcessingRate(ProcessingRate::KindId::Relative, 1, 0, std::move(ref)); |
---|
[5706] | 134 | } |
---|
| 135 | |
---|
[5755] | 136 | inline ProcessingRate PopcountOf(std::string ref, const ProcessingRate::RateValue ratio = ProcessingRate::RateValue{1}) { |
---|
| 137 | return ProcessingRate(ProcessingRate::KindId::PopCount, ratio, ProcessingRate::RateValue{0}, std::move(ref)); |
---|
[5706] | 138 | } |
---|
| 139 | |
---|
[5755] | 140 | ProcessingRate::RateValue lcm(const ProcessingRate::RateValue & x, const ProcessingRate::RateValue & y); |
---|
| 141 | |
---|
| 142 | ProcessingRate::RateValue gcd(const ProcessingRate::RateValue & x, const ProcessingRate::RateValue & y); |
---|
| 143 | |
---|
[5782] | 144 | unsigned ceiling(const ProcessingRate::RateValue & r); |
---|
| 145 | |
---|
[5755] | 146 | } |
---|
| 147 | |
---|
[5706] | 148 | #endif // PROCESSING_RATE_H |
---|