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

Revisit, assess and extend ETISS Fault Injection #100

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

Conversation

JoGei
Copy link
Member

@JoGei JoGei commented Nov 24, 2021

This PR revisits the existing fault injection functionality in ETISS and extends it.

@JoGei JoGei changed the title Revisit, asses and extend ETISS Fault Injection Revisit, assess and extend ETISS Fault Injection Nov 24, 2021
Copy link
Member

@rafzi rafzi left a comment

Choose a reason for hiding this comment

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

looks good to merge, just some comments

src/ETISS.cpp Outdated
if (!faults.empty())
{
std::list<std::string> ffs = etiss::split(faults, ';');
for (auto ff : ffs)
Copy link
Member

Choose a reason for hiding this comment

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

The default pattern for this should be "const auto&". If you need mutablity, drop const and if you need a copy, drop the reference.

Copy link
Member Author

Choose a reason for hiding this comment

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

agreed (copied from old code base). Fixed with 3087cae

src/ETISS.cpp Outdated
}

etiss::log(etiss::VERBOSE, std::string("Add InstructionAccurateCallback Plugin to ") + cpu_core->getName() + std::string(". Required for etiss::fault::Injector."));
cpu_core->addPlugin(std::shared_ptr<etiss::Plugin>(new etiss::plugin::InstructionAccurateCallback()));
Copy link
Member

Choose a reason for hiding this comment

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

avoid explicit "new" by using "make_shared"

Copy link
Member Author

Choose a reason for hiding this comment

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

agreed (copied from example/bare_etiss_processor/main.cpp:L129). Fixed with 5149bc1 - also addresses example/bare_etiss_processor/main.cpp


std::shared_ptr<VirtualStruct> MemoryManipulationSystem::getStruct(void)
{
if(!vsystem_)
Copy link
Member

Choose a reason for hiding this comment

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

This file and others do not follow our coding style. please use the provided .clang-format configuration

Copy link
Member Author

Choose a reason for hiding this comment

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

Was not aware of clang format style. Used the following before committing changes:

clang-format --style=file --verbose src/fault/Fault.cpp src/fault/Action.cpp include/etiss/fault/Action.h \
include/etiss/fault/Fault.h include/etiss/fault/Trigger.h src/fault/Trigger.cpp src/fault/Stressor.cpp \
include/etiss/fault/Injector.h src/VirtualStruct.cpp include/etiss/VirtualStruct.h src/fault/InjectorAddress.cpp \
include/etiss/fault/InjectorAddress.h include/etiss/fault/Stressor.h src/fault/Injector.cpp -i

split_cmd.push_back(cmd);
if (split_cmd.size() > 1)
{
std::stringstream ss;
Copy link
Member

Choose a reason for hiding this comment

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

std::stoll would make this less verbose and more robust

Copy link
Member Author

Choose a reason for hiding this comment

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

would prefer boost::lexical_cast over std::sto*, but either over std::stringstream. Fixed with 459ac53

find = fieldPrettyNames_.find(field);
if (find == fieldPrettyNames_.end())
{
f = 0;
Copy link
Member

Choose a reason for hiding this comment

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

is already set

Copy link
Member Author

Choose a reason for hiding this comment

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

hello copy paste my old friend... Fixed with c8f9478

Copy link
Member

Choose a reason for hiding this comment

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

not sure if that fix is correct. the line you removed was searching a different list. what i meant is that f is already initialized to null at the start of the function, so this assignment is redundant and the conditional block can be dropped.

Copy link
Member Author

Choose a reason for hiding this comment

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

you are right. reversed and fixed with c86cb7f

{
return type_;
}

const InjectorAddress &Action::getInjectorAddress() const
{
if(unlikely(!(type_ == Type::BITFLIP || type_ == Type::MASK || type_ == Type::COMMAND)))
Copy link
Member

Choose a reason for hiding this comment

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

unless they are measurably important for performance, i'd perfer to avoid the un/likely clutter

Copy link
Member Author

Choose a reason for hiding this comment

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

agreed. From old code base, but the getters are not performance critical. Fixed with b6da677

Trigger::Trigger(const Trigger &sub, uint64_t count)
: type_(META_COUNTER), sub_(new Trigger(sub)), param1_(count), param2_(0)
: type_(Type::META_COUNTER)
, sub_(new Trigger(sub))
Copy link
Member

Choose a reason for hiding this comment

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

should be unique_ptr + make_unique

Copy link
Member Author

Choose a reason for hiding this comment

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

agreed. Also old code base not really up to date with current coding style. Fixed with 909d74e and 746b340 (remove wild inclusion style)

: type_(Type::META_COUNTER)
, sub_(new Trigger(sub))
, param1_(count)
, param2_(0)
Copy link
Member

Choose a reason for hiding this comment

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

there are many uninitialized fields in these constructors. maybe just default initialize them in the class definition

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed with 909d74e


private: // Attributes
type_t type_; ///< type of the Attribute
std::unique_ptr<InjectorAddress> inj_{ nullptr }; ///< Address of Injector
Copy link
Member

Choose a reason for hiding this comment

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

for unique_ptr and string the initialization is redundant

Copy link
Member Author

Choose a reason for hiding this comment

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

////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Action type class
template <typename enum_t>
class SmartType : public etiss::ToString
Copy link
Member

Choose a reason for hiding this comment

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

this seems nice, but as implemented a bit weak: you still have to manually set up the table causing code duplication and potential for errors. the error handling is inconsistent between from/toString - one returns bool, the other throws. a lot of code could be constant evaluated. outdated docstrings

i think it makes sense to just use an existing solution for this problem. for example i found this: https://github.com/aantron/better-enums

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, I understand these concerns. I had this laying around for when I needed string->enum and enum->string encoding as we need here for all the from and to xml stuff going on in ETISS-FI.
The better-enums seems perfect, but would need a third party integration of it in ETISS, which I would like to avoid in this PR. I'd even suggest to add a /third_party/ directory to ETISS root to easier integrate such things - either through git submodules or CMake fetch. Otherwise we end up with missing copyright/licenses and pasted source code like we already have here:

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed with 5e795d7

Fault(int nullid);
Fault(const Fault &cpy);
Fault &operator=(const Fault &cpy);
#if CXX0X_UP_SUPPORTED
Copy link
Member

Choose a reason for hiding this comment

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

these can be removed, because we now support c++14

Copy link
Member Author

Choose a reason for hiding this comment

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

volatile bool has_pending_triggers;
std::list<std::pair<Trigger, int32_t>> pending_triggers; ///> Triggers which were just added
std::list<std::pair<Trigger, int32_t>> unknown_triggers; ///> Triggers to look at in callbacks
volatile bool has_pending_triggers{false};
Copy link
Member

Choose a reason for hiding this comment

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

why are these volatile? if thread-safety is intended, this will not work. an atomic would be required

Copy link
Member Author

Choose a reason for hiding this comment

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

I do not know either. I removed them for now fba85d5

find = fieldPrettyNames_.find(field);
if (find == fieldPrettyNames_.end())
{
f = 0;
Copy link
Member

Choose a reason for hiding this comment

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

not sure if that fix is correct. the line you removed was searching a different list. what i meant is that f is already initialized to null at the start of the function, so this assignment is redundant and the conditional block can be dropped.

switch (type_)
{
case Type::BITFLIP:
inj_ = std::make_unique<InjectorAddress>(cpy.getInjectorAddress());
Copy link
Member

Choose a reason for hiding this comment

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

it is not clear to me why you made inj_ pointers. could they not just be value types so that this copy becomes a trivial "=default"?

Copy link
Member Author

@JoGei JoGei Dec 6, 2021

Choose a reason for hiding this comment

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

Unfortunately not so easily.
For example in Stressor::firedTrigger:

        for (std::vector<etiss::fault::Action>::iterator iter = find->second.actions.begin();
             iter != find->second.actions.end(); ++iter)
        {
...
            default: // on field actions
            {
                if (iter->getInjectorAddress().getInjector())

The inj_ member of Action is used to decide whether the Action may run through this Injector or is legal in the first place. The check is whether the member was set. Without major changes to most of the old fault injection stuff, I can not re-use most of it. All this FI code is way older than this open source repository. I do not even know who wrote it initially.

The idea behind this PR was to make the FI usable again, seems to take a lot more work to make the code up to date than the functionality.

The Action and Trigger classes both are built similar in that their instances have uninitialized members depending on their respective type_. Obviously, this could be done much better through different design patterns, but such major changes were not initially the idea behind this PR. If you think such a refactoring process is a must, I can start with it.


Fault::Fault(int nullid) : id_(nullid) {}

Fault::Fault(const Fault &cpy)
Copy link
Member

Choose a reason for hiding this comment

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

these copy/move constr/assign are equivalent to the default

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. Was not aware of the main CMakeLists.txt already forcing c++14
eff549b

#if CXX0X_UP_SUPPORTED
std::lock_guard<std::mutex> lock(sync);
#endif
for (const auto &rm : remove_triggers)
Copy link
Member

Choose a reason for hiding this comment

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

could use erase-remove idiom

auto shouldRemove = [&](auto elem){
    return std::find(b.begin(), b.end(), elem) != b.end();
};
a.erase(std::remove_if(a.begin(), a.end(), shouldRemove), a.end());

otherwise the typical pattern uses a while loop and iter=a.erase(iter);

Copy link
Member Author

Choose a reason for hiding this comment

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

@rafzi
Copy link
Member

rafzi commented Dec 7, 2021

thanks for the justifications, but please don't feel obligated to address all of my comments. as i said, this would have been fine to merge on the first iteration. just noted some stuff that caught my eye

JoGei added 25 commits June 30, 2022 12:12
… of VirtualStruct require it being mounted with an instance of CPUCore::getStruct(). Move 'faults.xml' configuration resolve from etiss::initialize to initialize_virtual (requires mounted VirtualStruct). Add 'faults.xml' configuration as command line parameter. Make VirtualStruct::Field::flags_ member a non-const to allow runtime configuration of access type.
…ger[lock mutex]->Stresser::addFault[lock mutex]
…initialize_virtualstruct call. Add WIP: Fault Injection How-To to examples/bare_etiss_processor/README.md and example `fault.xml` file for better reference.
… fault injection flag of a field will be set if a fault for the field is configured through Stressor. Add "MASK" fault as Action. A Mask fault has a mask operation <op> (and, or, xor, nand, nor) and a mask value <value> (64-bit) acting on a <field>: "<field> = <field> <op> <value>"
…om xml).

Add event type to <action> types which allows to inject ETISS simulation 
events (all ETISS::RETURNCODES), e.g., to flush translation cache.
Minor fixes in mask type <action>
…instructionAccurateCallback() to trigger on next trigger check.

Update Trigger typing code.
…ication of mounted structs.

Minor typo fixes.
…actions from fault injection. Extends SimpleMemSystem.
…xplicitly added through a fault's INJECTION action or through the <initial> node in given XML,

add EJECTION action that deactivates all triggers of the referenced 
fault,
disable automatic removal of a trigger once it was fired to allow 
permanent faults - remove triggers (therefore the fault) through 
EJECTION action of a referenced fault,
extend faults.xml example and readme section w.r.t. new features.
@JoGei JoGei force-pushed the rev_faultinjection branch from b57f159 to 1d6f2d7 Compare June 30, 2022 11:08
@JoGei JoGei marked this pull request as ready for review December 16, 2022 13:21
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