<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Energy Meter Examples
Energy estimations in Gem5
The Gem5EnergyMeter in Lisa uses the devlib Gem5PowerInstrument to extract energy information from the gem5 statistics file referenced in the energy meter field of the target configuration.
Step1:  Target configuration
The target configuration is used to describe and configure your test environment. You can find more details in examples/utils/testenv_example.ipynb.
Step2:  Workload execution
For this example, we will investigate the energy consumption of the target while running a random workload. Our observations will be made using the RT-App decreasing ramp workload defined below. With such a workload, the system load goes from high to low over time. We expect to see a similar pattern in power consumption.
Step3:  Energy estimation
The gem5 energy meters feature two methods
Step4:  Data analysis
Step5:  We can see on the above plot that the system level power consumption decreases over time (in average). This is coherent with the expected behaviour given the decreasing ramp workload under consideration.
<ASSISTANT_TASK:>
Python Code:
from conf import LisaLogging
LisaLogging.setup()
# One initial cell for imports
import json
import logging
import os
from env import TestEnv
# Suport for FTrace events parsing and visualization
import trappy
from trappy.ftrace import FTrace
from trace import Trace
# Support for plotting
# Generate plots inline
%matplotlib inline
import numpy
import pandas as pd
import matplotlib.pyplot as plt
from env import TestEnv
# RTApp configurator for generation of PERIODIC tasks
from wlgen import RTA, Ramp
Explanation: Energy Meter Examples
Energy estimations in Gem5
The Gem5EnergyMeter in Lisa uses the devlib Gem5PowerInstrument to extract energy information from the gem5 statistics file referenced in the energy meter field of the target configuration.
End of explanation
# Root path of the gem5 workspace
base = "/home/vagrant/gem5"
conf = {
    # Only 'linux' is supported by gem5 for now, 'android' is a WIP
    "platform"    : 'linux',
    
    # Preload settings for a specific target
    "board"       : 'gem5',
    
    # Devlib modules to load - "gem5stats" is required to use the power instrument
    "modules" : ["cpufreq", "bl", "gem5stats"],
    # Host that will run the gem5 instance
    "host"        : "workstation-lin",
    
    "gem5" : {
        # System to simulate
        "system" : {
            # Platform description
            "platform" : {
                # Gem5 platform description
                # LISA will also look for an optional gem5<platform> board file
                # located in the same directory as the description file.
                "description" : os.path.join(base, "juno.py"),
                "args" : [
                    "--power-model", # Platform-specific parameter enabling power modelling
                    "--juno-revision 2",
                    # Resume simulation from a previous checkpoint
                    # Checkpoint must be taken before Virtio folders are mounted
                    #"--checkpoint-indir /data/tmp/Results_LISA/gem5",
                    #"--checkpoint-resume 1",
                ]
            },
            # Kernel compiled for gem5 with Virtio flags
            "kernel"   : os.path.join(base, "product/", "vmlinux"),
            # DTB of the system to simulate
            "dtb"      : os.path.join(base, "product/", "armv8_juno_r2.dtb"),
            # Disk of the distrib to run
            "disk"     : os.path.join(base, "aarch64-ubuntu-trusty-headless.img")
        },
        # gem5 settings
        "simulator" : {
            # Path to gem5 binary
            "bin"     : os.path.join(base, "gem5/build/ARM/gem5.fast"),
            # Args to be given to the binary
            "args" : [
                # Zilch
            ],
        }
    },
    
    # Tools required by the experiments
    "tools"   : ['trace-cmd', 'sysbench', 'rt-app'],
    
    # Output directory on host
    "results_dir" : "gem5_res",
    
    # Energy Meters configuration based on Gem5 stats
    "emeter" : {
        "instrument" : "gem5",
        "conf" : {
            # Zilch
        },
        # Each channel here must refer to a specific **power** field in the stats file. 
        'channel_map' : {
            'Core0S' : 'system.cluster0.cores0.power_model.static_power',
            'Core0D' : 'system.cluster0.cores0.power_model.dynamic_power',
            'Core1S' : 'system.cluster0.cores1.power_model.static_power',
            'Core1D' : 'system.cluster0.cores1.power_model.dynamic_power',
            'Core2S' : 'system.cluster0.cores2.power_model.static_power',
            'Core2D' : 'system.cluster0.cores2.power_model.dynamic_power',
            'Core3S' : 'system.cluster0.cores3.power_model.static_power',
            'Core3D' : 'system.cluster0.cores3.power_model.dynamic_power',
            'Core4S' : 'system.cluster1.cores0.power_model.static_power',
            'Core4D' : 'system.cluster1.cores0.power_model.dynamic_power',
            'Core5S' : 'system.cluster1.cores1.power_model.static_power',
            'Core5D' : 'system.cluster1.cores1.power_model.dynamic_power',
        },
    },
}
# This can take a lot of time ...
te = TestEnv(conf, wipe=True)
target = te.target
Explanation: Target configuration
The target configuration is used to describe and configure your test environment. You can find more details in examples/utils/testenv_example.ipynb.
End of explanation
# Create and RTApp RAMP tasks
rtapp = RTA(target, 'ramp', calibration=te.calibration())
rtapp.conf(kind='profile',
           params={
                'ramp1' : Ramp(
                    start_pct =  95,
                    end_pct   =  5,
                    delta_pct =   10,
                    time_s    =   0.1).get(),
                'ramp2' : Ramp(
                    start_pct =  90,
                    end_pct   =  30,
                    delta_pct =   20,
                    time_s    =   0.2).get(),
          })
Explanation: Workload execution
For this example, we will investigate the energy consumption of the target while running a random workload. Our observations will be made using the RT-App decreasing ramp workload defined below. With such a workload, the system load goes from high to low over time. We expect to see a similar pattern in power consumption.
End of explanation
# Start emeters & run workload
te.emeter.reset()
rtapp.run(out_dir=te.res_dir)
nrg_rep = te.emeter.report(te.res_dir)
Explanation: Energy estimation
The gem5 energy meters feature two methods: reset and report.
* The reset method will start sampling the channels defined in the target configuration.
* The report method will stop the sampling and produce a CSV file containing power samples together with a JSON file summarizing the total energy consumption of each channel.
End of explanation
logging.info("Measured channels energy:")
print json.dumps(nrg_rep.channels, indent=4)
logging.info("DataFrame of collected samples (only first 5)")
nrg_rep.data_frame.head()
# Obtain system level energy by ...
df = nrg_rep.data_frame
# ... summing the dynamic power of all cores to obtain total dynamic power, ...
df["total_dynamic"] = df[('system.cluster0.cores0.power_model.dynamic_power', 'power')] + \
                      df[('system.cluster0.cores1.power_model.dynamic_power', 'power')] + \
                      df[('system.cluster0.cores2.power_model.dynamic_power', 'power')] + \
                      df[('system.cluster0.cores3.power_model.dynamic_power', 'power')] + \
                      df[('system.cluster1.cores0.power_model.dynamic_power', 'power')] + \
                      df[('system.cluster1.cores1.power_model.dynamic_power', 'power')]
# ... summing the static power of all cores to obtain total static power and ...
df["total_static"] = df[('system.cluster0.cores0.power_model.static_power', 'power')] + \
                      df[('system.cluster0.cores1.power_model.static_power', 'power')] + \
                      df[('system.cluster0.cores2.power_model.static_power', 'power')] + \
                      df[('system.cluster0.cores3.power_model.static_power', 'power')] + \
                      df[('system.cluster1.cores0.power_model.static_power', 'power')] + \
                      df[('system.cluster1.cores1.power_model.static_power', 'power')]
# ... summing the dynamic and static powers
df["total"] = df["total_dynamic"] + df["total_static"]
logging.info("Plot of collected power samples")
axes =df[('total')].plot(figsize=(16,8),
                         drawstyle='steps-post');
axes.set_title('Power samples');
axes.set_xlabel('Time [s]');
axes.set_ylabel('Output power [W]');
Explanation: Data analysis
End of explanation
logging.info("Power distribution")
axes = df[('total')].plot(kind='hist', bins=32,
                          figsize=(16,8));
axes.set_title('Power Histogram');
axes.set_xlabel('Output power [W] buckets');
axes.set_ylabel('Samples per bucket');
logging.info("Plot of collected power samples")
nrg_rep.data_frame.describe(percentiles=[0.90, 0.95, 0.99]).T
# Don't forget to stop Gem5
target.disconnect()
Explanation: We can see on the above plot that the system level power consumption decreases over time (in average). This is coherent with the expected behaviour given the decreasing ramp workload under consideration.
End of explanation
<END_TASK>