diff --git a/.travis.yml b/.travis.yml index d671e87..8ed2c9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: python python: - - "2.7" + - "2.7.12" + - "3.4.8" before_install: - sudo apt-get update -qq - sudo apt-get install -qq libfreetype6-dev @@ -8,15 +9,12 @@ before_install: - wget http://ftp.us.debian.org/debian/pool/main/t/trace-cmd/trace-cmd_2.4.0-1_amd64.deb - sudo dpkg -i trace-cmd_2.4.0-1_amd64.deb install: - - pip install matplotlib - pip install Cython --install-option="--no-cython-compile" - - pip install pandas - - pip install hypothesis - - pip install ipython[all] - - pip install --upgrade trappy + # IPython 6.0.0 requires Python 3.3. Use an older version so we can keep using + # Python 2.7 + - pip install "ipython[all]<6.0.0" + - python ./setup.py install script: nosetests -virtualenv: - system_site_packages: true notifications: email: recipients: diff --git a/bart/__init__.py b/bart/__init__.py index 886dbc8..6996bd8 100644 --- a/bart/__init__.py +++ b/bart/__init__.py @@ -14,6 +14,9 @@ # """Initialization for bart""" +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function import bart.sched import bart.common diff --git a/bart/common/Analyzer.py b/bart/common/Analyzer.py index 7bb55c9..2193e02 100644 --- a/bart/common/Analyzer.py +++ b/bart/common/Analyzer.py @@ -18,7 +18,11 @@ also intended to have aggregator based functionality. This is not implemented yet. """ +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function +from builtins import object from trappy.stats.grammar import Parser import warnings import numpy as np diff --git a/bart/common/Utils.py b/bart/common/Utils.py index 034cf74..e81e763 100644 --- a/bart/common/Utils.py +++ b/bart/common/Utils.py @@ -14,7 +14,11 @@ # """Utility functions for sheye""" +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function +from past.builtins import basestring import trappy import numpy as np diff --git a/bart/common/__init__.py b/bart/common/__init__.py index f42522b..13577da 100644 --- a/bart/common/__init__.py +++ b/bart/common/__init__.py @@ -14,7 +14,9 @@ # """Initialization for bart.common""" - +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function from bart.common import Utils from bart.common import Analyzer diff --git a/bart/common/signal.py b/bart/common/signal.py index acf7091..d01bc87 100644 --- a/bart/common/signal.py +++ b/bart/common/signal.py @@ -45,7 +45,11 @@ - :code:`"trappy.event.class:event_column"` """ +from __future__ import division +from __future__ import unicode_literals +from __future__ import print_function +from builtins import object from trappy.stats.grammar import Parser from trappy.stats import StatConf from bart.common.Utils import area_under_curve, interval_sum diff --git a/bart/sched/SchedAssert.py b/bart/sched/SchedAssert.py index 5ecfec9..1a6a73b 100755 --- a/bart/sched/SchedAssert.py +++ b/bart/sched/SchedAssert.py @@ -18,7 +18,11 @@ The analysis is based on TRAPpy's statistics framework and is potent enough to aggregate statistics over processor hierarchies. """ +from __future__ import division +from __future__ import unicode_literals +from __future__ import print_function +from builtins import object import trappy import itertools import math diff --git a/bart/sched/SchedMatrix.py b/bart/sched/SchedMatrix.py index 4595469..aca791a 100755 --- a/bart/sched/SchedMatrix.py +++ b/bart/sched/SchedMatrix.py @@ -63,8 +63,13 @@ assertSiblings(A3, 2, operator.eq) assertSiblings(A4, 2, operator.eq) """ +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function - +from builtins import str +from builtins import range +from builtins import object import sys import trappy import numpy as np diff --git a/bart/sched/SchedMultiAssert.py b/bart/sched/SchedMultiAssert.py index 32ea17d..e9b189b 100755 --- a/bart/sched/SchedMultiAssert.py +++ b/bart/sched/SchedMultiAssert.py @@ -15,9 +15,14 @@ """A library for asserting scheduler scenarios based on the statistics aggregation framework""" +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function +from builtins import object import re import inspect +import functools import trappy from bart.sched import functions as sched_funcs from bart.sched.SchedAssert import SchedAssert @@ -176,21 +181,23 @@ def _populate_pids(self): return list(set(pids)) - def _create_method(self, attr_name): + def _create_method(self, attr, attr_name): """A wrapper function to create a dispatch function""" - return lambda *args, **kwargs: self._dispatch(attr_name, *args, **kwargs) + @functools.wraps(attr) + def wrapper(*args, **kwargs): + return self._dispatch(attr_name, *args, **kwargs) + + return wrapper def _populate_methods(self): """Populate Methods from SchedAssert""" - for attr_name in dir(SchedAssert): - attr = getattr(SchedAssert, attr_name) - + for attr_name, attr in inspect.getmembers(SchedAssert): valid_method = attr_name.startswith("get") or \ attr_name.startswith("assert") - if inspect.ismethod(attr) and valid_method: - func = self._create_method(attr_name) + if callable(attr) and valid_method: + func = self._create_method(attr, attr_name) setattr(self, attr_name, func) def get_task_name(self, pid): @@ -253,7 +260,7 @@ def getCPUBusyTime(self, level, node, window=None, percent=False): """ residencies = self.getResidency(level, node, window=window) - busy_time = sum(v["residency"] for v in residencies.itervalues()) + busy_time = sum(v["residency"] for v in residencies.values()) if percent: if window: diff --git a/bart/sched/__init__.py b/bart/sched/__init__.py index c0cc5c4..3ea83af 100644 --- a/bart/sched/__init__.py +++ b/bart/sched/__init__.py @@ -14,7 +14,9 @@ # """Initialization for bart.sched""" - +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function from bart.sched import SchedAssert from bart.sched import SchedMultiAssert diff --git a/bart/sched/functions.py b/bart/sched/functions.py index d1b17d4..9185f2f 100644 --- a/bart/sched/functions.py +++ b/bart/sched/functions.py @@ -56,6 +56,9 @@ .. seealso:: :mod:`trappy.stats.Topology.Topology` """ +from __future__ import division +from __future__ import unicode_literals +from __future__ import print_function import numpy as np from trappy.stats.Trigger import Trigger @@ -180,7 +183,7 @@ def filter_small_gaps(series): """ start = None - for index, value in series.iteritems(): + for index, value in series.items(): if value == SCHED_SWITCH_IN: if start == None: @@ -298,7 +301,7 @@ def residency_sum(series, window=None): running = select_window(org_series.cumsum(), window) if running.values[0] == TASK_RUNNING and running.values[-1] == TASK_RUNNING: return window[1] - window[0] - except Exception,e: + except Exception as e: pass if len(s_in) != len(s_out): @@ -433,7 +436,7 @@ def binary_correlate(series_x, series_y): agree = len(series_x[series_x == series_y]) disagree = len(series_x[series_x != series_y]) - return (agree - disagree) / float(len(series_x)) + return (agree - disagree) / len(series_x) def get_pids_for_process(ftrace, execname, cls=None): """Get the PIDs for a given process diff --git a/bart/sched/pelt.py b/bart/sched/pelt.py index ad5f88a..7ee2bde 100644 --- a/bart/sched/pelt.py +++ b/bart/sched/pelt.py @@ -31,7 +31,12 @@ behavior. Specifically, the Simulator requires also the PeriodicTask which signal has to be computed. """ +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function +from builtins import range +from builtins import object import math from collections import namedtuple as namedtuple @@ -143,8 +148,8 @@ def isRunning(self, time_ms): def __str__(self): return "PeriodicTask(start: {:.3f} [ms], period: {:.3f} [ms], run: {:.3f} [ms], "\ "duty_cycle: {:.3f} [%], pelt_avg: {:d})"\ - .format(self.start_us / 1e3, self.period_us / 1e3, - self.run_us / 1e3, self.duty_cycle_pct, + .format(self.start_us/1e3, self.period_us/1e3, + self.run_us/1e3, self.duty_cycle_pct, self.pelt_avg) @@ -249,7 +254,7 @@ def __init__(self, init_value=0, half_life_ms=32, decay_cap_ms=None): self.half_life_ms = half_life_ms self.decay_cap_ms = decay_cap_ms - self._geom_y = pow(0.5, 1. / half_life_ms) + self._geom_y = pow(0.5, 1 / half_life_ms) self._geom_u = float(self._signal_max) * (1. - self._geom_y) self.task = None @@ -313,7 +318,7 @@ def stableRange(self, task): raise ValueError("Wrong time for task parameter") def _to_pelt_samples(time_us): - return float(time_us) / self._sample_us + return time_us / self._sample_us # Compute max value max_pelt = (1. - pow(self._geom_y, _to_pelt_samples(task.run_us))) @@ -428,8 +433,7 @@ def getSignal(self, task, start_s=0, end_s=10): pelt_value = self._geomSum(pelt_value, active_us) # Append PELT sample - sample = (_us_to_s(t_us), t_us / - self._sample_us, running, pelt_value) + sample = (_us_to_s(t_us), t_us/self._sample_us, running, pelt_value) samples.append(sample) # Prepare for next sample computation @@ -537,7 +541,7 @@ def estimateInitialPeltValue(cls, first_val, first_event_time_s, :returns: int - Estimated value of PELT signal when the task starts """ - geom_y = pow(0.5, 1. / half_life_ms) + geom_y = pow(0.5, 1/half_life_ms) geom_u = float(cls._signal_max) * (1. - geom_y) # Compute period of time between when the task started and when the @@ -549,7 +553,7 @@ def estimateInitialPeltValue(cls, first_val, first_event_time_s, 'happens before the task starts') # Compute number of times the simulated PELT would be updated in this # period of time - updates_since_start = int(time_since_start / (cls._sample_us / 1e6)) + updates_since_start = int(time_since_start/(cls._sample_us/1e6)) pelt_val = first_val for i in range(updates_since_start): pelt_val = (pelt_val - geom_u) / geom_y @@ -588,8 +592,8 @@ def _s_to_us(time_s, interval_us=1e3, nearest_up=True): :type nearest_up: bool """ if nearest_up: - return interval_us * int(math.ceil((1e6 * time_s) / interval_us)) - return interval_us * int(math.floor((1e6 * time_s) / interval_us)) + return interval_us * int(math.ceil((1e6 * time_s)/interval_us)) + return interval_us * int(math.floor((1e6 * time_s)/interval_us)) def _ms_to_us(time_ms, interval_us=1e3, nearest_up=True): @@ -619,23 +623,23 @@ def _ms_to_us(time_ms, interval_us=1e3, nearest_up=True): :type nearest_up: bool """ if nearest_up: - return interval_us * int(math.ceil((1e3 * time_ms) / interval_us)) - return interval_us * int(math.floor((1e3 * time_ms) / interval_us)) + return interval_us * int(math.ceil((1e3 * time_ms)/interval_us)) + return interval_us * int(math.floor((1e3 * time_ms)/interval_us)) def _us_to_s(time_us): """Convert [us] into (float) [s] """ - return (float(time_us) / 1e6) + return time_us/1e6 def _us_to_ms(time_us): """Convert [us] into (float) [ms] """ - return (float(time_us) / 1e3) + return time_us/1e3 def _ms_to_s(time_ms): """Convert [ms] into (float) [s] """ - return (float(time_ms) / 1e3) + return time_ms/1e3 diff --git a/bart/thermal/ThermalAssert.py b/bart/thermal/ThermalAssert.py index d0ffa78..e9dbfd3 100644 --- a/bart/thermal/ThermalAssert.py +++ b/bart/thermal/ThermalAssert.py @@ -15,7 +15,11 @@ """A thermal specific library to assert certain thermal behaviours """ +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function +from builtins import object from bart.common import Utils from bart.common.Analyzer import Analyzer import numpy as np @@ -78,7 +82,7 @@ def getThermalResidency(self, temp_range, window, percent=False): if percent: result[pivot] = ( - result[pivot] * 100.0) / self._ftrace.get_duration() + (result[pivot] * 100.0)/self._ftrace.get_duration()) return result diff --git a/bart/thermal/__init__.py b/bart/thermal/__init__.py index 6eefbc2..b9627a2 100644 --- a/bart/thermal/__init__.py +++ b/bart/thermal/__init__.py @@ -14,6 +14,8 @@ # """Initialization for bart.thermal""" - +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function import bart.thermal.ThermalAssert diff --git a/docs/api_reference/conf.py b/docs/api_reference/conf.py index 32d6653..8868bbd 100644 --- a/docs/api_reference/conf.py +++ b/docs/api_reference/conf.py @@ -25,6 +25,9 @@ # # All configuration values have a default; values that are commented out # serve to show the default. +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function import sys import os diff --git a/docs/examples/thermal.py b/docs/examples/thermal.py index 8fe3e95..2ebc393 100644 --- a/docs/examples/thermal.py +++ b/docs/examples/thermal.py @@ -16,6 +16,10 @@ """ An example file for usage of Analyzer for thermal assertions """ +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function + from bart.common.Analyzer import Analyzer from trappy.stats.Topology import Topology import unittest diff --git a/setup.py b/setup.py index 7d9f0ab..a94aef2 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2015-2016 ARM Limited # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,8 +15,8 @@ # from setuptools import setup, find_packages - -execfile("bart/version.py") +with open("bart/version.py") as f: + exec(f.read()) LONG_DESCRIPTION = """Behavioural Analysis involves the expressing the general expectation of the state of the system while targeting a single or set of heuristics. @@ -30,8 +30,10 @@ """ REQUIRES = [ - "TRAPpy>=3.0", + "pandas", + "trappy>=3.0", "hypothesis>=3.0", + "future", ] setup(name='bart-py', @@ -51,6 +53,7 @@ "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", # As we depend on trace data from the Linux Kernel/FTrace "Topic :: System :: Operating System Kernels :: Linux", "Topic :: Scientific/Engineering :: Visualization" diff --git a/tests/pelt.py b/tests/pelt.py index 6ba176d..05323a6 100644 --- a/tests/pelt.py +++ b/tests/pelt.py @@ -1,7 +1,11 @@ +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function + from hypothesis import given from hypothesis.strategies import integers, tuples, none, one_of import unittest -from sys import maxint +from sys import maxsize from bart.sched.pelt import * @@ -22,7 +26,7 @@ nonneg_ints(), # start_sample nonneg_ints(), # run_samples none(), # duty_cycle_pct -).filter(lambda (period, _, run, __): run <= period) +).filter(lambda period___run___: period___run___[2] <= period___run___[0]) # Generate args for PeriodicTask::__init__ args using duty_cycle_pct periodic_task_args_pct = lambda: tuples( @@ -73,7 +77,7 @@ def test_signal_time_range(self, task_args, sim_args, signal_range): signal = sim.getSignal(task, start_s, end_s) # Should start no earlier than 1 sample before start_s - earliest_start = min(0, start_s - (sim._sample_us / 1.e6)) + earliest_start = min(0, start_s - (im._sample_us/1.e6)) self.assertGreaterEqual(signal.index[0], earliest_start) # Should start no later than start_s self.assertLessEqual(signal.index[0], start_s) @@ -81,7 +85,7 @@ def test_signal_time_range(self, task_args, sim_args, signal_range): # Should start no earlier than end_s self.assertGreaterEqual(signal.index[-1], end_s) # Should end no later than 1 sample after end_s - latest_start = end_s + (sim._sample_us / 1.e6) + latest_start = end_s + (sim._sample_us/1.e6) self.assertLessEqual(signal.index[-1], latest_start) if __name__ == "__main__": diff --git a/tests/test_common_utils.py b/tests/test_common_utils.py index 09b31e3..2737e73 100644 --- a/tests/test_common_utils.py +++ b/tests/test_common_utils.py @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function from bart.common import Utils from bart.common.Analyzer import Analyzer diff --git a/tests/test_pelt_sim.py b/tests/test_pelt_sim.py index e609c75..c9957ca 100644 --- a/tests/test_pelt_sim.py +++ b/tests/test_pelt_sim.py @@ -12,14 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function from bart.sched.pelt import * from hypothesis import given from hypothesis.strategies import integers, tuples, none, one_of -from sys import maxint from utils_tests import TestBART +import sys +import math -# Required to use `int` not `long` henx ma=maxint +# Required to use `int` not `long` on Python 2 ,hence ma=maxint +maxint = getattr(sys, 'maxint', sys.maxsize) nonneg_ints = lambda mi=0, ma=maxint: integers(min_value=mi, max_value=ma) # Generate a Simulator @@ -36,7 +41,7 @@ nonneg_ints(), # start_sample nonneg_ints(), # run_samples none(), # duty_cycle_pct -).filter(lambda (period, _, run, __): run <= period) +).filter(lambda period___run___: period___run___[2] <= period___run___[0]) # Generate args for PeriodicTask::__init__ args using duty_cycle_pct periodic_task_args_pct = lambda: tuples( @@ -92,7 +97,7 @@ def test_signal_time_range(self, task_args, sim_args, signal_range): signal = sim.getSignal(task, start_s, end_s) # Should start no earlier than 1 sample before start_s - earliest_start = min(0, start_s - (sim._sample_us / 1.e6)) + earliest_start = min(0, start_s - (sim._sample_us/1.e6)) self.assertGreaterEqual(signal.index[0], earliest_start) # Should start no later than start_s self.assertLessEqual(signal.index[0], start_s) @@ -100,7 +105,7 @@ def test_signal_time_range(self, task_args, sim_args, signal_range): # Should start no earlier than end_s self.assertGreaterEqual(signal.index[-1], end_s) # Should end no later than 1 sample after end_s - latest_start = end_s + (sim._sample_us / 1.e6) + latest_start = end_s + (sim._sample_us/1.e6) self.assertLessEqual(signal.index[-1], latest_start) @given(periodic_task_args(), simulator_args()) @@ -113,7 +118,7 @@ def test_signal_mean_value(self, task_args, sim_args): signal = sim.getSignal(task) stats = sim.getStats() - expected_mean = (task.duty_cycle_pct * 1024) / 100 + expected_mean = (task.duty_cycle_pct * 1024)/100 - self.assertEqual(stats.pelt_avg, expected_mean) + self.assertEqual(math.floor(stats.pelt_avg), math.floor(expected_mean)) diff --git a/tests/test_sched_assert.py b/tests/test_sched_assert.py index 4f8c28b..18f293a 100644 --- a/tests/test_sched_assert.py +++ b/tests/test_sched_assert.py @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function from bart.sched.SchedAssert import SchedAssert from bart.sched.SchedMultiAssert import SchedMultiAssert diff --git a/tests/test_sched_functions.py b/tests/test_sched_functions.py index 1a8d4ac..61828a6 100644 --- a/tests/test_sched_functions.py +++ b/tests/test_sched_functions.py @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function import trappy @@ -43,7 +46,6 @@ def test_get_pids_for_process_funny_process_names(self): from bart.sched.functions import get_pids_for_process trace_file = "trace.txt" - raw_trace_file = "trace.raw.txt" in_data = """ -0 [001] 10826.894644: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=0 next_comm=rt-app next_pid=3268 next_prio=120 wmig-3268 [001] 10826.894778: sched_switch: prev_comm=wmig prev_pid=3268 prev_prio=120 prev_state=1 next_comm=rt-app next_pid=3269 next_prio=120 wmig1-3269 [001] 10826.905152: sched_switch: prev_comm=wmig1 prev_pid=3269 prev_prio=120 prev_state=1 next_comm=wmig next_pid=3268 next_prio=120 @@ -54,16 +56,8 @@ def test_get_pids_for_process_funny_process_names(self): wmig1-3269 [005] 10827.031061: sched_switch: prev_comm=wmig1 prev_pid=3269 prev_prio=120 prev_state=0 next_comm=wmig next_pid=3268 next_prio=120 wmig-3268 [005] 10827.050645: sched_switch: prev_comm=wmig prev_pid=3268 prev_prio=120 prev_state=1 next_comm=swapper/5 next_pid=0 next_prio=120 """ - - # We create an empty trace.txt to please trappy ... with open(trace_file, "w") as fout: - fout.write("") - - # ... but we only put the sched_switch events in the raw trace - # file because that's where trappy is going to look for - with open(raw_trace_file, "w") as fout: fout.write(in_data) trace = trappy.FTrace(trace_file) - self.assertEquals(get_pids_for_process(trace, "wmig"), [3268]) diff --git a/tests/test_signal.py b/tests/test_signal.py index 48692a9..71f2c5a 100644 --- a/tests/test_signal.py +++ b/tests/test_signal.py @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function import pandas as pd import trappy @@ -40,7 +43,7 @@ def test_conditional_compare(self): trace.add_parsed_event("event", df) s = SignalCompare(trace, "event:A", "event:B") - expected = (1.5, 2.0 / 7) + expected = (1.5, 2.0/7) self.assertEqual( s.conditional_compare( "event:A > event:B", @@ -58,7 +61,7 @@ def test_get_overshoot(self): trace.add_parsed_event("event", df) s = SignalCompare(trace, "event:A", "event:B") - expected = (1.5, 2.0 / 7) + expected = (1.5, 2.0/7) self.assertEqual( s.get_overshoot(method="rect"), expected) @@ -86,7 +89,7 @@ def test_get_undershoot(self): trace.add_parsed_event("event", df) s = SignalCompare(trace, "event:A", "event:B") - expected = (4.0 / 14.0, 1.0) + expected = (4.0/14.0, 1.0) self.assertEqual( s.get_undershoot(method="rect"), expected) diff --git a/tests/utils_tests.py b/tests/utils_tests.py index 6dadca1..4c6ff12 100644 --- a/tests/utils_tests.py +++ b/tests/utils_tests.py @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - +from __future__ import unicode_literals +from __future__ import division +from __future__ import print_function import unittest import os