import logging
from conf import LisaLogging
LisaLogging.setup()

# Generate plots inline
%matplotlib inline

import copy
import json
import os
import time
import math
import logging

# Support to access the remote target
import devlib
from env import TestEnv

# Support to configure and run RTApp based workloads
from wlgen import RTA

# Support for performance analysis of RTApp workloads
from perf_analysis import PerfAnalysis

# Support for trace events analysis
from trace import Trace

# Suport for FTrace events parsing and visualization
import trappy

"""
Explanation: TRAPpy custom events
Detailed information on Trappy can be found at examples/trappy/trappy_example.ipynb.
End of explanation
"""


# Setup a target configuration
my_target_conf = {
    
    # Define the kind of target platform to use for the experiments
    "platform"    : 'linux',  # Linux system, valid other options are:
                              # android - access via ADB
                              # linux   - access via SSH
                              # host    - direct access
    
    # Preload settings for a specific target
    "board"       : 'juno',  # juno - JUNO board with mainline hwmon
    
    # Define devlib module to load
    "modules"     : [
        'bl',           # enable big.LITTLE support
        'cpufreq'       # enable CPUFreq support
    ],

    # Account to access the remote target
    "host"        : '192.168.0.1',
    "username"    : 'root',
    "password"    : 'juno',

    # Comment the following line to force rt-app calibration on your target
    "rtapp-calib" : {
        '0': 361, '1': 138, '2': 138, '3': 352, '4': 360, '5': 353
    }

}

# Setup the required Test Environment supports
my_tests_conf = {
        
    # Binary tools required to run this experiment
    # These tools must be present in the tools/ folder for the architecture
    "tools"   : ['trace-cmd'],
    
    # FTrace events buffer configuration
    # events listed here MUST be 
    "ftrace"  : {
        
        
##############################################################################
# EVENTS SPECIFICATIPON
##############################################################################
# Here is where we specify the list of events we are interested into:
# Events are of two types:
# 1. FTrace tracepoints that _must_ be supported by the target's kernel in use.
#    These events will be enabled at ftrace start time, thus if the kernel does
#    not support one of them, ftrace starting will fails.

        "events" : [
            "sched_switch",
            "cpu_frequency",
        ],

# 2. FTrace events generated via trace_printk, from either kernel or user
#    space. These events are different from the previous because they do not
#    need to be explicitely enabled at ftrace start time.
#    It's up to the user to ensure that the generated events satisfies these
#    formatting requirements:
#    a) the name must be a unique word into the trace
#    b) values must be reported as a sequence of key=value paires
#    For example, a valid custom event string is:
#      my_math_event: kay1=val1 key2=val2 key3=val3

        "custom" : [
            "my_math_event",
        ],
        
# For each of these events, TRAPpy will generate a Pandas dataframe accessible
# via a TRAPpy::FTrace object, whith the same name of the event.
# Thus for example, ftrace.my_math_event will be the object exposing the
# dataframe with all the event matching the "my_math_event" unique word.
        
##############################################################################
        
         "buffsize" : 10240,
    },

}

# Initialize a test environment using:
#  - the provided target configuration (my_target_conf)
#  - the provided test configuration (my_test_conf)
te = TestEnv(target_conf=my_target_conf, test_conf=my_tests_conf)
target = te.target

logging.info("Target ABI: %s, CPus: %s",
             target.abi,
             target.cpuinfo.cpu_names)

"""
Explanation: Test environment setup
For more details on this please check out examples/utils/testenv_example.ipynb.
End of explanation
"""


# Define the format string for the custom events we will inject from user-space
my_math_event_fmt = "my_math_event: sin={} cos={}"

# Start FTrace
te.ftrace.start()

# Let's generate some interesting "custom" events from userspace
logging.info('Generating events from user-space (will take ~140[s])...')
for angle in range(360):
    v_sin = int(1e6 * math.sin(math.radians(angle)))
    v_cos = int(1e6 * math.cos(math.radians(angle)))
    my_math_event = my_math_event_fmt.format(v_sin, v_cos)
    # custom events can be generated either from userspace, like in this
    # example, or also from kernelspace (using a trace_printk call)
    target.execute('echo {} > /sys/kernel/debug/tracing/trace_marker'\
                   .format(my_math_event))

# Stop FTrace
te.ftrace.stop()

# Collect the generate trace
trace_file = '/tmp/trace.dat'
te.ftrace.get_trace(trace_file)

# Parse trace
events_to_parse = my_tests_conf['ftrace']['events'] + my_tests_conf['ftrace']['custom']
trace = Trace(te.platform, '/tmp', events_to_parse)

"""
Explanation: Example of custom event definition
End of explanation
"""


# Get the TRAPpy FTrace object which has been generated from the trace parsing
ftrace = trace.ftrace

# The FTrace object allows to verify which (of the registered) events have been
# identified into the trace
logging.info("List of events identified in the trace:\n%s",
             ftrace.class_definitions.keys())

# Each event identified in the trace is appended to a table (i.e. data_frame)
# which has the same name of the event
logging.info("First 10 events of our 'my_math_event' custom event:")
ftrace.my_math_event.data_frame.head(10)

logging.info("First 10 events of our 'cpu_frequency' tracepoint:")
ftrace.cpu_frequency.data_frame.head(10)

"""
Explanation: Inspection of the generated TRAPpy FTrace object
End of explanation
"""


# It is possible to mix in the same plot tracepoints and custom events

# The LinePlot module requires to specify a list of signals to plot.
# Each signal is defined as:
#       <event>:<column>
# where:
#  <event>   is one of the events collected from the trace by the FTrace object
#  <column>  is one of the column of the previously defined event
my_signals = [
    'cpu_frequency:frequency',
    'my_math_event:sin',
    'my_math_event:cos'
]

# These two paramatere are passed to the LinePlot call as long with the
# TRAPpy FTrace object
trappy.LinePlot(
    ftrace,                      # FTrace object
    signals=my_signals,          # Signals to be plotted
    drawstyle='steps-post',      # Plot style options
    marker = '+'
).view()

"""
Explanation: Plotting tracepoint and/or custom events
End of explanation
"""


