base: Add operators to SatCounter

Add shift, add and subtract assignment operators, as well as
copy and move constructor and assignments to SatCounter, so
that it they can be used by the prefetchers.

Also add extra useful functions to calculate saturation
oercentile so that the instantiator does not need to be aware
of the counter's maximum value.

Change-Id: I61d0cb28c8375b9d2774a39011e4a0aa6fe9ccb7
Signed-off-by: Daniel <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/17996
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
Daniel
2019-04-13 11:02:43 +02:00
committed by Daniel Carvalho
parent 5b3f91daf6
commit 50a533f101
2 changed files with 287 additions and 0 deletions

View File

@@ -56,6 +56,9 @@
class SatCounter
{
public:
/** The default constructor should never be used. */
SatCounter() = delete;
/**
* Constructor for the counter. The explicit keyword is used to make
* sure the user does not assign a number to the counter thinking it
@@ -75,6 +78,58 @@ class SatCounter
"Saturating counter's Initial value exceeds max value.");
}
/** Copy constructor. */
SatCounter(const SatCounter& other)
: initialVal(other.initialVal), maxVal(other.maxVal),
counter(other.counter)
{
}
/** Copy assignment. */
SatCounter& operator=(const SatCounter& other) {
if (this != &other) {
SatCounter temp(other);
this->swap(temp);
}
return *this;
}
/** Move constructor. */
SatCounter(SatCounter&& other)
{
initialVal = other.initialVal;
maxVal = other.maxVal;
counter = other.counter;
SatCounter temp(0);
other.swap(temp);
}
/** Move assignment. */
SatCounter& operator=(SatCounter&& other) {
if (this != &other) {
initialVal = other.initialVal;
maxVal = other.maxVal;
counter = other.counter;
SatCounter temp(0);
other.swap(temp);
}
return *this;
}
/**
* Swap the contents of every member of the class. Used for the default
* copy-assignment created by the compiler.
*
* @param other The other object to swap contents with.
*/
void
swap(SatCounter& other)
{
std::swap(initialVal, other.initialVal);
std::swap(maxVal, other.maxVal);
std::swap(counter, other.counter);
}
/** Pre-increment operator. */
SatCounter&
operator++()
@@ -113,6 +168,49 @@ class SatCounter
return old_counter;
}
/** Shift-right-assignment. */
SatCounter&
operator>>=(const int& shift)
{
this->counter >>= shift;
return *this;
}
/** Shift-left-assignment. */
SatCounter&
operator<<=(const int& shift)
{
this->counter <<= shift;
if (this->counter > maxVal) {
this->counter = maxVal;
}
return *this;
}
/** Add-assignment. */
SatCounter&
operator+=(const int& value)
{
if (maxVal - this->counter >= value) {
this->counter += value;
} else {
this->counter = maxVal;
}
return *this;
}
/** Subtract-assignment. */
SatCounter&
operator-=(const int& value)
{
if (this->counter > value) {
this->counter -= value;
} else {
this->counter = 0;
}
return *this;
}
/**
* Read the counter's value.
*/
@@ -121,6 +219,22 @@ class SatCounter
/** Reset the counter to its initial value. */
void reset() { counter = initialVal; }
/**
* Calculate saturation percentile of the current counter's value
* with regard to its maximum possible value.
*
* @return A value between 0.0 and 1.0 to indicate which percentile of
* the maximum value the current value is.
*/
double calcSaturation() const { return (double) counter / maxVal; }
/**
* Whether the counter has achieved its maximum value or not.
*
* @return True if the counter saturated.
*/
bool isSaturated() const { return counter == maxVal; }
private:
uint8_t initialVal;
uint8_t maxVal;

View File

@@ -30,6 +30,8 @@
#include <gtest/gtest.h>
#include <utility>
#include "base/sat_counter.hh"
/**
@@ -77,6 +79,23 @@ TEST(SatCounterTest, InitialValue)
ASSERT_EQ(counter, initial_value);
}
/**
* Test calculating saturation percentile.
*/
TEST(SatCounterTest, SaturationPercentile)
{
const unsigned bits = 3;
const unsigned max_value = (1 << bits) - 1;
SatCounter counter(bits);
ASSERT_FALSE(counter.isSaturated());
for (double value = 0.0; value <= max_value; value++, counter++) {
const double saturation = value / max_value;
ASSERT_DOUBLE_EQ(counter.calcSaturation(), saturation);
}
ASSERT_TRUE(counter.isSaturated());
}
/**
* Test back and forth against an int.
*/
@@ -101,6 +120,55 @@ TEST(SatCounterTest, IntComparison)
ASSERT_EQ(counter, 0);
}
/**
* Test shift operators.
*/
TEST(SatCounterTest, Shift)
{
const unsigned bits = 3;
const unsigned max_value = (1 << bits) - 1;
const unsigned initial_value = 1;
SatCounter counter(bits, initial_value);
SatCounter other(bits, initial_value);
// The saturated shift value is just enough to saturate, since greater
// values could generate undefined behavior
SatCounter saturated_counter(bits, bits);
int value = initial_value;
// Test random shifts
counter <<= 2;
value <<= 2;
ASSERT_EQ(counter, value);
counter >>= 1;
value >>= 1;
ASSERT_EQ(counter, value);
// Test saturation
counter <<= bits;
ASSERT_EQ(counter, max_value);
// Test zeroing
counter >>= bits;
ASSERT_EQ(counter, 0);
// Test saturation against other saturating counter
counter.reset();
value = initial_value;
counter <<= other;
value <<= other;
ASSERT_EQ(counter, value);
counter <<= saturated_counter;
value = max_value;
ASSERT_EQ(counter, max_value);
// Test zeroing against other saturating counter
counter >>= other;
value >>= other;
ASSERT_EQ(counter, value);
counter >>= saturated_counter;
ASSERT_EQ(counter, 0);
}
/**
* Test both pre and post operators.
*/
@@ -129,3 +197,108 @@ TEST(SatCounterTest, PrePostOperators)
ASSERT_EQ(counter_pre, 0);
ASSERT_EQ(counter_post, 0);
}
/**
* Test copy and move for both constructor and assignment.
*/
TEST(SatCounterTest, CopyMove)
{
const unsigned bits = 3;
const unsigned max_value = (1 << bits) - 1;
const unsigned initial_value = 1;
SatCounter counter(bits, initial_value);
SatCounter deep_copy(1);
SatCounter counter_copy(2);
// Increase counter value so that we can check if the inner counter is
// being copied
counter++;
// Copy counter using both the copy constructor and the copy assignment
SatCounter counter_copy_constructor(counter);
deep_copy = counter_copy = counter;
ASSERT_EQ(counter_copy_constructor, initial_value + 1);
ASSERT_EQ(counter_copy, initial_value + 1);
ASSERT_EQ(deep_copy, initial_value + 1);
// Make sure max value is the same for all of them, and that modifying
// the copies does not modify the original
for (int i = 0; i < 2*max_value; i++) {
counter_copy_constructor++;
counter_copy++;
deep_copy++;
}
ASSERT_EQ(counter, initial_value + 1);
ASSERT_EQ(counter_copy_constructor, max_value);
ASSERT_EQ(counter_copy, max_value);
ASSERT_EQ(deep_copy, max_value);
// Make sure initial value is the same for all of them
counter_copy_constructor.reset();
counter_copy.reset();
deep_copy.reset();
ASSERT_EQ(counter_copy_constructor, initial_value);
ASSERT_EQ(counter_copy, initial_value);
ASSERT_EQ(deep_copy, initial_value);
// Now check move
SatCounter counter_move_constructor(std::move(counter));
ASSERT_EQ(counter, 0);
ASSERT_EQ(counter_move_constructor, initial_value + 1);
SatCounter counter_move(bits);
counter_move = std::move(counter_move_constructor);
ASSERT_EQ(counter_move_constructor, 0);
ASSERT_EQ(counter_move, initial_value + 1);
}
/**
* Test add-assignment and subtract assignment.
*/
TEST(SatCounterTest, AddSubAssignment)
{
const unsigned bits = 3;
const unsigned max_value = (1 << bits) - 1;
SatCounter counter(bits);
SatCounter other(bits, 2);
SatCounter saturated_counter(bits, max_value);
int value = 0;
// Test add-assignment for a few random values and then saturate
counter += 2;
value += 2;
ASSERT_EQ(counter, value);
counter += 3;
value += 3;
ASSERT_EQ(counter, value);
counter += max_value;
value = max_value;
ASSERT_EQ(counter, value);
// Test subtract-assignment for a few random values until back to zero
counter -= 2;
value -= 2;
ASSERT_EQ(counter, value);
counter -= 3;
value -= 3;
ASSERT_EQ(counter, value);
counter -= max_value;
value = 0;
ASSERT_EQ(counter, value);
// Test add-assignment of other saturating counter
counter += other;
value += other;
ASSERT_EQ(counter, value);
counter += saturated_counter;
value = max_value;
ASSERT_EQ(counter, saturated_counter);
// Test subtract-assignment of other saturating counter
counter -= other;
value -= other;
ASSERT_EQ(counter, value);
counter -= saturated_counter;
ASSERT_EQ(counter, 0);
}