aboutsummaryrefslogtreecommitdiff
path: root/bart/sched/SchedMatrix.py
diff options
context:
space:
mode:
Diffstat (limited to 'bart/sched/SchedMatrix.py')
-rwxr-xr-xbart/sched/SchedMatrix.py292
1 files changed, 292 insertions, 0 deletions
diff --git a/bart/sched/SchedMatrix.py b/bart/sched/SchedMatrix.py
new file mode 100755
index 0000000..4595469
--- /dev/null
+++ b/bart/sched/SchedMatrix.py
@@ -0,0 +1,292 @@
+# Copyright 2015-2016 ARM Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+The SchedMatrix provides an ability to compare two executions
+of benchmarks with multiple processes.
+
+For example, consider a benchmark that spawns 4 identical threads
+and any two threads should exhibit a certain behaviours and the
+remaining another identical but different behaviour.
+
+SchedMatrix creates a Matrix of Scheduler Waveform Correlations
+
+A = Reference Execution
+B = Execution to be Evaluated
+
+.. code::
+
+ +---+ +---+
+ | | | |
+ A1, B3 +---+ +--+ +--------------+
+ +---+ +---+
+ | | | |
+ A2, B4 +--------------+ +--+ +---+
+ +---+ +---+
+ | | | |
+ A3, B1 +---+ +--+ +--------------+
+ +---+ +---+
+ | | | |
+ A4, B2 +--------------+ +--+ +---+
+
+
+**Correlation Matrix**
+
+ === ==== ==== ==== ====
+ B1 B2 B3 B4
+ === ==== ==== ==== ====
+ A1 1 0 1 0
+ A2 0 1 0 1
+ A3 1 0 1 0
+ A4 0 1 0 1
+ === ==== ==== ==== ====
+
+
+Thus a success criteria can be defined as A1 having two similar threads in the
+evaluated execution
+::
+
+ assertSiblings(A1, 2, operator.eq)
+ assertSiblings(A2, 2, operator.eq)
+ assertSiblings(A3, 2, operator.eq)
+ assertSiblings(A4, 2, operator.eq)
+"""
+
+
+import sys
+import trappy
+import numpy as np
+from trappy.stats.Aggregator import MultiTriggerAggregator
+from trappy.stats.Correlator import Correlator
+from bart.sched import functions as sched_funcs
+from bart.common import Utils
+
+POSITIVE_TOLERANCE = 0.80
+
+# pylint: disable=invalid-name
+# pylint: disable=too-many-arguments
+
+
+class SchedMatrix(object):
+
+ """
+ :param reference_trace: The trace file path/ftrace object
+ to be used as a reference
+ :type reference_trace: str, :mod:`trappy.ftrace.FTrace`
+
+ :param trace: The trace file path/ftrace object
+ to be verified
+ :type trace: str, :mod:`trappy.ftrace.FTrace`
+
+ :param topology: A topology that describes the arrangement of
+ CPU's on a system. This is useful for multi-cluster systems
+ where data needs to be aggregated at different topological
+ levels
+ :type topology: :mod:`trappy.stats.Topology.Topology`
+
+ :param execnames: The execnames of the task to be analysed
+
+ A single execname or a list of execnames can be passed.
+ There can be multiple processes associated with a single
+ execname parameter. The execnames are searched using a prefix
+ match.
+ :type execname: list, str
+
+ Consider the following processes which need to be analysed:
+
+ * **Reference Trace**
+
+ ===== ==============
+ PID execname
+ ===== ==============
+ 11 task_1
+ 22 task_2
+ 33 task_3
+ ===== ==============
+
+ * **Trace to be verified**
+
+ ===== ==============
+ PID execname
+ ===== ==============
+ 77 task_1
+ 88 task_2
+ 99 task_3
+ ===== ==============
+
+
+ A :mod:`bart.sched.SchedMatrix.SchedMatrix` instance be created
+ following different ways:
+
+ - Using execname prefix match
+ ::
+
+ SchedMatrix(r_trace, trace, topology,
+ execnames="task_")
+
+ - Individual Task names
+ ::
+
+ SchedMatrix(r_trace, trace, topology,
+ execnames=["task_1", "task_2", "task_3"])
+
+ """
+
+ def __init__(
+ self,
+ reference_trace,
+ trace,
+ topology,
+ execnames,
+ aggfunc=sched_funcs.csum):
+
+ run = Utils.init_ftrace(trace)
+ reference_run = Utils.init_ftrace(reference_trace)
+
+ self._execnames = Utils.listify(execnames)
+ self._reference_pids = self._populate_pids(reference_run)
+ self._pids = self._populate_pids(run)
+ self._dimension = len(self._pids)
+ self._topology = topology
+ self._matrix = self._generate_matrix(run, reference_run, aggfunc)
+
+ if len(self._pids) != len(self._reference_pids):
+ raise RuntimeError(
+ "The runs do not have the same number of PIDs for {0}".format(
+ str(execnames)))
+
+ def _populate_pids(self, run):
+ """Populate the qualifying PIDs from the run"""
+
+ if len(self._execnames) == 1:
+ return sched_funcs.get_pids_for_process(run, self._execnames[0])
+
+ pids = []
+
+ for proc in self._execnames:
+ pids += sched_funcs.get_pids_for_process(run, proc)
+
+ return list(set(pids))
+
+ def _generate_matrix(self, run, reference_run, aggfunc):
+ """Generate the Correlation Matrix"""
+
+ reference_aggs = []
+ aggs = []
+
+ for idx in range(self._dimension):
+
+ reference_aggs.append(
+ MultiTriggerAggregator(
+ sched_funcs.sched_triggers(
+ reference_run,
+ self._reference_pids[idx],
+ trappy.sched.SchedSwitch
+ ),
+ self._topology,
+ aggfunc))
+
+ aggs.append(
+ MultiTriggerAggregator(
+ sched_funcs.sched_triggers(
+ run,
+ self._pids[idx],
+ trappy.sched.SchedSwitch
+ ),
+ self._topology,
+ aggfunc))
+
+ agg_pair_gen = ((r_agg, agg)
+ for r_agg in reference_aggs for agg in aggs)
+
+ # pylint fails to recognize numpy members.
+ # pylint: disable=no-member
+ matrix = np.zeros((self._dimension, self._dimension))
+ # pylint: enable=no-member
+
+ for (ref_result, test_result) in agg_pair_gen:
+ i = reference_aggs.index(ref_result)
+ j = aggs.index(test_result)
+ corr = Correlator(
+ ref_result,
+ test_result,
+ corrfunc=sched_funcs.binary_correlate,
+ filter_gaps=True)
+ _, total = corr.correlate(level="cluster")
+
+ matrix[i][j] = total
+
+ return matrix
+
+ def print_matrix(self):
+ """Print the correlation matrix"""
+
+ # pylint fails to recognize numpy members.
+ # pylint: disable=no-member
+ np.set_printoptions(precision=5)
+ np.set_printoptions(suppress=False)
+ np.savetxt(sys.stdout, self._matrix, "%5.5f")
+ # pylint: enable=no-member
+
+ def getSiblings(self, pid, tolerance=POSITIVE_TOLERANCE):
+ """Return the number of processes in the
+ reference trace that have a correlation
+ greater than tolerance
+
+ :param pid: The PID of the process in the reference
+ trace
+ :type pid: int
+
+ :param tolerance: A correlation value > tolerance
+ will classify the resultant process as a sibling
+ :type tolerance: float
+
+ .. seealso:: :mod:`bart.sched.SchedMatrix.SchedMatrix.assertSiblings`
+ """
+
+ ref_pid_idx = self._reference_pids.index(pid)
+ pid_result = self._matrix[ref_pid_idx]
+ return len(pid_result[pid_result > tolerance])
+
+ def assertSiblings(self, pid, expected_value, operator,
+ tolerance=POSITIVE_TOLERANCE):
+ """Assert that the number of siblings in the reference
+ trace match the expected value and the operator
+
+ :param pid: The PID of the process in the reference
+ trace
+ :type pid: int
+
+ :param operator: A binary operator function that returns
+ a boolean. For example:
+ ::
+
+ import operator
+ op = operator.eq
+ getSiblings(pid, expected_value, op)
+
+ Will do the following check:
+ ::
+
+ getSiblings(pid) == expected_value
+
+ :param tolerance: A correlation value > tolerance
+ will classify the resultant process as a sibling
+ :type tolerance: float
+
+ .. seealso:: :mod:`bart.sched.SchedMatrix.SchedMatrix.getSiblings`
+ """
+ num_siblings = self.getSiblings(pid, tolerance)
+ return operator(num_siblings, expected_value)