diff options
Diffstat (limited to 'tools/thermal')
-rw-r--r-- | tools/thermal/tmon/Makefile | 47 | ||||
-rw-r--r-- | tools/thermal/tmon/README | 50 | ||||
-rw-r--r-- | tools/thermal/tmon/pid.c | 131 | ||||
-rw-r--r-- | tools/thermal/tmon/sysfs.c | 596 | ||||
-rw-r--r-- | tools/thermal/tmon/tmon.8 | 142 | ||||
-rw-r--r-- | tools/thermal/tmon/tmon.c | 352 | ||||
-rw-r--r-- | tools/thermal/tmon/tmon.h | 204 | ||||
-rw-r--r-- | tools/thermal/tmon/tui.c | 638 |
8 files changed, 0 insertions, 2160 deletions
diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile deleted file mode 100644 index 4473211..0000000 --- a/tools/thermal/tmon/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -VERSION = 1.0 - -BINDIR=usr/bin -WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int -CFLAGS= -O1 ${WARNFLAGS} -fstack-protector -CC=gcc - -CFLAGS+=-D VERSION=\"$(VERSION)\" -LDFLAGS+= -TARGET=tmon - -INSTALL_PROGRAM=install -m 755 -p -DEL_FILE=rm -f - -INSTALL_CONFIGFILE=install -m 644 -p -CONFIG_FILE= -CONFIG_PATH= - - -OBJS = tmon.o tui.o sysfs.o pid.o -OBJS += - -tmon: $(OBJS) Makefile tmon.h - $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS) -o $(TARGET) -lm -lpanel -lncursesw -lpthread - -valgrind: tmon - sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET) 1> /dev/null - -install: - - mkdir -p $(INSTALL_ROOT)/$(BINDIR) - - $(INSTALL_PROGRAM) "$(TARGET)" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" - - mkdir -p $(INSTALL_ROOT)/$(CONFIG_PATH) - - $(INSTALL_CONFIGFILE) "$(CONFIG_FILE)" "$(INSTALL_ROOT)/$(CONFIG_PATH)" - -uninstall: - $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" - $(CONFIG_FILE) "$(CONFIG_PATH)" - - -clean: - find . -name "*.o" | xargs $(DEL_FILE) - rm -f $(TARGET) - -dist: - git tag v$(VERSION) - git archive --format=tar --prefix="$(TARGET)-$(VERSION)/" v$(VERSION) | \ - gzip > $(TARGET)-$(VERSION).tar.gz diff --git a/tools/thermal/tmon/README b/tools/thermal/tmon/README deleted file mode 100644 index 4579498..0000000 --- a/tools/thermal/tmon/README +++ /dev/null @@ -1,50 +0,0 @@ -TMON - A Monitoring and Testing Tool for Linux kernel thermal subsystem - -Why TMON? -========== -Increasingly, Linux is running on thermally constrained devices. The simple -thermal relationship between processor and fan has become past for modern -computers. - -As hardware vendors cope with the thermal constraints on their products, more -and more sensors are added, new cooling capabilities are introduced. The -complexity of the thermal relationship can grow exponentially among cooling -devices, zones, sensors, and trip points. They can also change dynamically. - -To expose such relationship to the userspace, Linux generic thermal layer -introduced sysfs entry at /sys/class/thermal with a matrix of symbolic -links, trip point bindings, and device instances. To traverse such -matrix by hand is not a trivial task. Testing is also difficult in that -thermal conditions are often exception cases that hard to reach in -normal operations. - -TMON is conceived as a tool to help visualize, tune, and test the -complex thermal subsystem. - -Files -===== - tmon.c : main function for set up and configurations. - tui.c : handles ncurses based user interface - sysfs.c : access to the generic thermal sysfs - pid.c : a proportional-integral-derivative (PID) controller - that can be used for thermal relationship training. - -Requirements -============ -Depends on ncurses - -Build -========= -$ make -$ sudo ./tmon -h -Usage: tmon [OPTION...] - -c, --control cooling device in control - -d, --daemon run as daemon, no TUI - -l, --log log data to /var/tmp/tmon.log - -h, --help show this help message - -t, --time-interval set time interval for sampling - -v, --version show version - -g, --debug debug message in syslog - -1. For monitoring only: -$ sudo ./tmon diff --git a/tools/thermal/tmon/pid.c b/tools/thermal/tmon/pid.c deleted file mode 100644 index fd7e9e9..0000000 --- a/tools/thermal/tmon/pid.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * pid.c PID controller for testing cooling devices - * - * - * - * Copyright (C) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 or later as published by the Free Software Foundation. - * - * 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. - * - * Author Name Jacob Pan <jacob.jun.pan@linux.intel.com> - * - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <sys/types.h> -#include <dirent.h> -#include <libintl.h> -#include <ctype.h> -#include <assert.h> -#include <time.h> -#include <limits.h> -#include <math.h> -#include <sys/stat.h> -#include <syslog.h> - -#include "tmon.h" - -/************************************************************************** - * PID (Proportional-Integral-Derivative) controller is commonly used in - * linear control system, consider the the process. - * G(s) = U(s)/E(s) - * kp = proportional gain - * ki = integral gain - * kd = derivative gain - * Ts - * We use type C Alan Bradley equation which takes set point off the - * output dependency in P and D term. - * - * y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k] - * - 2*x[k-1]+x[k-2])/Ts - * - * - ***********************************************************************/ -struct pid_params p_param; -/* cached data from previous loop */ -static double xk_1, xk_2; /* input temperature x[k-#] */ - -/* - * TODO: make PID parameters tuned automatically, - * 1. use CPU burn to produce open loop unit step response - * 2. calculate PID based on Ziegler-Nichols rule - * - * add a flag for tuning PID - */ -int init_thermal_controller(void) -{ - int ret = 0; - - /* init pid params */ - p_param.ts = ticktime; - /* TODO: get it from TUI tuning tab */ - p_param.kp = .36; - p_param.ki = 5.0; - p_param.kd = 0.19; - - p_param.t_target = target_temp_user; - - return ret; -} - -void controller_reset(void) -{ - /* TODO: relax control data when not over thermal limit */ - syslog(LOG_DEBUG, "TC inactive, relax p-state\n"); - p_param.y_k = 0.0; - xk_1 = 0.0; - xk_2 = 0.0; - set_ctrl_state(0); -} - -/* To be called at time interval Ts. Type C PID controller. - * y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k] - * - 2*x[k-1]+x[k-2])/Ts - * TODO: add low pass filter for D term - */ -#define GUARD_BAND (2) -void controller_handler(const double xk, double *yk) -{ - double ek; - double p_term, i_term, d_term; - - ek = p_param.t_target - xk; /* error */ - if (ek >= 3.0) { - syslog(LOG_DEBUG, "PID: %3.1f Below set point %3.1f, stop\n", - xk, p_param.t_target); - controller_reset(); - *yk = 0.0; - return; - } - /* compute intermediate PID terms */ - p_term = -p_param.kp * (xk - xk_1); - i_term = p_param.kp * p_param.ki * p_param.ts * ek; - d_term = -p_param.kp * p_param.kd * (xk - 2 * xk_1 + xk_2) / p_param.ts; - /* compute output */ - *yk += p_term + i_term + d_term; - /* update sample data */ - xk_1 = xk; - xk_2 = xk_1; - - /* clamp output adjustment range */ - if (*yk < -LIMIT_HIGH) - *yk = -LIMIT_HIGH; - else if (*yk > -LIMIT_LOW) - *yk = -LIMIT_LOW; - - p_param.y_k = *yk; - - set_ctrl_state(lround(fabs(p_param.y_k))); - -} diff --git a/tools/thermal/tmon/sysfs.c b/tools/thermal/tmon/sysfs.c deleted file mode 100644 index dfe4548..0000000 --- a/tools/thermal/tmon/sysfs.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * sysfs.c sysfs ABI access functions for TMON program - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 or later as published by the Free Software Foundation. - * - * 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. - * - * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> - * - */ -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <dirent.h> -#include <libintl.h> -#include <ctype.h> -#include <time.h> -#include <syslog.h> -#include <sys/time.h> -#include <errno.h> - -#include "tmon.h" - -struct tmon_platform_data ptdata; -const char *trip_type_name[] = { - "critical", - "hot", - "passive", - "active", -}; - -int sysfs_set_ulong(char *path, char *filename, unsigned long val) -{ - FILE *fd; - int ret = -1; - char filepath[256]; - - snprintf(filepath, 256, "%s/%s", path, filename); - - fd = fopen(filepath, "w"); - if (!fd) { - syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); - return ret; - } - ret = fprintf(fd, "%lu", val); - fclose(fd); - - return 0; -} - -/* history of thermal data, used for control algo */ -#define NR_THERMAL_RECORDS 3 -struct thermal_data_record trec[NR_THERMAL_RECORDS]; -int cur_thermal_record; /* index to the trec array */ - -static int sysfs_get_ulong(char *path, char *filename, unsigned long *p_ulong) -{ - FILE *fd; - int ret = -1; - char filepath[256]; - - snprintf(filepath, 256, "%s/%s", path, filename); - - fd = fopen(filepath, "r"); - if (!fd) { - syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); - return ret; - } - ret = fscanf(fd, "%lu", p_ulong); - fclose(fd); - - return 0; -} - -static int sysfs_get_string(char *path, char *filename, char *str) -{ - FILE *fd; - int ret = -1; - char filepath[256]; - - snprintf(filepath, 256, "%s/%s", path, filename); - - fd = fopen(filepath, "r"); - if (!fd) { - syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); - return ret; - } - ret = fscanf(fd, "%256s", str); - fclose(fd); - - return ret; -} - -/* get states of the cooling device instance */ -static int probe_cdev(struct cdev_info *cdi, char *path) -{ - sysfs_get_string(path, "type", cdi->type); - sysfs_get_ulong(path, "max_state", &cdi->max_state); - sysfs_get_ulong(path, "cur_state", &cdi->cur_state); - - syslog(LOG_INFO, "%s: %s: type %s, max %lu, curr %lu inst %d\n", - __func__, path, - cdi->type, cdi->max_state, cdi->cur_state, cdi->instance); - - return 0; -} - -static int str_to_trip_type(char *name) -{ - int i; - - for (i = 0; i < NR_THERMAL_TRIP_TYPE; i++) { - if (!strcmp(name, trip_type_name[i])) - return i; - } - - return -ENOENT; -} - -/* scan and fill in trip point info for a thermal zone and trip point id */ -static int get_trip_point_data(char *tz_path, int tzid, int tpid) -{ - char filename[256]; - char temp_str[256]; - int trip_type; - - if (tpid >= MAX_NR_TRIP) - return -EINVAL; - /* check trip point type */ - snprintf(filename, sizeof(filename), "trip_point_%d_type", tpid); - sysfs_get_string(tz_path, filename, temp_str); - trip_type = str_to_trip_type(temp_str); - if (trip_type < 0) { - syslog(LOG_ERR, "%s:%s no matching type\n", __func__, temp_str); - return -ENOENT; - } - ptdata.tzi[tzid].tp[tpid].type = trip_type; - syslog(LOG_INFO, "%s:tz:%d tp:%d:type:%s type id %d\n", __func__, tzid, - tpid, temp_str, trip_type); - - /* TODO: check attribute */ - - return 0; -} - -/* return instance id for file format such as trip_point_4_temp */ -static int get_instance_id(char *name, int pos, int skip) -{ - char *ch; - int i = 0; - - ch = strtok(name, "_"); - while (ch != NULL) { - ++i; - syslog(LOG_INFO, "%s:%s:%s:%d", __func__, name, ch, i); - ch = strtok(NULL, "_"); - if (pos == i) - return atol(ch + skip); - } - - return -1; -} - -/* Find trip point info of a thermal zone */ -static int find_tzone_tp(char *tz_name, char *d_name, struct tz_info *tzi, - int tz_id) -{ - int tp_id; - unsigned long temp_ulong; - - if (strstr(d_name, "trip_point") && - strstr(d_name, "temp")) { - /* check if trip point temp is non-zero - * ignore 0/invalid trip points - */ - sysfs_get_ulong(tz_name, d_name, &temp_ulong); - if (temp_ulong < MAX_TEMP_KC) { - tzi->nr_trip_pts++; - /* found a valid trip point */ - tp_id = get_instance_id(d_name, 2, 0); - syslog(LOG_DEBUG, "tzone %s trip %d temp %lu tpnode %s", - tz_name, tp_id, temp_ulong, d_name); - if (tp_id < 0 || tp_id >= MAX_NR_TRIP) { - syslog(LOG_ERR, "Failed to find TP inst %s\n", - d_name); - return -1; - } - get_trip_point_data(tz_name, tz_id, tp_id); - tzi->tp[tp_id].temp = temp_ulong; - } - } - - return 0; -} - -/* check cooling devices for binding info. */ -static int find_tzone_cdev(struct dirent *nl, char *tz_name, - struct tz_info *tzi, int tz_id, int cid) -{ - unsigned long trip_instance = 0; - char cdev_name_linked[256]; - char cdev_name[256]; - char cdev_trip_name[256]; - int cdev_id; - - if (nl->d_type == DT_LNK) { - syslog(LOG_DEBUG, "TZ%d: cdev: %s cid %d\n", tz_id, nl->d_name, - cid); - tzi->nr_cdev++; - if (tzi->nr_cdev > ptdata.nr_cooling_dev) { - syslog(LOG_ERR, "Err: Too many cdev? %d\n", - tzi->nr_cdev); - return -EINVAL; - } - /* find the link to real cooling device record binding */ - snprintf(cdev_name, 256, "%s/%s", tz_name, nl->d_name); - memset(cdev_name_linked, 0, sizeof(cdev_name_linked)); - if (readlink(cdev_name, cdev_name_linked, - sizeof(cdev_name_linked) - 1) != -1) { - cdev_id = get_instance_id(cdev_name_linked, 1, - sizeof("device") - 1); - syslog(LOG_DEBUG, "cdev %s linked to %s : %d\n", - cdev_name, cdev_name_linked, cdev_id); - tzi->cdev_binding |= (1 << cdev_id); - - /* find the trip point in which the cdev is binded to - * in this tzone - */ - snprintf(cdev_trip_name, 256, "%s%s", nl->d_name, - "_trip_point"); - sysfs_get_ulong(tz_name, cdev_trip_name, - &trip_instance); - /* validate trip point range, e.g. trip could return -1 - * when passive is enabled - */ - if (trip_instance > MAX_NR_TRIP) - trip_instance = 0; - tzi->trip_binding[cdev_id] |= 1 << trip_instance; - syslog(LOG_DEBUG, "cdev %s -> trip:%lu: 0x%lx %d\n", - cdev_name, trip_instance, - tzi->trip_binding[cdev_id], - cdev_id); - - - } - return 0; - } - - return -ENODEV; -} - - - -/***************************************************************************** - * Before calling scan_tzones, thermal sysfs must be probed to determine - * the number of thermal zones and cooling devices. - * We loop through each thermal zone and fill in tz_info struct, i.e. - * ptdata.tzi[] -root@jacob-chiefriver:~# tree -d /sys/class/thermal/thermal_zone0 -/sys/class/thermal/thermal_zone0 -|-- cdev0 -> ../cooling_device4 -|-- cdev1 -> ../cooling_device3 -|-- cdev10 -> ../cooling_device7 -|-- cdev11 -> ../cooling_device6 -|-- cdev12 -> ../cooling_device5 -|-- cdev2 -> ../cooling_device2 -|-- cdev3 -> ../cooling_device1 -|-- cdev4 -> ../cooling_device0 -|-- cdev5 -> ../cooling_device12 -|-- cdev6 -> ../cooling_device11 -|-- cdev7 -> ../cooling_device10 -|-- cdev8 -> ../cooling_device9 -|-- cdev9 -> ../cooling_device8 -|-- device -> ../../../LNXSYSTM:00/device:62/LNXTHERM:00 -|-- power -`-- subsystem -> ../../../../class/thermal -*****************************************************************************/ -static int scan_tzones(void) -{ - DIR *dir; - struct dirent **namelist; - char tz_name[256]; - int i, j, n, k = 0; - - if (!ptdata.nr_tz_sensor) - return -1; - - for (i = 0; i <= ptdata.max_tz_instance; i++) { - memset(tz_name, 0, sizeof(tz_name)); - snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, i); - - dir = opendir(tz_name); - if (!dir) { - syslog(LOG_INFO, "Thermal zone %s skipped\n", tz_name); - continue; - } - /* keep track of valid tzones */ - n = scandir(tz_name, &namelist, 0, alphasort); - if (n < 0) - syslog(LOG_ERR, "scandir failed in %s", tz_name); - else { - sysfs_get_string(tz_name, "type", ptdata.tzi[k].type); - ptdata.tzi[k].instance = i; - /* detect trip points and cdev attached to this tzone */ - j = 0; /* index for cdev */ - ptdata.tzi[k].nr_cdev = 0; - ptdata.tzi[k].nr_trip_pts = 0; - while (n--) { - char *temp_str; - - if (find_tzone_tp(tz_name, namelist[n]->d_name, - &ptdata.tzi[k], k)) - break; - temp_str = strstr(namelist[n]->d_name, "cdev"); - if (!temp_str) { - free(namelist[n]); - continue; - } - if (!find_tzone_cdev(namelist[n], tz_name, - &ptdata.tzi[k], i, j)) - j++; /* increment cdev index */ - free(namelist[n]); - } - free(namelist); - } - /*TODO: reverse trip points */ - closedir(dir); - syslog(LOG_INFO, "TZ %d has %d cdev\n", i, - ptdata.tzi[k].nr_cdev); - k++; - } - - return 0; -} - -static int scan_cdevs(void) -{ - DIR *dir; - struct dirent **namelist; - char cdev_name[256]; - int i, n, k = 0; - - if (!ptdata.nr_cooling_dev) { - fprintf(stderr, "No cooling devices found\n"); - return 0; - } - for (i = 0; i <= ptdata.max_cdev_instance; i++) { - memset(cdev_name, 0, sizeof(cdev_name)); - snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, i); - - dir = opendir(cdev_name); - if (!dir) { - syslog(LOG_INFO, "Cooling dev %s skipped\n", cdev_name); - /* there is a gap in cooling device id, check again - * for the same index. - */ - continue; - } - - n = scandir(cdev_name, &namelist, 0, alphasort); - if (n < 0) - syslog(LOG_ERR, "scandir failed in %s", cdev_name); - else { - sysfs_get_string(cdev_name, "type", ptdata.cdi[k].type); - ptdata.cdi[k].instance = i; - if (strstr(ptdata.cdi[k].type, ctrl_cdev)) { - ptdata.cdi[k].flag |= CDEV_FLAG_IN_CONTROL; - syslog(LOG_DEBUG, "control cdev id %d\n", i); - } - while (n--) - free(namelist[n]); - free(namelist); - } - closedir(dir); - k++; - } - return 0; -} - - -int probe_thermal_sysfs(void) -{ - DIR *dir; - struct dirent **namelist; - int n; - - dir = opendir(THERMAL_SYSFS); - if (!dir) { - fprintf(stderr, "\nNo thermal sysfs, exit\n"); - return -1; - } - n = scandir(THERMAL_SYSFS, &namelist, 0, alphasort); - if (n < 0) - syslog(LOG_ERR, "scandir failed in thermal sysfs"); - else { - /* detect number of thermal zones and cooling devices */ - while (n--) { - int inst; - - if (strstr(namelist[n]->d_name, CDEV)) { - inst = get_instance_id(namelist[n]->d_name, 1, - sizeof("device") - 1); - /* keep track of the max cooling device since - * there may be gaps. - */ - if (inst > ptdata.max_cdev_instance) - ptdata.max_cdev_instance = inst; - - syslog(LOG_DEBUG, "found cdev: %s %d %d\n", - namelist[n]->d_name, - ptdata.nr_cooling_dev, - ptdata.max_cdev_instance); - ptdata.nr_cooling_dev++; - } else if (strstr(namelist[n]->d_name, TZONE)) { - inst = get_instance_id(namelist[n]->d_name, 1, - sizeof("zone") - 1); - if (inst > ptdata.max_tz_instance) - ptdata.max_tz_instance = inst; - - syslog(LOG_DEBUG, "found tzone: %s %d %d\n", - namelist[n]->d_name, - ptdata.nr_tz_sensor, - ptdata.max_tz_instance); - ptdata.nr_tz_sensor++; - } - free(namelist[n]); - } - free(namelist); - } - syslog(LOG_INFO, "found %d tzone(s), %d cdev(s), target zone %d\n", - ptdata.nr_tz_sensor, ptdata.nr_cooling_dev, - target_thermal_zone); - closedir(dir); - - if (!ptdata.nr_tz_sensor) { - fprintf(stderr, "\nNo thermal zones found, exit\n\n"); - return -1; - } - - ptdata.tzi = calloc(sizeof(struct tz_info), ptdata.max_tz_instance+1); - if (!ptdata.tzi) { - fprintf(stderr, "Err: allocate tz_info\n"); - return -1; - } - - /* we still show thermal zone information if there is no cdev */ - if (ptdata.nr_cooling_dev) { - ptdata.cdi = calloc(sizeof(struct cdev_info), - ptdata.max_cdev_instance + 1); - if (!ptdata.cdi) { - free(ptdata.tzi); - fprintf(stderr, "Err: allocate cdev_info\n"); - return -1; - } - } - - /* now probe tzones */ - if (scan_tzones()) - return -1; - if (scan_cdevs()) - return -1; - return 0; -} - -/* convert sysfs zone instance to zone array index */ -int zone_instance_to_index(int zone_inst) -{ - int i; - - for (i = 0; i < ptdata.nr_tz_sensor; i++) - if (ptdata.tzi[i].instance == zone_inst) - return i; - return -ENOENT; -} - -/* read temperature of all thermal zones */ -int update_thermal_data() -{ - int i; - char tz_name[256]; - static unsigned long samples; - - if (!ptdata.nr_tz_sensor) { - syslog(LOG_ERR, "No thermal zones found!\n"); - return -1; - } - - /* circular buffer for keeping historic data */ - if (cur_thermal_record >= NR_THERMAL_RECORDS) - cur_thermal_record = 0; - gettimeofday(&trec[cur_thermal_record].tv, NULL); - if (tmon_log) { - fprintf(tmon_log, "%lu ", ++samples); - fprintf(tmon_log, "%3.1f ", p_param.t_target); - } - for (i = 0; i < ptdata.nr_tz_sensor; i++) { - memset(tz_name, 0, sizeof(tz_name)); - snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, - ptdata.tzi[i].instance); - sysfs_get_ulong(tz_name, "temp", - &trec[cur_thermal_record].temp[i]); - if (tmon_log) - fprintf(tmon_log, "%lu ", - trec[cur_thermal_record].temp[i]/1000); - } - for (i = 0; i < ptdata.nr_cooling_dev; i++) { - char cdev_name[256]; - unsigned long val; - - snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, - ptdata.cdi[i].instance); - probe_cdev(&ptdata.cdi[i], cdev_name); - val = ptdata.cdi[i].cur_state; - if (val > 1000000) - val = 0; - if (tmon_log) - fprintf(tmon_log, "%lu ", val); - } - - if (tmon_log) { - fprintf(tmon_log, "\n"); - fflush(tmon_log); - } - - return 0; -} - -void set_ctrl_state(unsigned long state) -{ - char ctrl_cdev_path[256]; - int i; - unsigned long cdev_state; - - if (no_control) - return; - /* set all ctrl cdev to the same state */ - for (i = 0; i < ptdata.nr_cooling_dev; i++) { - if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) { - if (ptdata.cdi[i].max_state < 10) { - strcpy(ctrl_cdev, "None."); - return; - } - /* scale to percentage of max_state */ - cdev_state = state * ptdata.cdi[i].max_state/100; - syslog(LOG_DEBUG, - "ctrl cdev %d set state %lu scaled to %lu\n", - ptdata.cdi[i].instance, state, cdev_state); - snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS, - CDEV, ptdata.cdi[i].instance); - syslog(LOG_DEBUG, "ctrl cdev path %s", ctrl_cdev_path); - sysfs_set_ulong(ctrl_cdev_path, "cur_state", - cdev_state); - } - } -} - -void get_ctrl_state(unsigned long *state) -{ - char ctrl_cdev_path[256]; - int ctrl_cdev_id = -1; - int i; - - /* TODO: take average of all ctrl types. also consider change based on - * uevent. Take the first reading for now. - */ - for (i = 0; i < ptdata.nr_cooling_dev; i++) { - if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) { - ctrl_cdev_id = ptdata.cdi[i].instance; - syslog(LOG_INFO, "ctrl cdev %d get state\n", - ptdata.cdi[i].instance); - break; - } - } - if (ctrl_cdev_id == -1) { - *state = 0; - return; - } - snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS, - CDEV, ctrl_cdev_id); - sysfs_get_ulong(ctrl_cdev_path, "cur_state", state); -} - -void free_thermal_data(void) -{ - free(ptdata.tzi); - free(ptdata.cdi); -} diff --git a/tools/thermal/tmon/tmon.8 b/tools/thermal/tmon/tmon.8 deleted file mode 100644 index 0be727c..0000000 --- a/tools/thermal/tmon/tmon.8 +++ /dev/null @@ -1,142 +0,0 @@ -.TH TMON 8 -.SH NAME -\fBtmon\fP - A monitoring and testing tool for Linux kernel thermal subsystem - -.SH SYNOPSIS -.ft B -.B tmon -.RB [ Options ] -.br -.SH DESCRIPTION -\fBtmon \fP can be used to visualize thermal relationship and -real-time thermal data; tune -and test cooling devices and sensors; collect thermal data for offline -analysis and plot. \fBtmon\fP must be run as root in order to control device -states via sysfs. -.PP -\fBFunctions\fP -.PP -.nf -1. Thermal relationships: -- show thermal zone information -- show cooling device information -- show trip point binding within each thermal zone -- show trip point and cooling device instance bindings -.PP -2. Real time data display -- show temperature of all thermal zones w.r.t. its trip points and types -- show states of all cooling devices -.PP -3. Thermal relationship learning and device tuning -- with a built-in Proportional Integral Derivative (\fBPID\fP) -controller, user can pair a cooling device to a thermal sensor for -testing the effectiveness and learn about the thermal distance between the two -- allow manual control of cooling device states and target temperature -.PP -4. Data logging in /var/tmp/tmon.log -- contains thermal configuration data, i.e. cooling device, thermal - zones, and trip points. Can be used for data collection in remote - debugging. -- log real-time thermal data into space separated format that can be - directly consumed by plotting tools such as Rscript. - -.SS Options -.PP -The \fB-c --control\fP option sets a cooling device type to control temperature -of a thermal zone -.PP -The \fB-d --daemon\fP option runs \fBtmon \fP as daemon without user interface -.PP -The \fB-g --debug\fP option allow debug messages to be stored in syslog -.PP -The \fB-h --help\fP option shows help message -.PP -The \fB-l --log\fP option write data to /var/tmp/tmon.log -.PP -The \fB-t --time-interval\fP option sets the polling interval in seconds -.PP -The \fB-v --version\fP option shows the version of \fBtmon \fP -.PP -The \fB-z --zone\fP option sets the target therma zone instance to be controlled -.PP - -.SH FIELD DESCRIPTIONS -.nf -.PP -\fBP \fP passive cooling trip point type -\fBA \fP active cooling trip point type (fan) -\fBC \fP critical trip point type -\fBA \fP hot trip point type -\fBkp \fP proportional gain of \fBPID\fP controller -\fBki \fP integral gain of \fBPID\fP controller -\fBkd \fP derivative gain of \fBPID\fP controller - -.SH REQUIREMENT -Build depends on ncurses -.PP -Runtime depends on window size large enough to show the number of -devices found on the system. - -.PP - -.SH INTERACTIVE COMMANDS -.pp -.nf -\fBCtrl-C, q/Q\fP stops \fBtmon\fP -\fBTAB\fP shows tuning pop up panel, choose a letter to modify - -.SH EXAMPLES -Without any parameters, tmon is in monitoring only mode and refresh -screen every 1 second. -.PP -1. For monitoring only: -.nf -$ sudo ./tmon - -2. Use Processor cooling device to control thermal zone 0 at default 65C. -$ sudo ./tmon -c Processor -z 0 - -3. Use intel_powerclamp(idle injection) cooling device to control thermal zone 1 -$ sudo ./tmon -c intel_powerclamp -z 1 - -4. Turn on debug and collect data log at /var/tmp/tmon.log -$ sudo ./tmon -g -l - -For example, the log below shows PID controller was adjusting current states -for all cooling devices with "Processor" type such that thermal zone 0 -can stay below 65 dC. - -#---------- THERMAL DATA LOG STARTED ----------- -Samples TargetTemp acpitz0 acpitz1 Fan0 Fan1 Fan2 Fan3 Fan4 Fan5 -Fan6 Fan7 Fan8 Fan9 Processor10 Processor11 Processor12 Processor13 -LCD14 intel_powerclamp15 1 65.0 65 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 2 -65.0 66 65 0 0 0 0 0 0 0 0 0 0 4 4 4 4 6 0 3 65.0 60 54 0 0 0 0 0 0 0 0 -0 0 4 4 4 4 6 0 4 65.0 53 53 0 0 0 0 0 0 0 0 0 0 4 4 4 4 6 0 -5 65.0 52 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 -6 65.0 53 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 -7 65.0 68 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 -8 65.0 68 68 0 0 0 0 0 0 0 0 0 0 5 5 5 5 6 0 -9 65.0 68 68 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 0 -10 65.0 67 67 0 0 0 0 0 0 0 0 0 0 7 7 7 7 6 0 -11 65.0 67 67 0 0 0 0 0 0 0 0 0 0 8 8 8 8 6 0 -12 65.0 67 67 0 0 0 0 0 0 0 0 0 0 8 8 8 8 6 0 -13 65.0 67 67 0 0 0 0 0 0 0 0 0 0 9 9 9 9 6 0 -14 65.0 66 66 0 0 0 0 0 0 0 0 0 0 10 10 10 10 6 0 -15 65.0 66 67 0 0 0 0 0 0 0 0 0 0 10 10 10 10 6 0 -16 65.0 66 66 0 0 0 0 0 0 0 0 0 0 11 11 11 11 6 0 -17 65.0 66 66 0 0 0 0 0 0 0 0 0 0 11 11 11 11 6 0 -18 65.0 64 61 0 0 0 0 0 0 0 0 0 0 11 11 11 11 6 0 -19 65.0 60 59 0 0 0 0 0 0 0 0 0 0 12 12 12 12 6 0 - -Data can be read directly into an array by an example R-script below: - -#!/usr/bin/Rscript -tdata <- read.table("/var/tmp/tmon.log", header=T, comment.char="#") -attach(tdata) -jpeg("tmon.jpg") -X11() -g_range <- range(0, intel_powerclamp15, TargetTemp, acpitz0) -plot( Samples, intel_powerclamp15, col="blue", ylim=g_range, axes=FALSE, ann=FALSE) -par(new=TRUE) -lines(TargetTemp, type="o", pch=22, lty=2, col="red") -dev.off() diff --git a/tools/thermal/tmon/tmon.c b/tools/thermal/tmon/tmon.c deleted file mode 100644 index b30f531..0000000 --- a/tools/thermal/tmon/tmon.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * tmon.c Thermal Monitor (TMON) main function and entry point - * - * Copyright (C) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 or later as published by the Free Software Foundation. - * - * 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. - * - * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> - * - */ - -#include <getopt.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <ncurses.h> -#include <ctype.h> -#include <time.h> -#include <signal.h> -#include <limits.h> -#include <sys/time.h> -#include <pthread.h> -#include <math.h> -#include <stdarg.h> -#include <syslog.h> - -#include "tmon.h" - -unsigned long ticktime = 1; /* seconds */ -unsigned long no_control = 1; /* monitoring only or use cooling device for - * temperature control. - */ -double time_elapsed = 0.0; -unsigned long target_temp_user = 65; /* can be select by tui later */ -int dialogue_on; -int tmon_exit; -static short daemon_mode; -static int logging; /* for recording thermal data to a file */ -static int debug_on; -FILE *tmon_log; -/*cooling device used for the PID controller */ -char ctrl_cdev[CDEV_NAME_SIZE] = "None"; -int target_thermal_zone; /* user selected target zone instance */ -static void start_daemon_mode(void); - -pthread_t event_tid; -pthread_mutex_t input_lock; -void usage() -{ - printf("Usage: tmon [OPTION...]\n"); - printf(" -c, --control cooling device in control\n"); - printf(" -d, --daemon run as daemon, no TUI\n"); - printf(" -g, --debug debug message in syslog\n"); - printf(" -h, --help show this help message\n"); - printf(" -l, --log log data to /var/tmp/tmon.log\n"); - printf(" -t, --time-interval sampling time interval, > 1 sec.\n"); - printf(" -v, --version show version\n"); - printf(" -z, --zone target thermal zone id\n"); - - exit(0); -} - -void version() -{ - printf("TMON version %s\n", VERSION); - exit(EXIT_SUCCESS); -} - -static void tmon_cleanup(void) -{ - - syslog(LOG_INFO, "TMON exit cleanup\n"); - fflush(stdout); - refresh(); - if (tmon_log) - fclose(tmon_log); - if (event_tid) { - pthread_mutex_lock(&input_lock); - pthread_cancel(event_tid); - pthread_mutex_unlock(&input_lock); - pthread_mutex_destroy(&input_lock); - } - closelog(); - /* relax control knobs, undo throttling */ - set_ctrl_state(0); - - keypad(stdscr, FALSE); - echo(); - nocbreak(); - close_windows(); - endwin(); - free_thermal_data(); - - exit(1); -} - - -static void tmon_sig_handler(int sig) -{ - syslog(LOG_INFO, "TMON caught signal %d\n", sig); - refresh(); - switch (sig) { - case SIGTERM: - printf("sigterm, exit and clean up\n"); - fflush(stdout); - break; - case SIGKILL: - printf("sigkill, exit and clean up\n"); - fflush(stdout); - break; - case SIGINT: - printf("ctrl-c, exit and clean up\n"); - fflush(stdout); - break; - default: - break; - } - tmon_exit = true; -} - - -static void start_syslog(void) -{ - if (debug_on) - setlogmask(LOG_UPTO(LOG_DEBUG)); - else - setlogmask(LOG_UPTO(LOG_ERR)); - openlog("tmon.log", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0); - syslog(LOG_NOTICE, "TMON started by User %d", getuid()); -} - -static void prepare_logging(void) -{ - int i; - - if (!logging) - return; - /* open local data log file */ - tmon_log = fopen(TMON_LOG_FILE, "w+"); - if (!tmon_log) { - syslog(LOG_ERR, "failed to open log file %s\n", TMON_LOG_FILE); - return; - } - - fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n"); - for (i = 0; i < ptdata.nr_tz_sensor; i++) { - char binding_str[33]; /* size of long + 1 */ - int j; - - memset(binding_str, 0, sizeof(binding_str)); - for (j = 0; j < 32; j++) - binding_str[j] = (ptdata.tzi[i].cdev_binding & 1<<j) ? - '1' : '0'; - - fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n", - ptdata.tzi[i].type, - ptdata.tzi[i].instance, - binding_str); - for (j = 0; j < ptdata.tzi[i].nr_trip_pts; j++) { - fprintf(tmon_log, "#\tTP%02d type:%s, temp:%lu\n", j, - trip_type_name[ptdata.tzi[i].tp[j].type], - ptdata.tzi[i].tp[j].temp); - } - - } - - for (i = 0; i < ptdata.nr_cooling_dev; i++) - fprintf(tmon_log, "#cooling devices%02d: %s\n", - i, ptdata.cdi[i].type); - - fprintf(tmon_log, "#---------- THERMAL DATA LOG STARTED -----------\n"); - fprintf(tmon_log, "Samples TargetTemp "); - for (i = 0; i < ptdata.nr_tz_sensor; i++) { - fprintf(tmon_log, "%s%d ", ptdata.tzi[i].type, - ptdata.tzi[i].instance); - } - for (i = 0; i < ptdata.nr_cooling_dev; i++) - fprintf(tmon_log, "%s%d ", ptdata.cdi[i].type, - ptdata.cdi[i].instance); - - fprintf(tmon_log, "\n"); -} - -static struct option opts[] = { - { "control", 1, NULL, 'c' }, - { "daemon", 0, NULL, 'd' }, - { "time-interval", 1, NULL, 't' }, - { "log", 0, NULL, 'l' }, - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'v' }, - { "debug", 0, NULL, 'g' }, - { 0, 0, NULL, 0 } -}; - - -int main(int argc, char **argv) -{ - int err = 0; - int id2 = 0, c; - double yk = 0.0; /* controller output */ - int target_tz_index; - - if (geteuid() != 0) { - printf("TMON needs to be run as root\n"); - exit(EXIT_FAILURE); - } - - while ((c = getopt_long(argc, argv, "c:dlht:vgz:", opts, &id2)) != -1) { - switch (c) { - case 'c': - no_control = 0; - strncpy(ctrl_cdev, optarg, CDEV_NAME_SIZE); - break; - case 'd': - start_daemon_mode(); - printf("Run TMON in daemon mode\n"); - break; - case 't': - ticktime = strtod(optarg, NULL); - if (ticktime < 1) - ticktime = 1; - break; - case 'l': - printf("Logging data to /var/tmp/tmon.log\n"); - logging = 1; - break; - case 'h': - usage(); - break; - case 'v': - version(); - break; - case 'g': - debug_on = 1; - break; - case 'z': - target_thermal_zone = strtod(optarg, NULL); - break; - default: - break; - } - } - if (pthread_mutex_init(&input_lock, NULL) != 0) { - fprintf(stderr, "\n mutex init failed, exit\n"); - return 1; - } - start_syslog(); - if (signal(SIGINT, tmon_sig_handler) == SIG_ERR) - syslog(LOG_DEBUG, "Cannot handle SIGINT\n"); - if (signal(SIGTERM, tmon_sig_handler) == SIG_ERR) - syslog(LOG_DEBUG, "Cannot handle SIGINT\n"); - - if (probe_thermal_sysfs()) { - pthread_mutex_destroy(&input_lock); - closelog(); - return -1; - } - initialize_curses(); - setup_windows(); - signal(SIGWINCH, resize_handler); - show_title_bar(); - show_sensors_w(); - show_cooling_device(); - update_thermal_data(); - show_data_w(); - prepare_logging(); - init_thermal_controller(); - - nodelay(stdscr, TRUE); - err = pthread_create(&event_tid, NULL, &handle_tui_events, NULL); - if (err != 0) { - printf("\ncan't create thread :[%s]", strerror(err)); - tmon_cleanup(); - exit(EXIT_FAILURE); - } - - /* validate range of user selected target zone, default to the first - * instance if out of range - */ - target_tz_index = zone_instance_to_index(target_thermal_zone); - if (target_tz_index < 0) { - target_thermal_zone = ptdata.tzi[0].instance; - syslog(LOG_ERR, "target zone is not found, default to %d\n", - target_thermal_zone); - } - while (1) { - sleep(ticktime); - show_title_bar(); - show_sensors_w(); - update_thermal_data(); - if (!dialogue_on) { - show_data_w(); - show_cooling_device(); - } - cur_thermal_record++; - time_elapsed += ticktime; - controller_handler(trec[0].temp[target_tz_index] / 1000, - &yk); - trec[0].pid_out_pct = yk; - if (!dialogue_on) - show_control_w(); - if (tmon_exit) - break; - } - tmon_cleanup(); - return 0; -} - -static void start_daemon_mode() -{ - daemon_mode = 1; - /* fork */ - pid_t sid, pid = fork(); - if (pid < 0) { - exit(EXIT_FAILURE); - } else if (pid > 0) - /* kill parent */ - exit(EXIT_SUCCESS); - - /* disable TUI, it may not be necessary, but saves some resource */ - disable_tui(); - - /* change the file mode mask */ - umask(0); - - /* new SID for the daemon process */ - sid = setsid(); - if (sid < 0) - exit(EXIT_FAILURE); - - /* change working directory */ - if ((chdir("/")) < 0) - exit(EXIT_FAILURE); - - - sleep(10); - - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - -} diff --git a/tools/thermal/tmon/tmon.h b/tools/thermal/tmon/tmon.h deleted file mode 100644 index 9e3c49c..0000000 --- a/tools/thermal/tmon/tmon.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * tmon.h contains data structures and constants used by TMON - * - * Copyright (C) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 or later as published by the Free Software Foundation. - * - * 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. - * - * Author Name Jacob Pan <jacob.jun.pan@linux.intel.com> - * - */ - -#ifndef TMON_H -#define TMON_H - -#define MAX_DISP_TEMP 125 -#define MAX_CTRL_TEMP 105 -#define MIN_CTRL_TEMP 40 -#define MAX_NR_TZONE 16 -#define MAX_NR_CDEV 32 -#define MAX_NR_TRIP 16 -#define MAX_NR_CDEV_TRIP 12 /* number of cooling devices that can bind - * to a thermal zone trip. - */ -#define MAX_TEMP_KC 140000 -/* starting char position to draw sensor data, such as tz names - * trip point list, etc. - */ -#define DATA_LEFT_ALIGN 10 -#define NR_LINES_TZDATA 1 -#define TMON_LOG_FILE "/var/tmp/tmon.log" - -extern unsigned long ticktime; -extern double time_elapsed; -extern unsigned long target_temp_user; -extern int dialogue_on; -extern char ctrl_cdev[]; -extern pthread_mutex_t input_lock; -extern int tmon_exit; -extern int target_thermal_zone; -/* use fixed size record to simplify data processing and transfer - * TBD: more info to be added, e.g. programmable trip point data. -*/ -struct thermal_data_record { - struct timeval tv; - unsigned long temp[MAX_NR_TZONE]; - double pid_out_pct; -}; - -struct cdev_info { - char type[64]; - int instance; - unsigned long max_state; - unsigned long cur_state; - unsigned long flag; -}; - -enum trip_type { - THERMAL_TRIP_CRITICAL, - THERMAL_TRIP_HOT, - THERMAL_TRIP_PASSIVE, - THERMAL_TRIP_ACTIVE, - NR_THERMAL_TRIP_TYPE, -}; - -struct trip_point { - enum trip_type type; - unsigned long temp; - unsigned long hysteresis; - int attribute; /* programmability etc. */ -}; - -/* thermal zone configuration information, binding with cooling devices could - * change at runtime. - */ -struct tz_info { - char type[256]; /* e.g. acpitz */ - int instance; - int passive; /* active zone has passive node to force passive mode */ - int nr_cdev; /* number of cooling device binded */ - int nr_trip_pts; - struct trip_point tp[MAX_NR_TRIP]; - unsigned long cdev_binding; /* bitmap for attached cdevs */ - /* cdev bind trip points, allow one cdev bind to multiple trips */ - unsigned long trip_binding[MAX_NR_CDEV]; -}; - -struct tmon_platform_data { - int nr_tz_sensor; - int nr_cooling_dev; - /* keep track of instance ids since there might be gaps */ - int max_tz_instance; - int max_cdev_instance; - struct tz_info *tzi; - struct cdev_info *cdi; -}; - -struct control_ops { - void (*set_ratio)(unsigned long ratio); - unsigned long (*get_ratio)(unsigned long ratio); - -}; - -enum cdev_types { - CDEV_TYPE_PROC, - CDEV_TYPE_FAN, - CDEV_TYPE_MEM, - CDEV_TYPE_NR, -}; - -/* REVISIT: the idea is to group sensors if possible, e.g. on intel mid - * we have "skin0", "skin1", "sys", "msicdie" - * on DPTF enabled systems, we might have PCH, TSKN, TAMB, etc. - */ -enum tzone_types { - TZONE_TYPE_ACPI, - TZONE_TYPE_PCH, - TZONE_TYPE_NR, -}; - -/* limit the output of PID controller adjustment */ -#define LIMIT_HIGH (95) -#define LIMIT_LOW (2) - -struct pid_params { - double kp; /* Controller gain from Dialog Box */ - double ki; /* Time-constant for I action from Dialog Box */ - double kd; /* Time-constant for D action from Dialog Box */ - double ts; - double k_lpf; - - double t_target; - double y_k; -}; - -extern int init_thermal_controller(void); -extern void controller_handler(const double xk, double *yk); - -extern struct tmon_platform_data ptdata; -extern struct pid_params p_param; - -extern FILE *tmon_log; -extern int cur_thermal_record; /* index to the trec array */ -extern struct thermal_data_record trec[]; -extern const char *trip_type_name[]; -extern unsigned long no_control; - -extern void initialize_curses(void); -extern void show_controller_stats(char *line); -extern void show_title_bar(void); -extern void setup_windows(void); -extern void disable_tui(void); -extern void show_sensors_w(void); -extern void show_data_w(void); -extern void write_status_bar(int x, char *line); -extern void show_control_w(); - -extern void show_cooling_device(void); -extern void show_dialogue(void); -extern int update_thermal_data(void); - -extern int probe_thermal_sysfs(void); -extern void free_thermal_data(void); -extern void resize_handler(int sig); -extern void set_ctrl_state(unsigned long state); -extern void get_ctrl_state(unsigned long *state); -extern void *handle_tui_events(void *arg); -extern int sysfs_set_ulong(char *path, char *filename, unsigned long val); -extern int zone_instance_to_index(int zone_inst); -extern void close_windows(void); - -#define PT_COLOR_DEFAULT 1 -#define PT_COLOR_HEADER_BAR 2 -#define PT_COLOR_ERROR 3 -#define PT_COLOR_RED 4 -#define PT_COLOR_YELLOW 5 -#define PT_COLOR_GREEN 6 -#define PT_COLOR_BRIGHT 7 -#define PT_COLOR_BLUE 8 - -/* each thermal zone uses 12 chars, 8 for name, 2 for instance, 2 space - * also used to list trip points in forms of AAAC, which represents - * A: Active - * C: Critical - */ -#define TZONE_RECORD_SIZE 12 -#define TZ_LEFT_ALIGN 32 -#define CDEV_NAME_SIZE 20 -#define CDEV_FLAG_IN_CONTROL (1 << 0) - -/* dialogue box starts */ -#define DIAG_X 48 -#define DIAG_Y 8 -#define THERMAL_SYSFS "/sys/class/thermal" -#define CDEV "cooling_device" -#define TZONE "thermal_zone" -#define TDATA_LEFT 16 -#endif /* TMON_H */ diff --git a/tools/thermal/tmon/tui.c b/tools/thermal/tmon/tui.c deleted file mode 100644 index 89f8ef0..0000000 --- a/tools/thermal/tmon/tui.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - * tui.c ncurses text user interface for TMON program - * - * Copyright (C) 2013 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 or later as published by the Free Software Foundation. - * - * 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. - * - * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> - * - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <ncurses.h> -#include <time.h> -#include <syslog.h> -#include <panel.h> -#include <pthread.h> -#include <signal.h> - -#include "tmon.h" - -static PANEL *data_panel; -static PANEL *dialogue_panel; -static PANEL *top; - -static WINDOW *title_bar_window; -static WINDOW *tz_sensor_window; -static WINDOW *cooling_device_window; -static WINDOW *control_window; -static WINDOW *status_bar_window; -static WINDOW *thermal_data_window; -static WINDOW *dialogue_window; - -char status_bar_slots[10][40]; -static void draw_hbar(WINDOW *win, int y, int start, int len, - unsigned long pattern, bool end); - -static int maxx, maxy; -static int maxwidth = 200; - -#define TITLE_BAR_HIGHT 1 -#define SENSOR_WIN_HIGHT 4 /* one row for tz name, one for trip points */ - - -/* daemon mode flag (set by startup parameter -d) */ -static int tui_disabled; - -static void close_panel(PANEL *p) -{ - if (p) { - del_panel(p); - p = NULL; - } -} - -static void close_window(WINDOW *win) -{ - if (win) { - delwin(win); - win = NULL; - } -} - -void close_windows(void) -{ - if (tui_disabled) - return; - /* must delete panels before their attached windows */ - if (dialogue_window) - close_panel(dialogue_panel); - if (cooling_device_window) - close_panel(data_panel); - - close_window(title_bar_window); - close_window(tz_sensor_window); - close_window(status_bar_window); - close_window(cooling_device_window); - close_window(control_window); - close_window(thermal_data_window); - close_window(dialogue_window); - -} - -void write_status_bar(int x, char *line) -{ - mvwprintw(status_bar_window, 0, x, "%s", line); - wrefresh(status_bar_window); -} - -void setup_windows(void) -{ - int y_begin = 1; - - if (tui_disabled) - return; - - getmaxyx(stdscr, maxy, maxx); - resizeterm(maxy, maxx); - - title_bar_window = subwin(stdscr, TITLE_BAR_HIGHT, maxx, 0, 0); - y_begin += TITLE_BAR_HIGHT; - - tz_sensor_window = subwin(stdscr, SENSOR_WIN_HIGHT, maxx, y_begin, 0); - y_begin += SENSOR_WIN_HIGHT; - - cooling_device_window = subwin(stdscr, ptdata.nr_cooling_dev + 3, maxx, - y_begin, 0); - y_begin += ptdata.nr_cooling_dev + 3; /* 2 lines for border */ - /* two lines to show borders, one line per tz show trip point position - * and value. - * dialogue window is a pop-up, when needed it lays on top of cdev win - */ - - dialogue_window = subwin(stdscr, ptdata.nr_cooling_dev+5, maxx-50, - DIAG_Y, DIAG_X); - - thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor * - NR_LINES_TZDATA + 3, maxx, y_begin, 0); - y_begin += ptdata.nr_tz_sensor * NR_LINES_TZDATA + 3; - control_window = subwin(stdscr, 4, maxx, y_begin, 0); - - scrollok(cooling_device_window, TRUE); - maxwidth = maxx - 18; - status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0); - - strcpy(status_bar_slots[0], " Ctrl-c - Quit "); - strcpy(status_bar_slots[1], " TAB - Tuning "); - wmove(status_bar_window, 1, 30); - - /* prepare panels for dialogue, if panel already created then we must - * be doing resizing, so just replace windows with new ones, old ones - * should have been deleted by close_window - */ - data_panel = new_panel(cooling_device_window); - if (!data_panel) - syslog(LOG_DEBUG, "No data panel\n"); - else { - if (dialogue_window) { - dialogue_panel = new_panel(dialogue_window); - if (!dialogue_panel) - syslog(LOG_DEBUG, "No dialogue panel\n"); - else { - /* Set up the user pointer to the next panel*/ - set_panel_userptr(data_panel, dialogue_panel); - set_panel_userptr(dialogue_panel, data_panel); - top = data_panel; - } - } else - syslog(LOG_INFO, "no dialogue win, term too small\n"); - } - doupdate(); - werase(stdscr); - refresh(); -} - -void resize_handler(int sig) -{ - /* start over when term gets resized, but first we clean up */ - close_windows(); - endwin(); - refresh(); - clear(); - getmaxyx(stdscr, maxy, maxx); /* get the new screen size */ - setup_windows(); - /* rate limit */ - sleep(1); - syslog(LOG_DEBUG, "SIG %d, term resized to %d x %d\n", - sig, maxy, maxx); - signal(SIGWINCH, resize_handler); -} - -const char cdev_title[] = " COOLING DEVICES "; -void show_cooling_device(void) -{ - int i, j, x, y = 0; - - if (tui_disabled || !cooling_device_window) - return; - - werase(cooling_device_window); - wattron(cooling_device_window, A_BOLD); - mvwprintw(cooling_device_window, 1, 1, - "ID Cooling Dev Cur Max Thermal Zone Binding"); - wattroff(cooling_device_window, A_BOLD); - for (j = 0; j < ptdata.nr_cooling_dev; j++) { - /* draw cooling device list on the left in the order of - * cooling device instances. skip unused idr. - */ - mvwprintw(cooling_device_window, j + 2, 1, - "%02d %12.12s%6d %6d", - ptdata.cdi[j].instance, - ptdata.cdi[j].type, - ptdata.cdi[j].cur_state, - ptdata.cdi[j].max_state); - } - - /* show cdev binding, y is the global cooling device instance */ - for (i = 0; i < ptdata.nr_tz_sensor; i++) { - int tz_inst = ptdata.tzi[i].instance; - for (j = 0; j < ptdata.nr_cooling_dev; j++) { - int cdev_inst; - y = j; - x = tz_inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN; - - draw_hbar(cooling_device_window, y+2, x, - TZONE_RECORD_SIZE-1, ACS_VLINE, false); - - /* draw a column of spaces to separate thermal zones */ - mvwprintw(cooling_device_window, y+2, x-1, " "); - if (ptdata.tzi[i].cdev_binding) { - cdev_inst = ptdata.cdi[j].instance; - unsigned long trip_binding = - ptdata.tzi[i].trip_binding[cdev_inst]; - int k = 0; /* per zone trip point id that - * binded to this cdev, one to - * many possible based on the - * binding bitmask. - */ - syslog(LOG_DEBUG, - "bind tz%d cdev%d tp%lx %d cdev%lx\n", - i, j, trip_binding, y, - ptdata.tzi[i].cdev_binding); - /* draw each trip binding for the cdev */ - while (trip_binding >>= 1) { - k++; - if (!(trip_binding & 1)) - continue; - /* draw '*' to show binding */ - mvwprintw(cooling_device_window, - y + 2, - x + ptdata.tzi[i].nr_trip_pts - - k - 1, "*"); - } - } - } - } - /* draw border after data so that border will not be messed up - * even there is not enough space for all the data to be shown - */ - wborder(cooling_device_window, 0, 0, 0, 0, 0, 0, 0, 0); - wattron(cooling_device_window, A_BOLD); - mvwprintw(cooling_device_window, 0, maxx/2 - sizeof(cdev_title), - cdev_title); - wattroff(cooling_device_window, A_BOLD); - - wrefresh(cooling_device_window); -} - -const char DIAG_TITLE[] = "[ TUNABLES ]"; -#define DIAG_DEV_ROWS 5 -void show_dialogue(void) -{ - int j, x = 0, y = 0; - WINDOW *w = dialogue_window; - - if (tui_disabled || !w) - return; - - werase(w); - box(w, 0, 0); - mvwprintw(w, 0, maxx/4, DIAG_TITLE); - /* list all the available tunables */ - for (j = 0; j <= ptdata.nr_cooling_dev; j++) { - y = j % DIAG_DEV_ROWS; - if (y == 0 && j != 0) - x += 20; - if (j == ptdata.nr_cooling_dev) - /* save last choice for target temp */ - mvwprintw(w, y+1, x+1, "%C-%.12s", 'A'+j, "Set Temp"); - else - mvwprintw(w, y+1, x+1, "%C-%.10s-%2d", 'A'+j, - ptdata.cdi[j].type, ptdata.cdi[j].instance); - } - wattron(w, A_BOLD); - mvwprintw(w, DIAG_DEV_ROWS+1, 1, "Enter Choice [A-Z]?"); - wattroff(w, A_BOLD); - /* y size of dialogue win is nr cdev + 5, so print legend - * at the bottom line - */ - mvwprintw(w, ptdata.nr_cooling_dev+3, 1, - "Legend: A=Active, P=Passive, C=Critical"); - - wrefresh(dialogue_window); -} - -void write_dialogue_win(char *buf, int y, int x) -{ - WINDOW *w = dialogue_window; - - mvwprintw(w, y, x, "%s", buf); -} - -const char control_title[] = " CONTROLS "; -void show_control_w(void) -{ - unsigned long state; - - get_ctrl_state(&state); - - if (tui_disabled || !control_window) - return; - - werase(control_window); - mvwprintw(control_window, 1, 1, - "PID gain: kp=%2.2f ki=%2.2f kd=%2.2f Output %2.2f", - p_param.kp, p_param.ki, p_param.kd, p_param.y_k); - - mvwprintw(control_window, 2, 1, - "Target Temp: %2.1fC, Zone: %d, Control Device: %.12s", - p_param.t_target, target_thermal_zone, ctrl_cdev); - - /* draw border last such that everything is within boundary */ - wborder(control_window, 0, 0, 0, 0, 0, 0, 0, 0); - wattron(control_window, A_BOLD); - mvwprintw(control_window, 0, maxx/2 - sizeof(control_title), - control_title); - wattroff(control_window, A_BOLD); - - wrefresh(control_window); -} - -void initialize_curses(void) -{ - if (tui_disabled) - return; - - initscr(); - start_color(); - keypad(stdscr, TRUE); /* enable keyboard mapping */ - nonl(); /* tell curses not to do NL->CR/NL on output */ - cbreak(); /* take input chars one at a time */ - noecho(); /* dont echo input */ - curs_set(0); /* turn off cursor */ - use_default_colors(); - - init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); - init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); - init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); - init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); - init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); - init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); - init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE); - init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); - -} - -void show_title_bar(void) -{ - int i; - int x = 0; - - if (tui_disabled || !title_bar_window) - return; - - wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); - wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); - werase(title_bar_window); - - mvwprintw(title_bar_window, 0, 0, - " TMON v%s", VERSION); - - wrefresh(title_bar_window); - - werase(status_bar_window); - - for (i = 0; i < 10; i++) { - if (strlen(status_bar_slots[i]) == 0) - continue; - wattron(status_bar_window, A_REVERSE); - mvwprintw(status_bar_window, 0, x, "%s", status_bar_slots[i]); - wattroff(status_bar_window, A_REVERSE); - x += strlen(status_bar_slots[i]) + 1; - } - wrefresh(status_bar_window); -} - -static void handle_input_val(int ch) -{ - char buf[32]; - int val; - char path[256]; - WINDOW *w = dialogue_window; - - echo(); - keypad(w, TRUE); - wgetnstr(w, buf, 31); - val = atoi(buf); - - if (ch == ptdata.nr_cooling_dev) { - snprintf(buf, 31, "Invalid Temp %d! %d-%d", val, - MIN_CTRL_TEMP, MAX_CTRL_TEMP); - if (val < MIN_CTRL_TEMP || val > MAX_CTRL_TEMP) - write_status_bar(40, buf); - else { - p_param.t_target = val; - snprintf(buf, 31, "Set New Target Temp %d", val); - write_status_bar(40, buf); - } - } else { - snprintf(path, 256, "%s/%s%d", THERMAL_SYSFS, - CDEV, ptdata.cdi[ch].instance); - sysfs_set_ulong(path, "cur_state", val); - } - noecho(); - dialogue_on = 0; - show_data_w(); - show_control_w(); - - top = (PANEL *)panel_userptr(top); - top_panel(top); -} - -static void handle_input_choice(int ch) -{ - char buf[48]; - int base = 0; - int cdev_id = 0; - - if ((ch >= 'A' && ch <= 'A' + ptdata.nr_cooling_dev) || - (ch >= 'a' && ch <= 'a' + ptdata.nr_cooling_dev)) { - base = (ch < 'a') ? 'A' : 'a'; - cdev_id = ch - base; - if (ptdata.nr_cooling_dev == cdev_id) - snprintf(buf, sizeof(buf), "New Target Temp:"); - else - snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ", - ptdata.cdi[cdev_id].type, - ptdata.cdi[cdev_id].instance); - write_dialogue_win(buf, DIAG_DEV_ROWS+2, 2); - handle_input_val(cdev_id); - } else { - snprintf(buf, sizeof(buf), "Invalid selection %d", ch); - write_dialogue_win(buf, 8, 2); - } -} - -void *handle_tui_events(void *arg) -{ - int ch; - - keypad(cooling_device_window, TRUE); - while ((ch = wgetch(cooling_device_window)) != EOF) { - if (tmon_exit) - break; - /* when term size is too small, no dialogue panels are set. - * we need to filter out such cases. - */ - if (!data_panel || !dialogue_panel || - !cooling_device_window || - !dialogue_window) { - - continue; - } - pthread_mutex_lock(&input_lock); - if (dialogue_on) { - handle_input_choice(ch); - /* top panel filter */ - if (ch == 'q' || ch == 'Q') - ch = 0; - } - switch (ch) { - case KEY_LEFT: - box(cooling_device_window, 10, 0); - break; - case 9: /* TAB */ - top = (PANEL *)panel_userptr(top); - top_panel(top); - if (top == dialogue_panel) { - dialogue_on = 1; - show_dialogue(); - } else { - dialogue_on = 0; - /* force refresh */ - show_data_w(); - show_control_w(); - } - break; - case 'q': - case 'Q': - tmon_exit = 1; - break; - } - update_panels(); - doupdate(); - pthread_mutex_unlock(&input_lock); - } - - if (arg) - *(int *)arg = 0; /* make gcc happy */ - - return NULL; -} - -/* draw a horizontal bar in given pattern */ -static void draw_hbar(WINDOW *win, int y, int start, int len, unsigned long ptn, - bool end) -{ - mvwaddch(win, y, start, ptn); - whline(win, ptn, len); - if (end) - mvwaddch(win, y, MAX_DISP_TEMP+TDATA_LEFT, ']'); -} - -static char trip_type_to_char(int type) -{ - switch (type) { - case THERMAL_TRIP_CRITICAL: return 'C'; - case THERMAL_TRIP_HOT: return 'H'; - case THERMAL_TRIP_PASSIVE: return 'P'; - case THERMAL_TRIP_ACTIVE: return 'A'; - default: - return '?'; - } -} - -/* fill a string with trip point type and value in one line - * e.g. P(56) C(106) - * maintain the distance one degree per char - */ -static void draw_tp_line(int tz, int y) -{ - int j; - int x; - - for (j = 0; j < ptdata.tzi[tz].nr_trip_pts; j++) { - x = ptdata.tzi[tz].tp[j].temp / 1000; - mvwprintw(thermal_data_window, y + 0, x + TDATA_LEFT, - "%c%d", trip_type_to_char(ptdata.tzi[tz].tp[j].type), - x); - syslog(LOG_INFO, "%s:tz %d tp %d temp = %lu\n", __func__, - tz, j, ptdata.tzi[tz].tp[j].temp); - } -} - -const char data_win_title[] = " THERMAL DATA "; -void show_data_w(void) -{ - int i; - - - if (tui_disabled || !thermal_data_window) - return; - - werase(thermal_data_window); - wattron(thermal_data_window, A_BOLD); - mvwprintw(thermal_data_window, 0, maxx/2 - sizeof(data_win_title), - data_win_title); - wattroff(thermal_data_window, A_BOLD); - /* draw a line as ruler */ - for (i = 10; i < MAX_DISP_TEMP; i += 10) - mvwprintw(thermal_data_window, 1, i+TDATA_LEFT, "%2d", i); - - for (i = 0; i < ptdata.nr_tz_sensor; i++) { - int temp = trec[cur_thermal_record].temp[i] / 1000; - int y = 0; - - y = i * NR_LINES_TZDATA + 2; - /* y at tz temp data line */ - mvwprintw(thermal_data_window, y, 1, "%6.6s%2d:[%3d][", - ptdata.tzi[i].type, - ptdata.tzi[i].instance, temp); - draw_hbar(thermal_data_window, y, TDATA_LEFT, temp, ACS_RARROW, - true); - draw_tp_line(i, y); - } - wborder(thermal_data_window, 0, 0, 0, 0, 0, 0, 0, 0); - wrefresh(thermal_data_window); -} - -const char tz_title[] = "THERMAL ZONES(SENSORS)"; - -void show_sensors_w(void) -{ - int i, j; - char buffer[512]; - - if (tui_disabled || !tz_sensor_window) - return; - - werase(tz_sensor_window); - - memset(buffer, 0, sizeof(buffer)); - wattron(tz_sensor_window, A_BOLD); - mvwprintw(tz_sensor_window, 1, 1, "Thermal Zones:"); - wattroff(tz_sensor_window, A_BOLD); - - mvwprintw(tz_sensor_window, 1, TZ_LEFT_ALIGN, "%s", buffer); - /* fill trip points for each tzone */ - wattron(tz_sensor_window, A_BOLD); - mvwprintw(tz_sensor_window, 2, 1, "Trip Points:"); - wattroff(tz_sensor_window, A_BOLD); - - /* draw trip point from low to high for each tz */ - for (i = 0; i < ptdata.nr_tz_sensor; i++) { - int inst = ptdata.tzi[i].instance; - - mvwprintw(tz_sensor_window, 1, - TZ_LEFT_ALIGN+TZONE_RECORD_SIZE * inst, "%.9s%02d", - ptdata.tzi[i].type, ptdata.tzi[i].instance); - for (j = ptdata.tzi[i].nr_trip_pts - 1; j >= 0; j--) { - /* loop through all trip points */ - char type; - int tp_pos; - /* reverse the order here since trips are sorted - * in ascending order in terms of temperature. - */ - tp_pos = ptdata.tzi[i].nr_trip_pts - j - 1; - - type = trip_type_to_char(ptdata.tzi[i].tp[j].type); - mvwaddch(tz_sensor_window, 2, - inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN + - tp_pos, type); - syslog(LOG_DEBUG, "draw tz %d tp %d ch:%c\n", - inst, j, type); - } - } - wborder(tz_sensor_window, 0, 0, 0, 0, 0, 0, 0, 0); - wattron(tz_sensor_window, A_BOLD); - mvwprintw(tz_sensor_window, 0, maxx/2 - sizeof(tz_title), tz_title); - wattroff(tz_sensor_window, A_BOLD); - wrefresh(tz_sensor_window); -} - -void disable_tui(void) -{ - tui_disabled = 1; -} |