JetsonLeap is a framework that enables the design and test of energy-aware code transformations. It consists of an embedded hardware, a circuit to control the flow of energy, plus a library to instrument program parts.


General Operation


We built an electrical circuit to enable or disable energy measurement by means of a signal fired from within the hardware under analysis. This signal sets the output port of a microcontroller to high or low level, enabling or disabling energy measurement.


When measurement is enabled, we use a power meter that captures voltage samples in real time. To process the output of the power measurement, a program is used to read the power produced at each sample and to generate a file with time and power values. We also compute the integral from these values in order to indicate numerically, in Joules, the energy consumed by the device.


For our experiments, we use an NVIDIA Jetson TK1 board, which contains a Tegra K1 system on a chip device, and runs Linux Ubuntu. For data acquisition, we are currently using a National Instruments 6009 DAQ and a interface implemented in C++ called CMeasure.


Signal


In order to send a signal to enable energy measurement, at first, the GPIO port must be enabled. Then, it is defined as output and finally, its logic level must be set. With our Jetson board, these procedures are performed by the following commands:

  1. echo 165 > /sys/class/gpio/export
  2. echo out > /sys/class/gpio/gpio165/direction
  3. echo 1 > /sys/class/gpio/gpio156

The first line enables the gpio165 port to be used; the second line defines the same port as output; and the third line defines the port logic level as high.


The library used in this project was implemented in C. Thus we wrote the commands above as C functions. Such functions are invoked from within the target program i.e., the program analyzed.


Below, there's an example of a function implemented to set the GPIO value and a target program that invokes this function in order to enable power measurement.


 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21
22
23 
int gpioSetValue (unsigned int gpio, unsigned int value) {
  int fileDescriptor;
  char commandBuffer[64];
  snprintf(commandBuffer, sizeof(commandBuffer),
    "/sys/class/gpio/gpio%d/value", gpio);
  fileDescriptor = open(commandBuffer, 01);
  if (fileDescriptor < 0) {
     char errorBuffer[128] ;
     snprintf(errorBuffer,sizeof(errorBuffer),
       "gpioSetValue unable to open gpio%d",gpio) ;
     perror(errorBuffer);
     return fileDescriptor;
  }
  if (value && write(fileDescriptor, "1", 2) != 2) {
     perror("gpioSetValue");
     return fileDescriptor;
  } else if (write(fileDescriptor, "0", 2) != 2) {
     perror("gpioSetValue");
     return fileDescriptor;
  }
  close(fileDescriptor);
  return 0;
}

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
int main(int argc, char *argv[]) {
  // Do something without measuring energy
  // We are not measuring energy consumption
  // in foo().
  foo();
  // Start measuring energy:
  gpioSetValue(165, 1);
  // Do something measuring energy, e.g.:
  // Measure the energy consumed by bar();
  bar();
  // Stop measuring energy.
  gpioSetValue(165, 0);
  // Function baz() runs without energy
  // Measurement
  baz();
  return 0;
}