Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: testing framework and initial tests #14

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open

add: testing framework and initial tests #14

wants to merge 18 commits into from

Conversation

ounuvar
Copy link
Collaborator

@ounuvar ounuvar commented Jul 12, 2024

Added a testing framework and initial tests for the memory decoder. Two classes called Field and Instruction in the testing-utils.hh file form the testing framework. Some of the initial tests currently fail because of bugs in the memory decoder, and the correct decoder outputs for some instructions (like prefetch instructions) are ambiguous.

To run the tests (while at the top of the qflex repository):
$ cd qemu/middleware/testing
$ cmake -S . -B build
$ cmake --build build -j$(nproc)
$ (cd build && ctest -j$(nproc))

@ounuvar ounuvar requested a review from branylagaffe July 12, 2024 12:54
@ounuvar ounuvar self-assigned this Jul 12, 2024
@ounuvar ounuvar changed the title Testing framework and initial tests add: testing framework and initial tests Jul 12, 2024
Copy link
Contributor

@branylagaffe branylagaffe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall good.

Few design flaw. Few coding mistakes.

However, the comments are to improve. They are usually shallow and only reflect the meaning of the function name or the next line. Comments should indicate to the reader the possible state of the variable, why we need this function, the limitations of the function, any kind of asserted input/output.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As somewhat expected, the tests do not build OOTB, because the decoder require some qemu includes (osdep).
Two options from here:
1. Add a FLAG from the CmakeList.txt file which switch the header in the aforementioned files
2. Use QEMU build system to build the test, tricky but good.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on the second option? How would it work?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented the first option for now.

#ifndef TESTING_UTILS_HH
#define TESTING_UTILS_HH

#include <iostream>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these include are not needed anymore

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Fixing.

std::string bitmask{""};

// Current iteration number (iterates from 0 to numIters - 1)
int currIter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use coherently the std defined integer (uint8_t, size_t, ....) and c++ defined integer (int, long).
I guess we can use the std defined ones here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing.

Instruction(Args&&... args);

// Vector to hold pointers to Field objects
std::vector<Field*> fields;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to use raw pointer instead of reference here ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, we can't store references inside containers like vector in C++. I guess I could use a reference_wrapper object here as well (just like the void Instruction::addField(std::reference_wrapper field) function in testing-utils.cc). That might make even more sense actually since we already take the arguments as reference_wrapper objects.

InstructionIterator end() const;

private:
// Variadic template function to add fields (Field objects or string literals) to the instruction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variadic is not an English word

Suggested change
// Variadic template function to add fields (Field objects or string literals) to the instruction
// specialized function ..

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variadic is the correct technical term I believe: https://en.wikipedia.org/wiki/Variadic

bitmask += field->bitmask;
}
// The instruction bitmask must be 32 bits
assert(bitmask.size() == 32 && "Bitmask size must be 32.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your assert is wrongly defined.

  assert((void("void helps to avoid 'unused value' warning"), 2 * 2 == 4));
  OR
  assert((010 + 010 == 16) && "Yet another way to add an assert message");
  OR
  assertm((2 + 2) % 3 == 1, "Success");

Notice the parentheses around the expression

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

== should have higher precedence than && but will add the parentheses just to make it clearer.

assert(bitmask.size() == 32 && "Bitmask size must be 32.");

// Count the number of don't cares in the instruction bitmask
int numDontCares = std::count(bitmask.begin(), bitmask.end(), 'x');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type coherence

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you again referring to the use of builtin int instead of stdint types? (Or the lack of consisteny in the usage?)

uint32_t result = 0;

// Generate the instruction based on the bitmask
for (int i = 0, j = 0; i < 32; ++i) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid hardcoded number (32, 31)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing.

}

// Dereference operator to get the current instruction value during range-based for loops
uint32_t Instruction::InstructionIterator::operator*() const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why the dereference operator is link to generating an instruction, Shall not the instruction get pre-processed and retrieved by the deref. operator

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wdym by pre-processed? The exact instruction bits (the uint32_t value) for each iteration in for (uint32_t instr : bitmask) is generated during runtime through the dereference operator.

uint32_t Instruction::InstructionIterator::operator*() const {
uint32_t result = 0;

// Generate the instruction based on the bitmask
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop should be a function in Instruction instead of the Iterator.
The loop is slightly unintuitive (basically everything with bitwise operator is); i would suggest decoupling this loop into more functions

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dereference operator (method) needs to be defined for the Iterator class. I could move the logic to a separate helper function in the Instruction class (and also maybe divide it into multiple functions in the meantime like you said) and call it from the dereference operator in the Iterator class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep the deref. operator is needed for the Iterator, no question. As you said the logic should be moved elsewhere, and maybe pre-processed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants