1 # SPDX-License-Identifier: BSD-3-Clause
2 # Copyright 2018-2020, Intel Corporation
4 import memoryoperations
as memops
6 from reorderexceptions
import InconsistentFileException
7 from reorderexceptions
import NotSupportedOperationException
12 The base class of all states.
14 :ivar _context: The reordering context.
15 :type _context: opscontext.OpsContext
16 :ivar trans_stores: The list of unflushed stores.
17 :type trans_stores: list of :class:`memoryoperations.Store`
21 def __init__(self
, context
):
23 Default state constructor.
25 :param context: The context of the reordering.
26 :type context: opscontext.OpsContext
28 self
._context
= context
30 def next(self
, in_op
):
32 Go to the next state based on the input.
35 The next state might in fact be the same state.
37 :param in_op: The state switch trigger operation.
38 :type in_op: subclass of :class:`memoryoperations.BaseOperation`
39 :return: The next state.
40 :rtype: subclass of :class:`State`
42 raise NotImplementedError
46 Perform the required operation in this state.
48 :param in_op: The operation to be performed in this state.
49 :type in_op: subclass of :class:`memoryoperations.BaseOperation`
52 raise NotImplementedError
55 class InitState(State
):
57 The initial no-op state.
59 def __init__(self
, context
):
61 Saves the reordering context.
63 :param context: The reordering context.
64 :type context: opscontext.OpsContext
66 super(InitState
, self
).__init
__(context
)
68 def next(self
, in_op
):
70 Switch to the next valid state.
72 :param in_op: Ignored.
73 :return: The next valid state.
74 :rtype: CollectingState
76 return CollectingState(self
._context
)
82 :param in_op: Ignored.
88 class CollectingState(State
):
90 Collects appropriate operations.
92 This state mostly aggregates stores and flushes. It also
93 validates which stores will be made persistent and passes
94 them on to the next state.
96 :ivar _ops_list: The list of collected stores.
97 :type _ops_list: list of :class:`memoryoperations.Store`
98 :ivar _inner_state: The internal state of operations.
99 :type _inner_state: str
101 def __init__(self
, context
):
103 Saves the reordering context.
105 :param context: The reordering context.
106 :type context: opscontext.OpsContext
108 super(CollectingState
, self
).__init
__(context
)
110 self
._ops
_list
+= State
.trans_stores
111 self
._inner
_state
= "init"
113 def next(self
, in_op
):
115 Switch to the next valid state.
117 :param in_op: The state switch trigger operation.
118 :type in_op: subclass of :class:`memoryoperations.BaseOperation`
119 :return: The next state.
120 :rtype: subclass of :class:`State`
122 if isinstance(in_op
, memops
.Fence
) and \
123 self
._inner
_state
== "flush":
124 return ReplayingState(self
._ops
_list
, self
._context
)
128 def run(self
, in_op
):
130 Perform operations in this state.
132 Based on the type of operation, different handling is employed.
133 The recognized and handled types of operations are:
135 * :class:`memoryoperations.ReorderBase`
136 * :class:`memoryoperations.FlushBase`
137 * :class:`memoryoperations.Store`
138 * :class:`memoryoperations.Register_file`
140 :param in_op: The operation to be performed in this state.
141 :type in_op: subclass of :class:`memoryoperations.BaseOperation`
144 self
.move_inner_state(in_op
)
145 if isinstance(in_op
, memops
.ReorderBase
):
146 self
.substitute_reorder(in_op
)
147 elif isinstance(in_op
, memops
.FlushBase
):
148 self
.flush_stores(in_op
)
149 elif isinstance(in_op
, memops
.Store
):
150 self
._ops
_list
.append(in_op
)
151 elif isinstance(in_op
, memops
.Register_file
):
156 def substitute_reorder(self
, order_ops
):
158 Changes the reordering engine based on the log marker class.
160 :param order_ops: The reordering marker class.
161 :type order_ops: subclass of :class:`memoryoperations.ReorderBase`
164 if isinstance(order_ops
, memops
.ReorderFull
):
165 self
._context
.reorder_engine
= \
166 reorderengines
.FullReorderEngine()
167 self
._context
.test_on_barrier
= \
168 self
._context
.reorder_engine
.test_on_barrier
169 elif isinstance(order_ops
, memops
.ReorderPartial
):
170 # TODO add macro in valgrind or
171 # parameter inside the tool to support parameters?
172 self
._context
.reorder_engine
= \
173 reorderengines
.RandomPartialReorderEngine(3)
174 self
._context
.test_on_barrier
= \
175 self
._context
.reorder_engine
.test_on_barrier
176 elif isinstance(order_ops
, memops
.ReorderAccumulative
):
177 self
._context
.reorder_engine
= \
178 reorderengines
.AccumulativeReorderEngine()
179 self
._context
.test_on_barrier
= \
180 self
._context
.reorder_engine
.test_on_barrier
181 elif isinstance(order_ops
, memops
.ReorderReverseAccumulative
):
182 self
._context
.reorder_engine
= \
183 reorderengines
.AccumulativeReverseReorderEngine()
184 self
._context
.test_on_barrier
= \
185 self
._context
.reorder_engine
.test_on_barrier
186 elif isinstance(order_ops
, memops
.NoReorderDoCheck
):
187 self
._context
.reorder_engine
= reorderengines
.NoReorderEngine()
188 self
._context
.test_on_barrier
= \
189 self
._context
.reorder_engine
.test_on_barrier
190 elif isinstance(order_ops
, memops
.NoReorderNoCheck
):
191 self
._context
.reorder_engine
= reorderengines
.NoCheckerEngine()
192 self
._context
.test_on_barrier
= \
193 self
._context
.reorder_engine
.test_on_barrier
194 elif isinstance(order_ops
, memops
.ReorderDefault
):
195 self
._context
.reorder_engine
= self
._context
.default_engine
196 self
._context
.test_on_barrier
= self
._context
.default_barrier
198 raise NotSupportedOperationException(
199 "Not supported reorder engine: {}"
202 def flush_stores(self
, flush_op
):
204 Marks appropriate stores as flushed.
206 Does not align the flush, the log is expected to have the
207 flushes properly aligned.
209 :param flush_op: The flush operation marker.
210 :type flush_op: subclass of :class:`memoryoperations.FlushBase`
213 for st
in self
._ops
_list
:
214 if flush_op
.is_in_flush(st
):
217 def reg_file(self
, file_op
):
219 Register a new file mapped into virtual memory.
221 :param file_op: File registration operation marker.
222 :type file_op: memoryoperations.Register_file
225 self
._context
.file_handler
.add_file(file_op
.name
,
229 def move_inner_state(self
, in_op
):
231 Tracks the internal state of the collection.
233 The collected stores need to be processed only at specific moments -
234 after full persistent memory barriers (flush-fence).
236 :param in_op: The performed operation.
237 :type in_op: subclass of :class:`memoryoperations.BaseOperation`
240 if isinstance(in_op
, memops
.Store
) and \
241 self
._inner
_state
== "init":
242 self
._inner
_state
= "dirty"
243 elif isinstance(in_op
, memops
.FlushBase
) and \
244 self
._inner
_state
== "dirty":
245 self
._inner
_state
= "flush"
246 elif isinstance(in_op
, memops
.Fence
) and \
247 self
._inner
_state
== "flush":
248 self
._inner
_state
= "fence"
249 elif isinstance(in_op
, memops
.Flush
) and \
250 self
._inner
_state
== "init":
251 self
._inner
_state
= "flush"
254 class ReplayingState(State
):
256 Replays all collected stores according to the reordering context.
258 :ivar _ops_list: The list of stores to be reordered and replayed.
259 :type _ops_list: list of :class:`memoryoperations.Store`
261 def __init__(self
, in_ops_list
, context
):
268 super(ReplayingState
, self
).__init
__(context
)
269 self
._ops
_list
= in_ops_list
271 def next(self
, in_op
):
273 Switches to the collecting state regardless of the input.
275 :param in_op: Ignored.
276 :type in_op: subclass of :class:`memoryoperations.BaseOperation`
277 :return: The next state.
278 :rtype: CollectingState
280 return CollectingState(self
._context
)
282 def run(self
, in_op
):
284 Perform operations in this state.
286 The replaying state performs reordering and if necessary checks
287 the consistency of the registered files. The decisions and
288 type of reordering to be used is defined by the context.
290 :param in_op: The operation to be performed in this state.
291 :type in_op: subclass of :class:`memoryoperations.BaseOperation`
292 :return: State of consistency check.
294 # specifies consistency state of sequence
297 # consider only flushed stores
298 flushed_stores
= list(filter(lambda x
: x
.flushed
, self
._ops
_list
))
300 # not-flushed stores should be passed to next state
301 State
.trans_stores
= list(filter(lambda x
: x
.flushed
is False,
304 if self
._context
.test_on_barrier
:
305 for seq
in self
._context
.reorder_engine
.generate_sequence(
309 self
._context
.file_handler
.do_store(op
)
310 # check consistency of all files
312 self
._context
.file_handler
.check_consistency()
313 except InconsistentFileException
as e
:
315 self
._context
.logger
.warning(e
)
316 stacktrace
= "Call trace:\n"
317 for num
, op
in enumerate(seq
):
318 stacktrace
+= "Store [{}]:\n".format(num
)
319 stacktrace
+= str(op
.trace
)
320 self
._context
.logger
.warning(stacktrace
)
322 for op
in reversed(seq
):
324 self
._context
.file_handler
.do_revert(op
)
325 # write all flushed stores
326 for op
in flushed_stores
:
327 self
._context
.file_handler
.do_store(op
)
334 The state machine driver.
336 :ivar _curr_state: The current state.
337 :type _curr_state: subclass of :class:`State`
339 def __init__(self
, init_state
):
341 Initialize the state machine with a specified state.
343 :param init_state: The initial state to be used.
344 :type init_state: subclass of :class:`State`
346 self
._curr
_state
= init_state
348 def run_all(self
, operations
):
350 Starts the state machine.
352 :param operations: The operations to be performed by the state
354 :type operations: list of :class:`memoryoperations.BaseOperation`
357 all_consistent
= True
358 for ops
in operations
:
359 self
._curr
_state
= self
._curr
_state
.next(ops
)
360 check
= self
._curr
_state
.run(ops
)
362 all_consistent
= check
364 return all_consistent