/*
* Copyright 2009, Intel Corporation
*
* This file is part of PowerTOP
*
* 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
*
* Authors:
* Arjan van de Ven <arjan@linux.intel.com>
* Eric C Saxe <eric.saxe@sun.com>
* Aubrey Li <aubrey.li@intel.com>
*/
/*
* GPL Disclaimer
*
* For the avoidance of doubt, except that if any license choice other
* than GPL or LGPL is available it will apply instead, Sun elects to
* use only the General Public License version 2 (GPLv2) at this time
* for any software where a choice of GPL license versions is made
* available with the language indicating that GPLv2 or any later
* version may be used, or where a choice of which version of the GPL
* is applied is otherwise unspecified.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <strings.h>
#include <sys/systeminfo.h>
#include <kstat.h>
#include <time.h>
#include <errno.h>
#include "powertop.h"
static char *progname;
void
{
}
/*PRINTFLIKE1*/
void
{
if (g_gui)
return;
}
/*
* Returns the number of online CPUs.
*/
pt_enumerate_cpus(void)
{
int cpuid;
/* Fall back to one CPU if any of the sysconf calls above failed */
}
/* Free any previous cpu table */
if (g_cpu_table != NULL)
return (0);
ncpus++;
}
}
return (ncpus);
}
/*
* Simple integer comparison routine for the event report qsort(3C).
*/
int
{
return (-1);
return (1);
return (0);
}
void
pt_usage(void)
{
"times and print list of top offenders\n");
"data in seconds [1-30s]\n");
"kernel cyclic activity\n");
" CPU\n");
"message\n");
}
int
pt_get_bit_depth(void)
{
/*
* This little routine was derived from isainfo.c to look up
* the system's bit depth. It feeds a 10 byte long buffer to
* sysinfo (we only need the first word, sysinfo truncates and
* \0 terminates the rest) from which we figure out which isa
* we're running on.
*/
return (-2);
return (32);
return (64);
return (-3);
}
void
{
int i;
return;
for (i = 0; i < CPU_MAX_PSTATES; i++) {
g_pstate_info[i].total_time = 0;
}
for (i = 0; i < CPU_MAX_CSTATES; i++) {
g_cstate_info[i].total_time = 0;
g_cstate_info[i].last_time = 0;
g_cstate_info[i].events = 0;
}
g_total_c_time = 0;
g_total_p_time = 0;
g_total_events = 0;
switch (g_op_mode) {
case PT_MODE_CPU:
break;
case PT_MODE_DEFAULT:
default:
break;
}
}
void
{
int i;
return;
for (i = 0; i < new->s_num_cpus; i++) {
if (old) {
}
return;
}
}
void
{
int i = g_observed_cpu;
return;
if (old) {
}
return;
}
void
{
int i, j, n;
/*
* 2^64 - 1; includes null terminator
* max string will contain n-1 ':'s and one null terminator
*/
/*
* the first output will have c1 = NULL, to give results since boot
*/
if (c1) {
/* check there are stats to report */
if (!CPU_ACTIVE(c1))
return;
}
/* check there are stats to report */
if (c2) {
if (!CPU_ACTIVE(c2))
return;
}
return;
return;
return;
}
if (g_features & FEATURE_CSTATE) {
"supported_max_cstates", &g_supported_max_cstates_index);
g_max_cstates = ++max_cstates;
if (max_cstates > CPU_MAX_CSTATES) {
pt_error("max_cstates %d out of range\n",
exit(2);
}
for (i = 0; i < max_cstates; i++) {
c_nsec[i] = 0;
c_count[i] = 0;
}
if (n != max_cstates) {
return;
}
if (n != max_cstates) {
return;
}
/*
* C-State Kstats are in C(n) ... C(0) Order
* Powertop displays thenm in C(0) to C(n) order.
*/
for (i = 0; i < max_cstates; i++) {
j = max_cstates - i - 1;
g_total_c_time += c_nsec[j];
}
/* g_total_events is tranitions into C0 */
if (max_cstates > 0)
}
if (g_features & FEATURE_PSTATE) {
"supported_max_pstates",
g_max_pstates = ++max_pstates;
if (max_pstates > CPU_MAX_PSTATES) {
pt_error("max_pstates %d out of range\n",
exit(2);
}
for (i = 0; i < max_pstates; i++) {
p_nsec[i] = 0;
}
if (n != max_pstates) {
return;
}
for (i = 0; i < max_pstates; i++) {
/*
* P-State Kstats are in P(n) .. P(0) order
* powertop displays them is this order.
*/
g_total_p_time += p_nsec[i];
}
}
}
/*
* The snapshot has changed for whatever reason. We need to regenerate
* all information pertaining to the cpus including the record offsets.
*/
int
{
size_t i;
int max_cpus;
/*
* Re-enumerate the system's CPUs, populate cpu_table, g_ncpus
*/
if ((g_ncpus = pt_enumerate_cpus()) == 0)
if (!PT_ON_CPU)
sizeof (struct kstat_cpu_records))) == NULL)
return (errno);
/*
* Walk the cpu snapshot chain, looking for the information we desire.
*/
for (i = 0; i < max_cpus; i++) {
/* If no valid CPU is present, move on to the next one */
if (PT_ON_CPU) {
return (-1);
}
continue;
}
kstat_cpu_information[i].cs_id = i;
if ((kstat_cpu_information[i].cpu_info_ksp_ptr =
return (errno);
}
return (0);
}
/*
* Note: the following helpers do not clean up on the failure case,
* because pt_free_snapshot() is called in main each time through the loop
*/
int
{
size_t i;
sizeof (struct cpu_snapshot))) == NULL)
return (errno);
/*
* If the snap has changed or we have not obtained the
* kstat_cpu_information, then go and get the cpu information.
*/
return (rtc);
/*
* Read the data in that changes between the intervals.
*/
for (i = 0; i < ss->s_num_cpus; i++) {
/* If no valid CPU is present, move on to the next one */
continue;
continue;
return (errno);
return (errno);
/* now copy the cstate and pstate strings */
if (g_features & FEATURE_CSTATE) {
return (errno);
return (ENOENT);
return (errno);
return (ENOENT);
}
if (g_features & FEATURE_PSTATE) {
return (errno);
return (ENOENT);
}
}
errno = 0;
return (errno);
}
/*
* Note: the following helpers do not clean up on the failure case,
* because pt_free_snapshot() is called in main each time through the loop
*/
int
{
int rtc;
int i = g_observed_cpu;
if (i < 0 || i >= g_ncpus) {
return (errno);
}
sizeof (struct cpu_snapshot))) == NULL)
return (errno);
/*
* If the snap has changed or we have not obtained the
* kstat_cpu_information, then go and get the cpu information.
*/
return (rtc);
/*
* Read the data in that changes between the intervals.
*/
return (errno);
return (errno);
/*
* now copy the cstate and pstate strings
*/
if (g_features & FEATURE_CSTATE) {
return (errno);
return (ENOENT);
return (errno);
return (ENOENT);
}
if (g_features & FEATURE_PSTATE) {
return (errno);
return (ENOENT);
}
errno = 0;
return (errno);
}
struct snapshot *
{
int err = 0;
int retry_cnt = 0;
pt_error("acquiring snapshot failed, no memory");
exit(2);
}
}
retry_cnt++;
if (retry_cnt > PT_KSTAT_CHAIN_RETRYS)
break;
}
if (retry_cnt > PT_KSTAT_CHAIN_RETRYS) {
kc = kstat_open();
}
pt_error("kstat_chain_update failed");
exit(2);
}
if (PT_ON_CPU)
else
if (err)
return (NULL);
else
return (ss);
}
void
{
size_t i;
return;
for (i = 0; i < ss->s_num_cpus; i++) {
}
}
}
pt_open_kstat(void)
{
else {
pt_error("kstat_open failed");
exit(2);
}
}
return (kc);
}
void *
{
void *ptr;
} else {
pt_error("malloc failed");
exit(2);
}
}
return (ptr);
}
/*
* Convert a ':'-separated null terminated string into an array of values
* Assumptions:
* It is OK to modify the input string
* There will always be at least two entries (e.g. one ':') in the string.
* Return the number of entries found, or 0 for a misformed string
*/
int
{
int i;
return (0);
for (i = 0; i < (entries - 1); i++) {
break;
*cp = '\0';
}
if (i == (entries - 1)) {
return (entries);
} else {
return (0);
}
}
/*
* Convert a pair of strings of ':'-separated uint64 numbers into an array of
* the difference between the values of the numbers in each position.
* Assumes, based on knowing the context in which it is called:
* both strings have the same number of entries
* some numbers may be "empty" (e.g. the string may contain consecutive :'s
* if an entry in one string is empty then the other will be too
* the difference between two empty strings is computed as 0
* numbers represent nanoseconds, which won't wrap in our lifetime
* Returns the number of entries found in the string, else 0 if misformed.
*/
int
{
if (entries > CPU_MAX_PSTATES)
return (0);
if (n1 == 0)
return (0);
return (0);
for (i = 0; i < entries; i++)
return (entries);
}
long
{
else {
return (0);
}
}
int
{
return (-1);
} else {
dst->ks_data_size = 0;
}
return (0);
}
/*
* If index_ptr integer value is > -1 then the index points to the
* string entry in the ks_data that we are interested in. Otherwise
* we will need to walk the array.
*/
void *
{
int i;
int size;
int index;
return (NULL);
}
case KSTAT_TYPE_NAMED:
size = sizeof (kstat_named_t);
break;
case KSTAT_TYPE_TIMER:
size = sizeof (kstat_timer_t);
break;
default:
return (NULL);
}
if (index >= 0) {
/* Short cut to the information. */
return (datap);
}
/* Need to go find the string. */
*index_ptr = i;
return (datap);
}
}
return (NULL);
}