ETISS 0.11.2
ExtendableTranslatingInstructionSetSimulator(version0.11.2)
Loading...
Searching...
No Matches
Trigger.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2//
3// This file is part of ETISS. It is licensed under the BSD 3-Clause License; you may not use this file except in
4// compliance with the License. You should have received a copy of the license along with this project. If not, see the
5// LICENSE file.
6
7#ifndef NO_ETISS
8#include "etiss/fault/XML.h"
12#include "etiss/fault/Fault.h"
13#include "etiss/Misc.h"
14#else
15#include "fault/XML.h"
16#include "fault/Trigger.h"
17#include "fault/Injector.h"
19#include "fault/Fault.h"
20#endif
21
22#include <iostream>
23
24namespace etiss
25{
26
27namespace fault
28{
29
30void Trigger::ensure(type_t type) const
31{
32 if (type_ != type)
33 {
34 etiss::log(etiss::FATALERROR, std::string("etiss::fault::Trigger::ensure: Type mismatch type=") +
35 type._to_string() + " type_=" + type_._to_string());
36 throw "called function of different trigger type";
37 }
38}
39
40Trigger::Trigger() : type_(type_t::NOP)
41{
42 etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (NOP)"));
43}
44
45Trigger::Trigger(const InjectorAddress &target_injector)
46 : type_(type_t::ASAP), inj_(std::make_unique<InjectorAddress>(target_injector))
47{
49 std::string("etiss::fault::Trigger::Trigger(const InjectorAddress &target_injector) : type_ (ASAP)"));
50}
51
53 : type_(type_t::META_COUNTER), sub_(new Trigger(sub)), param1_(count), param2_(0)
54{
55 etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (META_COUNTER)"));
56}
57Trigger::Trigger(const InjectorAddress &target_injector, const std::string &field, uint64_t value)
58 : type_(type_t::VARIABLEVALUE)
59 , field_(field)
60 , inj_(std::make_unique<InjectorAddress>(target_injector))
61 , fieldptr_(0)
62 , param1_(value)
63{
64 etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (VARIABLEVALUE)"));
65}
66Trigger::Trigger(const InjectorAddress &target_injector, uint64_t time_ps, bool relative)
67 : type_(relative ? type_t::TIMERELATIVE : type_t::TIME)
68 , inj_(std::make_unique<InjectorAddress>(target_injector))
69 , param1_(time_ps)
70 , param2_(0)
71{
72 relative ? etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (TIMERELATIVE)"))
73 : etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::Trigger() : type_ (TIME)"));
74}
75
76Trigger::Trigger(const Trigger &cpy) : type_(type_t::NOP)
77{
78 *this = cpy;
79}
80
82{
83 if (type_ == +type_t::VARIABLEVALUE)
84 {
85 if (inj_->isResolved() && fieldptr_)
86 {
87 inj_->getInjector()->freeFastFieldAccessPtr(fieldptr_);
88 }
89 }
90 type_ = cpy.type_;
91 switch (type_)
92 {
93 case type_t::META_COUNTER:
94 sub_ = std::make_unique<Trigger>(cpy.getSubTrigger());
95 param1_ = cpy.param1_;
96 param2_ = cpy.param2_;
97 break;
98 case type_t::VARIABLEVALUE:
99 field_ = cpy.field_;
100 inj_ = std::make_unique<InjectorAddress>(cpy.getInjectorAddress());
101 fieldptr_ = 0;
102 param1_ = cpy.param1_;
103 break;
104 case type_t::TIMERELATIVE:
105 [[fallthrough]];
106 case type_t::TIME:
107 inj_ = std::make_unique<InjectorAddress>(cpy.getInjectorAddress());
108 param1_ = cpy.param1_;
109 param2_ = cpy.param2_;
110 break;
111 case type_t::ASAP:
112 inj_ = std::make_unique<InjectorAddress>(cpy.getInjectorAddress());
113 break;
114 case type_t::NOP:
115 break;
116 }
117 return *this;
118}
119
120#if CXX0X_UP_SUPPORTED
121Trigger::Trigger(Trigger &&cpy) : type_(cpy.getType())
122{
123 operator=(cpy);
124}
125Trigger &Trigger::operator=(Trigger &&cpy)
126{
127 operator=((const Trigger &)cpy);
128 return *this;
129}
130#endif
131
133{
134 if (type_ == +type_t::VARIABLEVALUE)
135 {
136 if (inj_->isResolved() && fieldptr_)
137 {
138 inj_->getInjector()->freeFastFieldAccessPtr(fieldptr_);
139 }
140 }
141}
142
143bool Trigger::check(uint64_t time_ps, etiss::fault::Injector *target_injector)
144{
145 etiss::log(etiss::VERBOSE, std::string("etiss::fault::Trigger::check(time_ps=") + std::to_string(time_ps) +
146 std::string(", Injector*)"));
147 switch (type_)
148 {
149 case type_t::META_COUNTER:
150 {
151 if (sub_->check(time_ps, target_injector))
152 {
153 ++param2_; // increase count
154 if (param1_ == param2_)
155 {
156 return true; // count reached -> fire event
157 }
158 }
159 break;
160 }
161 case type_t::VARIABLEVALUE:
162 {
163 if (fieldptr_ == 0)
164 {
165 std::string errmsg;
166 fieldptr_ = target_injector->fastFieldAccessPtr(field_, errmsg);
167 if (fieldptr_ == 0)
168 {
169#ifdef NO_ETISS
170 std::cout << "Trigger::check: Failed to get field" << std::endl;
171#else
172 etiss::log(etiss::ERROR, "Trigger::check: Failed to get field", *this);
173#endif
174 return false;
175 }
176 }
177 uint64_t val = 0;
178 std::string errmsg;
179 if (inj_->getInjector())
180 {
181 if (!inj_->getInjector()->readField(fieldptr_, val, errmsg))
182 {
183#ifdef NO_ETISS
184 std::cout << "Trigger::check: Failed to read field: " << errmsg << std::endl;
185#else
186 etiss::log(etiss::ERROR, "Trigger::check: Failed to get field", *this, errmsg);
187#endif
188 return false;
189 }
190 }
191 else
192 {
193#ifdef NO_ETISS
194 std::cout << "Trigger::check: Failed get injector: " << inj_->getInjectorPath() << std::endl;
195#else
196 etiss::log(etiss::ERROR, "Trigger::check: Failed get injector", *this, *inj_);
197#endif
198 }
199 return val == param1_;
200 }
201 case type_t::TIMERELATIVE:
202 {
203 etiss::log(etiss::WARNING, "Trigger::fired: Unresolved TIMERELATIVE - resolving now", *this, *inj_);
204 resolveTime(time_ps);
205 [[fallthrough]];
206 }
207 case type_t::TIME:
208 {
209 /* TODO: Why doing it like this ? this would always fire after time_ps has reached */
210 // Possibly because might be called not exaclty but later than excact trigger time, then late triggering should
211 // be done
212
213 // if (time_ps >= param1_ && param2_ <= time_ps)
214 if (param1_ <= time_ps && param2_ == 0) // testing alternative param2_ says if trigger has already fired
215 {
217 // param2_ = time_ps+1;
218 param2_ = 1; // testing alternative: param2_ says if trigger has already fired
219 return true;
220 }
221 // param2_ = time_ps;
222 // testing alternative param2_ says if trigger has already fired
223
224 // DO NOT DO IT LIKE THIS, MIGHT NOT BE CALLED EXACTLY WITH TIME OF TRIGGER
225 // if (time_ps == param1_)
226 // return true;
227 break;
228 }
229 case type_t::ASAP:
230 {
231 return true; // as soon as possible means on next check
232 }
233 case type_t::NOP:
234 {
235 return true;
236 }
237 }
238
239 return false;
240}
241
243{
245 std::string("etiss::fault::Trigger::resolveTime(time=") + std::to_string(time) + std::string(")"));
246 if (type_ == +type_t::TIMERELATIVE)
247 {
248 type_ = type_t::TIME;
249 param1_ = param1_ + time;
250 }
251 else if (type_ == +type_t::META_COUNTER)
252 {
253 return sub_->resolveTime(time);
254 }
255}
257{
258 if (type_ == +type_t::META_COUNTER)
259 {
260 return sub_->isResolved();
261 }
262 return type_ != +type_t::TIMERELATIVE;
263}
264
266{
267 ensure(type_t::META_COUNTER);
268 return param1_;
269}
270
272{
273 ensure(type_t::META_COUNTER);
274 return *sub_;
275}
276
278{
279 if (type_ == +type_t::META_COUNTER)
280 {
281 return sub_->getTriggerTime();
282 }
283 try
284 {
285 ensure(type_t::TIME);
286 }
287 catch (char const *)
288 {
289 ensure(type_t::TIMERELATIVE);
290 }
291 return param1_;
292}
293
295{
296 return *inj_;
297}
298
300{
301 if (type_ == +type_t::META_COUNTER)
302 {
303 return sub_->getInjector();
304 }
305 else
306 {
307 return inj_->getInjector();
308 }
309}
310
311bool Trigger::isNOP() const
312{
313 if (type_ == +type_t::META_COUNTER)
314 {
315 return sub_->isNOP();
316 }
317 else
318 {
319 return type_ == +type_t::NOP;
320 }
321}
322
323const std::string &Trigger::getTriggerField() const
324{
325 // std::cout << "Trigger::getTriggerField() called" << std::endl;
326 if (type_ == +type_t::META_COUNTER)
327 {
328 return sub_->getTriggerField();
329 }
330 ensure(type_t::VARIABLEVALUE);
331 return field_;
332}
333
335{
336 // std::cout << "Trigger::getTriggerFieldValue() called" << std::endl;
337 if (type_ == +type_t::META_COUNTER)
338 {
339 return sub_->getTriggerFieldValue();
340 }
341 ensure(type_t::VARIABLEVALUE);
342 return param1_;
343}
344
346{
347 return type_;
348}
349
350std::string Trigger::toString() const
351{
352 std::stringstream ss;
353 ss << "Trigger { type=" << type_;
354 switch (type_)
355 {
356 case type_t::META_COUNTER:
357 ss << " triggerCount=" << +param1_ << " currentCount=" << +param2_;
358 break;
359 case type_t::VARIABLEVALUE:
360 ss << " field=" << field_ << " triggerValue=" << +param1_;
361 break;
362 case type_t::TIMERELATIVE:
363 [[fallthrough]];
364 case type_t::TIME:
365 ss << " triggerTime=" << +param1_;
366 break;
367 default:
368 break;
369 }
370 ss << "}";
371 return ss.str();
372}
373
374#if ETISS_FAULT_XML
375namespace xml
376{
377template <>
378bool parse<etiss::fault::Trigger *>(pugi::xml_node node, etiss::fault::Trigger *&f, Diagnostics &diag)
379{
380 etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::parse<etiss::fault::Trigger*>") +
381 std::string("(node, Trigger*&, Diagnostics)"));
382 f = 0;
383 std::string type_s;
384 if (!parse_attr(node, "type", type_s, diag))
385 {
386 return false;
387 }
388
389 if (!Trigger::type_t::_from_string_nothrow(type_s.c_str()))
390 {
391 diag.unexpectedNode(node, std::string("There is no Trigger type ") + type_s);
392 return false;
393 }
394 auto type = Trigger::type_t::_from_string(type_s.c_str());
395
396 switch (type)
397 {
398 case Trigger::type_t::META_COUNTER:
399 {
400 uint64_t count;
401 if (!parse<uint64_t>(findSingleNode(node, "count", diag), count, diag))
402 {
403 return false;
404 }
405 etiss::fault::Trigger *sub = 0;
406 if ((!parse<etiss::fault::Trigger *>(findSingleNode(node, "trigger", diag), sub, diag)) || (sub == 0))
407 {
408 diag.unexpectedNode(node, "Failed to parse sub trigger");
409 return false;
410 }
411 f = new etiss::fault::Trigger(*sub, count);
412 delete sub;
413 return true;
414 }
415
416 case Trigger::type_t::VARIABLEVALUE:
417 {
418 uint64_t value;
419 if (!parse_hex(findSingleNode(node, "value", diag), value, diag))
420 {
421 return false;
422 }
423 std::string field;
424 if (!parse<std::string>(findSingleNode(node, "field", diag), field, diag))
425 {
426 return false;
427 }
428 setCoreName(field);
430 if (!parse<etiss::fault::InjectorAddress>(findSingleNode(node, "injector", diag), injector, diag))
431 {
432 return false;
433 }
434 f = new Trigger(injector, field, value);
435 return true;
436 }
437
438 case Trigger::type_t::TIME:
439 {
440 uint64_t count;
441 if (!parse<uint64_t>(findSingleNode(node, "time_ps", diag), count, diag))
442 {
443 return false;
445 }
447 if (!parse<etiss::fault::InjectorAddress>(findSingleNode(node, "injector", diag), injector, diag))
448 {
449 return false;
450 }
451 f = new Trigger(injector, count);
452 return true;
453 }
454
455 case Trigger::type_t::TIMERELATIVE:
456 {
457 uint64_t count;
458 if (!parse<uint64_t>(findSingleNode(node, "time_ps", diag), count, diag))
459 {
460 return false;
462 }
464 if (!parse<etiss::fault::InjectorAddress>(findSingleNode(node, "injector", diag), injector, diag))
465 {
466 return false;
467 }
468 f = new Trigger(injector, count, true);
469 etiss::log(etiss::VERBOSE, std::string("Injector2: ") + f->getInjectorAddress().getInjectorPath());
470 return true;
471 }
472
473 case Trigger::type_t::ASAP:
474 {
476 if (!parse<etiss::fault::InjectorAddress>(findSingleNode(node, "injector", diag), injector, diag))
477 {
478 return false;
479 }
480 f = new Trigger(injector);
481 return true;
482 }
483 default: // NOP
484 {
485 f = new Trigger();
486 return true;
487 }
488 }
489 return false;
490}
491template <>
492bool write<const etiss::fault::Trigger *>(pugi::xml_node node, const etiss::fault::Trigger *const &f, Diagnostics &diag)
493{
494 etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::write<etiss::fault::Trigger*>") +
495 std::string("(node, Trigger*&, Diagnostics)"));
496 if (f == 0)
497 return false;
498 return write<etiss::fault::Trigger>(node, *f, diag);
499}
500
501template <>
502bool parse<etiss::fault::Trigger>(pugi::xml_node node, etiss::fault::Trigger &f, Diagnostics &diag)
503{
504 etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::parse<etiss::fault::Trigger>") +
505 std::string("(node, Trigger&, Diagnostics)"));
507 if (!parse<etiss::fault::Trigger *>(node, t, diag))
508 return false;
509 f = *t;
510 delete t;
511 return true;
512}
513template <>
514bool write<Trigger>(pugi::xml_node node, const Trigger &f, Diagnostics &diag)
515{
516 etiss::log(etiss::VERBOSE, std::string("Called etiss::fault::xml::write<etiss::fault::Trigger>") +
517 std::string("(node, Trigger&, Diagnostics)"));
518
519 write_attr<std::string>(node, "type", f.getType()._to_string(), diag);
520 switch (f.getType())
521 {
522 case Trigger::type_t::META_COUNTER:
523 {
524 write<uint64_t>(node.append_child("count"), f.getTriggerCount(), diag);
525 write<Trigger>(node.append_child("trigger"), f.getSubTrigger(), diag);
526 }
527 return true;
528 case Trigger::type_t::VARIABLEVALUE:
529 {
530 write<std::string>(node.append_child("field"), f.getTriggerField(), diag);
531 write<uint64_t>(node.append_child("count"), f.getTriggerFieldValue(), diag);
532 Injector_ptr ptr = f.getInjector();
533 if (!ptr)
534 {
535 diag.errors.push_back("A fault trigger has no target_injector. failed to "
536 "get path of trigger");
537 return false;
538 }
539 write<std::string>(node.append_child("injector"), ptr->getInjectorPath(), diag);
540 }
541 return true;
542 case Trigger::type_t::TIME:
543 [[fallthrough]];
544 case Trigger::type_t::TIMERELATIVE:
545 {
546 write<uint64_t>(node.append_child("time_ps"), f.getTriggerTime(), diag);
547 Injector_ptr ptr = f.getInjector();
548 if (!ptr)
549 {
550 diag.errors.push_back("A fault trigger has no target_injector. failed to "
551 "get path of trigger");
552 return false;
553 }
554 write<std::string>(node.append_child("injector"), ptr->getInjectorPath(), diag);
555 return true;
556 }
557 case Trigger::type_t::ASAP:
558 [[fallthrough]];
559 case Trigger::type_t::NOP:
560 {
561 return true;
562 }
563 }
564
565 diag.errors.push_back("etiss::fault::xml::write<etiss::fault::Trigger> "
566 "encountered an unknown type of trigger");
567
568 return false;
569}
570
571} // namespace xml
572#endif
573
574} // namespace fault
575
576} // namespace etiss
contains the fault container class that stores triggers and actions for fault injection
contains a simple class that represents and resolves injector addresses as used by triggers (
contains the fault injector interface class.
general configuration and logging
contains the Trigger class that defines conditions under which actions of a Fault need to be applied.
contains XML related functions.
static __inline__ uint64_t
Definition arm_cde.h:31
const std::string & getInjectorPath() const
const Injector_ptr & getInjector() const
virtual void * fastFieldAccessPtr(const std::string &name, std::string &errormsg)=0
std::string toString() const
operator<< can be used.
Definition Trigger.cpp:350
const std::string & getTriggerField() const
Definition Trigger.cpp:323
const uint64_t & getTriggerFieldValue() const
Definition Trigger.cpp:334
uint64_t getTriggerCount() const
Definition Trigger.cpp:265
const Injector_ptr & getInjector() const
Definition Trigger.cpp:299
std::unique_ptr< Trigger > sub_
Definition Trigger.h:124
void ensure(type_t type) const
Definition Trigger.cpp:30
const type_t & getType() const
Definition Trigger.cpp:345
bool check(uint64_t time_ps, etiss::fault::Injector *target_injector)
this function checks if the Trigger has just fired.
Definition Trigger.cpp:143
const Trigger & getSubTrigger() const
Definition Trigger.cpp:271
const InjectorAddress & getInjectorAddress() const
Definition Trigger.cpp:294
std::unique_ptr< InjectorAddress > inj_
Definition Trigger.h:125
Trigger()
Type: NOP (no operation)
Definition Trigger.cpp:40
std::string field_
Definition Trigger.h:123
Trigger & operator=(const Trigger &cpy)
Definition Trigger.cpp:81
bool isNOP() const
Definition Trigger.cpp:311
Trigger_Type type_t
Definition Trigger.h:52
uint64_t getTriggerTime() const
Definition Trigger.cpp:277
bool isResolved() const
returns if the translation from TIMERELATIVE to TIME trigger has taken place
Definition Trigger.cpp:256
void resolveTime(uint64_t time)
this function calculates in case of a TIMERELATIVE Trigger a constant TIME trigger
Definition Trigger.cpp:242
void setCoreName(std::string &str)
Definition XML.cpp:26
std::shared_ptr< Injector > Injector_ptr
Definition Defs.h:48
forwards: include/jit/*
Definition Benchmark.h:17
@ VERBOSE
Definition Misc.h:88
@ WARNING
Definition Misc.h:86
@ ERROR
Definition Misc.h:85
@ FATALERROR
Definition Misc.h:84
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition Misc.cpp:94
STL namespace.