ThermalSensorCharacterisation


Thermal Sensor Measurements

The goal of this experiment is to measure temperature on Juno R2 board using the available sensors. In order to do that we will run a busy-loop workload of about 5 minutes and collect traces for the thermal_temperature event.

Measurements must be done with and without fan.


In [ ]:
import logging
from conf import LisaLogging
LisaLogging.setup()

In [ ]:
%pylab inline

import os

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

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

# Support for trace events analysis
from trace import Trace

# Suport for FTrace events parsing and visualization
import trappy

Target Configuration

Our target is a Juno R2 development board running Linux.


In [ ]:
# Setup a target configuration
my_target_conf = {
    
    # Target platform and board
    "platform"    : 'linux',
    "board"       : 'juno',
    
    # Target board IP/MAC address
    "host"        : '192.168.0.1',
    
    # Login credentials
    "username"    : 'root',
    "password"    : '',
    
    # RTApp calibration values (comment to let LISA do a calibration run)
    "rtapp-calib" :  {
        "0": 318, "1": 125, "2": 124, "3": 318, "4": 318, "5": 319
    },
    
    # Tools required by the experiments
    "tools"   : [ 'rt-app', 'trace-cmd' ],    
    "exclude_modules" : ['hwmon'],
    
    # FTrace events to collect for all the tests configuration which have
    # the "ftrace" flag enabled
    "ftrace"  : {
         "events" : [
            "thermal_temperature",
            # Use sched_switch event to recognize tasks on kernelshark
            "sched_switch",
            # cdev_update has been used to show that "step_wise" thermal governor introduces noise
            # because it keeps changing the state of the cooling devices and therefore
            # the available OPPs
            #"cdev_update",
         ],
         "buffsize" : 80 * 1024,
    },
}

Tests execution


In [ ]:
# Initialize a test environment using:
# the provided target configuration (my_target_conf)
te = TestEnv(target_conf=my_target_conf)
target = te.target

Workloads configuration


In [ ]:
# Create a new RTApp workload generator using the calibration values
# reported by the TestEnv module
rtapp_big = RTA(target, 'big', calibration=te.calibration())

big_tasks = dict()
for cpu in target.bl.bigs:
    big_tasks['busy_big'+str(cpu)] = Periodic(duty_cycle_pct=100,
                                              duration_s=360,     # 6 minutes
                                              cpus=str(cpu)       # pinned to a given cpu
                                             ).get()

# Configure this RTApp instance to:
rtapp_big.conf(
    # 1. generate a "profile based" set of tasks
    kind='profile',
    
    # 2. define the "profile" of each task
    params=big_tasks,
    
    # 3. Set load reference for task calibration
    loadref='big',
    
    # 4. use this folder for task logfiles
    run_dir=target.working_directory
);

In [ ]:
rtapp_little = RTA(target, 'little', calibration=te.calibration())

little_tasks = dict()
for cpu in target.bl.littles:
    little_tasks['busy_little'+str(cpu)] = Periodic(duty_cycle_pct=100,
                                                    duration_s=360,
                                                    cpus=str(cpu)).get()

rtapp_little.conf(
    kind='profile',
    params=little_tasks,
    # Allow the task duration to be calibrated for the littles (default is for big)
    loadref='little',
    run_dir=target.working_directory
);

Workload execution


In [ ]:
logging.info('#### Setup FTrace')
te.ftrace.start()

logging.info('#### Start RTApp execution')
# Run tasks on the bigs in background to allow execution of following instruction
rtapp_big.run(out_dir=te.res_dir, background=True)
# Run tasks on the littles and then wait 2 minutes for device to cool down
rtapp_little.run(out_dir=te.res_dir, end_pause_s=120.0)

logging.info('#### Stop FTrace')
te.ftrace.stop()

Trace Analysis

In order to analyze the trace we will plot it using TRAPpy.


In [ ]:
# Collect the trace
trace_file = os.path.join(te.res_dir, 'trace.dat')
logging.info('#### Save FTrace: %s', trace_file)
te.ftrace.get_trace(trace_file)
# Parse trace
therm_trace = trappy.FTrace(trace_file)

In [ ]:
therm_trace.thermal.data_frame.tail(10)

In [ ]:
# Plot the data
therm_plot = trappy.ILinePlot(therm_trace,
                              signals=['thermal:temp'],
                              filters={'thermal_zone': ["soc"]},
                              title='Juno R2 SoC Temperature w/o fans')
therm_plot.view()

The pmic sensor if off-chip and therefore it is not useful to get its temperature.


In [ ]:
# Extract a data frame for each zone
df = therm_trace.thermal.data_frame
soc_df = df[df.thermal_zone == "soc"]
big_df = df[df.thermal_zone == "big_cluster"]
little_df = df[df.thermal_zone == "little_cluster"]
gpu0_df = df[df.thermal_zone == "gpu0"]
gpu1_df = df[df.thermal_zone == "gpu1"]
# Build new trace
juno_trace = trappy.BareTrace(name = "Juno_R2")
juno_trace.add_parsed_event("SoC", soc_df)
juno_trace.add_parsed_event("big_Cluster", big_df)
juno_trace.add_parsed_event("LITTLE_Cluster", little_df)
juno_trace.add_parsed_event("gpu0", gpu0_df)
juno_trace.add_parsed_event("gpu1", gpu1_df)

In [ ]:
# Plot the data for all sensors
juno_signals = ['SoC:temp', 'big_Cluster:temp', 'LITTLE_Cluster:temp', 'gpu0:temp', 'gpu1:temp']
therm_plot = trappy.ILinePlot([juno_trace],
                              signals=juno_signals,
                              title='Juno R2 Temperature all traces')
therm_plot.view()