Running PowerTOP on OMAP35x platform

From Texas Instruments Wiki
Jump to: navigation, search

Introduction

The Linux port on OMAP35x supports multiple C-states (idle states) corresponding to different levels of power savings that can be achieved. The amount of power saved depends upon optimal choice of idle state.

This is exactly where PowerTOP comes handy. It collates various kernel statistics to help us visualize the 'activities' when system is idle. We can, now, confirm if the system is behaving as expected. Or, identify 'rogue' tasks/ events that are stealing power.

This article describes the steps and changes to get PowerTOP running on the OMAP35x platforms. These steps can be replicated on other processors and EVMs as well.

Background

Until recently, timer-tick was a periodic event causing CPU to use power - even when the system is idle. The 'tickless kernel' has enabled systems to stay in low power mode for much longer - enabling better power savings.

PowerTOP is Linux tool that aims at identifying software components that are using power while the CPU is idle. It is one of Intel's "LessWatts.org" projects. It is based on (and driven by) the Intel Processors and released under the GNU General Public License (version 2).

Kernel Configuration

The Linux kernel needs to be instrumented to gather relavent statistics. This section describes changes to default configuration.

  1. Create default configuration for the OMAP3EVM.
    $ make omap3_evm_defconfig
    NOTE: In the Linux PSP versions earlier than version 1.0.x, this command will be: make omap3evm_defconfig.
  2. Invoke Linux Kernel Configuration tool
    $ make menuconfig
  3. On the first screen, select the option Kernel hacking.
    Networking --->
    Device Drivers --->
    File systems --->
    Kernel hacking --->
    Security options --->
  4. Now select the option Collect kernel timers statistics.
    [ ] Collect scheduler statistics
    [*] Collect kernel timers statistics
    [ ] Debug object operations
    [ ] Debug slab memory allocations
  5. Now, build the kernel as usual.
    $ make uImage

Getting necessary sources

  • Download the PoweTOP from here.
    (Latest version at time of writing this article was 1.10)
  • Extract the sources to your working directory.
  • By default, PowerTOP uses libncursesw (wide character version of ncurses).
    Since, wide character version is not necessary for us, we will use regular ncurses library)
    It can be download from here.
    (Latest version at time of writing this article was 5.6)
  • Extract the sources to your working directory.

For simplicity, this article assumes that all sources are extracted besides the linux kernel sources as shown below:

/home/user/work
  |
  +-- linux
  |
  +-- ncurses
  |
  +-- powertop

Updates to PowerTOP

The changes are described here through "diff" between original and modified code. Consolidated patch containing the changes described below is available here.

Makefile

  • Use CodeSourcery toolchain. (You will need to customize depending upon: the toolchain used, install location etc.)
-WARNFLAGS=-Wall  -W -Wshadow
-CFLAGS?=-O1 -g ${WARNFLAGS}
-CC?=gcc
+WARNFLAGS=-Wall -Wstrict-prototypes
+INCPATH?=-I ../ncurses/include \
+          -I ../ncurses/include/ncurses \
+          -isystem /opt/codesourcery/2008q1/lib/gcc/arm-none-linux-gnueabi/4.2.3/include
+LIBPATH?=-L ../ncurses/lib
+
+CFLAGS?=-march=armv7a -DOMAP3 -pipe -O1 -g ${WARNFLAGS} ${INCPATH} ${LIBPATH}
+ 
+CC=arm-none-linux-gnueabi-gcc
  • Use ncurses instead of ncursesw.
 powertop: $(OBJS) Makefile powertop.h
-	$(CC) ${CFLAGS}  $(OBJS) -lncursesw -o powertop
+	$(CC) ${CFLAGS}  $(OBJS) -l ncurses -o powertop
 	@(cd po/ && $(MAKE))
  • Add new file omapcstates.c.
-	sata.o xrandr.o ethernet.o cpufreqstats.o usb.o urbnum.o intelcstates.o
+	sata.o xrandr.o ethernet.o cpufreqstats.o usb.o urbnum.o intelcstates.o omapcstates.o

powertop.h

  • Update maximum number of C-states and P-states supported in the Linux kernel.
 #include <libintl.h>
 
+#if defined(__I386__)
+#define MAX_NUM_CSTATES 4
+#define MAX_NUM_PSTATES 5
+
+#elif defined(OMAP3)
+#define MAX_NUM_CSTATES 7
+#define MAX_NUM_PSTATES 5
+
+#else
+#error "No valid architecture is defined."
+#endif
  • Define number of lines required for C-state information.
+
+#define MAX_CSTATE_LINES (MAX_NUM_CSTATES + 3)
+
  • Use the constants defined above:
-extern char cstate_lines[12][200];
-extern char cpufreqstrings[5][80];
+extern char cstate_lines[MAX_CSTATE_LINES][200];
+extern char cpufreqstrings[MAX_NUM_PSTATES][80];

powertop.c

  • Use constants defined in powertop.h instead of the magic numbers:
-char cstate_lines[12][200];
+char cstate_lines[MAX_CSTATE_LINES][200];
-		topcstate = -4;
+
+		topcstate = -(MAX_NUM_CSTATES);
+
-			for (i = 0; i < 8; i++)
+
+			for (i = 0; i < MAX_NUM_CSTATES; i++)
  • Insert function print_omap3_cstates():
+
+#if defined (__I386__)
 	print_intel_cstates();
+#elif defined (OMAP3)
+	print_omap3_cstates();
+#endif
+

display.c

  • Use constants defined in powertop.h instead of the magic numbers:
-	for (i=0; i < 10; i++) {
+	for (i=0; i < MAX_CSTATE_LINES; i++) {
-		if (strlen(cstate_lines[i]) && count <= 6) {
+		if (strlen(cstate_lines[i]) && count <= MAX_CSTATE_LINES) {
-	for (i=0; i<5; i++) {
+	for (i=0; i < MAX_NUM_PSTATES; i++) {
  • Use MAX_NUM_CSTATES to define sub-windows.
+	int yline = MAX_NUM_CSTATES;
+
 	getmaxyx(stdscr, maxy, maxx);
 
 	zap_windows();	
 
 	title_bar_window = subwin(stdscr, 1, maxx, 0, 0);
-	cstate_window = subwin(stdscr, 7, maxx, 2, 0);
-	wakeup_window = subwin(stdscr, 1, maxx, 9, 0);
-	acpi_power_window = subwin(stdscr, 2, maxx, 10, 0);
-	timerstat_window = subwin(stdscr, maxy-16, maxx, 12, 0);
+
+	cstate_window = subwin(stdscr, (yline + 2), maxx, 2, 0);
+	wakeup_window = subwin(stdscr, 1, maxx, (yline + 5), 0);
+	acpi_power_window = subwin(stdscr, 2, maxx, (yline + 6), 0);
+	timerstat_window = subwin(stdscr, maxy-16, maxx, (yline + 8), 0);
+

cpufreqstats.c

  • Use constants defined in powertop.h:
-char cpufreqstrings[5][80];
+char cpufreqstrings[MAX_NUM_PSTATES][80];
+

omapcstates.c

  • This is a new file.
/*
 * Copyright 2008, Texas Instruments Incorporated.
 *
 * This file prints the C states supported by the OMAP processor.
 * (Based on intelcstates.c)
 *
 * This program file is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program in a file named COPYING; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <dirent.h>
#include <ctype.h>

#include "powertop.h"


#if defined(OMAP3)
/**
 * print_omap3_cstates() - Prints the list of supported C-states.
 *
 * This functions uses standard sysfs interface of the cpuidle framework
 * to extract the information of the C-states supported by the Linux
 * kernel. 
 **/
void print_omap3_cstates(void)
{
	DIR *dir;
	struct dirent *entry;

	dir = opendir("/sys/devices/system/cpu/cpu0/cpuidle");

	if (dir) {
		printf(_("Supported C-states : "));

		while ((entry = readdir(dir))) {
			if (strlen(entry->d_name) < 3)
				continue;

			printf("C%s ", entry->d_name);
		}
		printf("\n");

		closedir(dir);
	}
}
#endif

Build

  • Set the environment variables CC and CXX.
$ setenv CC  /opt/codesourcery/2008q1/bin/arm-none-linux-gnueabi-gcc
$ setenv CXX /opt/codesourcery/2008q1/bin/arm-none-linux-gnueabi-g++

ncurses

  • Change to directory ncurses and execute the command:
$ ./configure \
        --host=arm-none-linux-gnueabi \
        --target=arm-none-linux-gnueabi \
        --with-shared \
        --without-ada
  • Build sources
$ make CROSS_COMPILE=arm-none-linux-gnueabi-
  • Ready the package for installation on target system.
$ make install DESTDIR=/home/user/work/ncurses/_install

The contents of the directory _install need to be copied on the target filesystem.

PowerTOP

  • Change to directory powertop and execute the command:
$ make CROSS_COMPILE=arm-none-linux-gnueabi-

The executable powertop needs to be copied on target filesystem. The directory /usr/local/bin is a good choice for copying the executable.

Example session

Boot the OMAP3EVM with uImage created earlier (with additional instrumentation enabled).

  • View list of supported arguments
$ powertop --help
Usage: powertop [OPTION...]
  -d, --dump            read wakeups once and print list of top offenders
  -t, --time=DOUBLE     default time to gather data in seconds
  -h, --help            Show this help message
  • To start utility in interactive mode:
$ powertop

References