Skip to content

Commit 94f6996

Browse files
Jacob Panzhang-rui
authored andcommitted
tools/thermal: Introduce tmon, a tool for thermal subsystem
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 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. Signed-off-by: Jacob Pan <[email protected]> Signed-off-by: Zhang Rui <[email protected]>
1 parent 959f585 commit 94f6996

File tree

9 files changed

+2173
-2
lines changed

9 files changed

+2173
-2
lines changed

tools/Makefile

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ help:
1515
@echo ' net - misc networking tools'
1616
@echo ' vm - misc vm tools'
1717
@echo ' x86_energy_perf_policy - Intel energy policy tool'
18+
@echo ' tmon - thermal monitoring and tuning tool'
1819
@echo ''
1920
@echo 'You can do:'
2021
@echo ' $$ make -C tools/ <tool>_install'
@@ -50,6 +51,9 @@ selftests: FORCE
5051
turbostat x86_energy_perf_policy: FORCE
5152
$(call descend,power/x86/$@)
5253

54+
tmon: FORCE
55+
$(call descend,thermal/$@)
56+
5357
cpupower_install:
5458
$(call descend,power/$(@:_install=),install)
5559

@@ -62,9 +66,13 @@ selftests_install:
6266
turbostat_install x86_energy_perf_policy_install:
6367
$(call descend,power/x86/$(@:_install=),install)
6468

69+
tmon_install:
70+
$(call descend,thermal/$(@:_install=),install)
71+
6572
install: cgroup_install cpupower_install firewire_install lguest_install \
6673
perf_install selftests_install turbostat_install usb_install \
67-
virtio_install vm_install net_install x86_energy_perf_policy_install
74+
virtio_install vm_install net_install x86_energy_perf_policy_install \
75+
tmon
6876

6977
cpupower_clean:
7078
$(call descend,power/cpupower,clean)
@@ -84,8 +92,11 @@ selftests_clean:
8492
turbostat_clean x86_energy_perf_policy_clean:
8593
$(call descend,power/x86/$(@:_clean=),clean)
8694

95+
tmon_clean:
96+
$(call descend,thermal/tmon,clean)
97+
8798
clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \
8899
selftests_clean turbostat_clean usb_clean virtio_clean \
89-
vm_clean net_clean x86_energy_perf_policy_clean
100+
vm_clean net_clean x86_energy_perf_policy_clean tmon_clean
90101

91102
.PHONY: FORCE

tools/thermal/tmon/Makefile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
VERSION = 1.0
2+
3+
BINDIR=usr/bin
4+
WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
5+
CFLAGS= -O1 ${WARNFLAGS} -fstack-protector
6+
CC=gcc
7+
8+
CFLAGS+=-D VERSION=\"$(VERSION)\"
9+
LDFLAGS+=
10+
TARGET=tmon
11+
12+
INSTALL_PROGRAM=install -m 755 -p
13+
DEL_FILE=rm -f
14+
15+
INSTALL_CONFIGFILE=install -m 644 -p
16+
CONFIG_FILE=
17+
CONFIG_PATH=
18+
19+
20+
OBJS = tmon.o tui.o sysfs.o pid.o
21+
OBJS +=
22+
23+
tmon: $(OBJS) Makefile tmon.h
24+
$(CC) ${CFLAGS} $(LDFLAGS) $(OBJS) -o $(TARGET) -lm -lpanel -lncursesw -lpthread
25+
26+
valgrind: tmon
27+
sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET) 1> /dev/null
28+
29+
install:
30+
- mkdir -p $(INSTALL_ROOT)/$(BINDIR)
31+
- $(INSTALL_PROGRAM) "$(TARGET)" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)"
32+
- mkdir -p $(INSTALL_ROOT)/$(CONFIG_PATH)
33+
- $(INSTALL_CONFIGFILE) "$(CONFIG_FILE)" "$(INSTALL_ROOT)/$(CONFIG_PATH)"
34+
35+
uninstall:
36+
$(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)"
37+
$(CONFIG_FILE) "$(CONFIG_PATH)"
38+
39+
40+
clean:
41+
find . -name "*.o" | xargs $(DEL_FILE)
42+
rm -f $(TARGET)
43+
44+
dist:
45+
git tag v$(VERSION)
46+
git archive --format=tar --prefix="$(TARGET)-$(VERSION)/" v$(VERSION) | \
47+
gzip > $(TARGET)-$(VERSION).tar.gz

tools/thermal/tmon/README

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
TMON - A Monitoring and Testing Tool for Linux kernel thermal subsystem
2+
3+
Why TMON?
4+
==========
5+
Increasingly, Linux is running on thermally constrained devices. The simple
6+
thermal relationship between processor and fan has become past for modern
7+
computers.
8+
9+
As hardware vendors cope with the thermal constraints on their products, more
10+
and more sensors are added, new cooling capabilities are introduced. The
11+
complexity of the thermal relationship can grow exponentially among cooling
12+
devices, zones, sensors, and trip points. They can also change dynamically.
13+
14+
To expose such relationship to the userspace, Linux generic thermal layer
15+
introduced sysfs entry at /sys/class/thermal with a matrix of symbolic
16+
links, trip point bindings, and device instances. To traverse such
17+
matrix by hand is not a trivial task. Testing is also difficult in that
18+
thermal conditions are often exception cases that hard to reach in
19+
normal operations.
20+
21+
TMON is conceived as a tool to help visualize, tune, and test the
22+
complex thermal subsystem.
23+
24+
Files
25+
=====
26+
tmon.c : main function for set up and configurations.
27+
tui.c : handles ncurses based user interface
28+
sysfs.c : access to the generic thermal sysfs
29+
pid.c : a proportional-integral-derivative (PID) controller
30+
that can be used for thermal relationship training.
31+
32+
Requirements
33+
============
34+
Depends on ncurses
35+
36+
Build
37+
=========
38+
$ make
39+
$ sudo ./tmon -h
40+
Usage: tmon [OPTION...]
41+
-c, --control cooling device in control
42+
-d, --daemon run as daemon, no TUI
43+
-l, --log log data to /var/tmp/tmon.log
44+
-h, --help show this help message
45+
-t, --time-interval set time interval for sampling
46+
-v, --version show version
47+
-g, --debug debug message in syslog
48+
49+
1. For monitoring only:
50+
$ sudo ./tmon

tools/thermal/tmon/pid.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* pid.c PID controller for testing cooling devices
3+
*
4+
*
5+
*
6+
* Copyright (C) 2012 Intel Corporation. All rights reserved.
7+
*
8+
* This program is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU General Public License version
10+
* 2 or later as published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* Author Name Jacob Pan <[email protected]>
18+
*
19+
*/
20+
21+
#include <unistd.h>
22+
#include <stdio.h>
23+
#include <stdlib.h>
24+
#include <string.h>
25+
#include <stdint.h>
26+
#include <sys/types.h>
27+
#include <dirent.h>
28+
#include <libintl.h>
29+
#include <ctype.h>
30+
#include <assert.h>
31+
#include <time.h>
32+
#include <limits.h>
33+
#include <math.h>
34+
#include <sys/stat.h>
35+
#include <syslog.h>
36+
37+
#include "tmon.h"
38+
39+
/**************************************************************************
40+
* PID (Proportional-Integral-Derivative) controller is commonly used in
41+
* linear control system, consider the the process.
42+
* G(s) = U(s)/E(s)
43+
* kp = proportional gain
44+
* ki = integral gain
45+
* kd = derivative gain
46+
* Ts
47+
* We use type C Alan Bradley equation which takes set point off the
48+
* output dependency in P and D term.
49+
*
50+
* y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k]
51+
* - 2*x[k-1]+x[k-2])/Ts
52+
*
53+
*
54+
***********************************************************************/
55+
struct pid_params p_param;
56+
/* cached data from previous loop */
57+
static double xk_1, xk_2; /* input temperature x[k-#] */
58+
59+
/*
60+
* TODO: make PID parameters tuned automatically,
61+
* 1. use CPU burn to produce open loop unit step response
62+
* 2. calculate PID based on Ziegler-Nichols rule
63+
*
64+
* add a flag for tuning PID
65+
*/
66+
int init_thermal_controller(void)
67+
{
68+
int ret = 0;
69+
70+
/* init pid params */
71+
p_param.ts = ticktime;
72+
/* TODO: get it from TUI tuning tab */
73+
p_param.kp = .36;
74+
p_param.ki = 5.0;
75+
p_param.kd = 0.19;
76+
77+
p_param.t_target = target_temp_user;
78+
79+
return ret;
80+
}
81+
82+
void controller_reset(void)
83+
{
84+
/* TODO: relax control data when not over thermal limit */
85+
syslog(LOG_DEBUG, "TC inactive, relax p-state\n");
86+
p_param.y_k = 0.0;
87+
xk_1 = 0.0;
88+
xk_2 = 0.0;
89+
set_ctrl_state(0);
90+
}
91+
92+
/* To be called at time interval Ts. Type C PID controller.
93+
* y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k]
94+
* - 2*x[k-1]+x[k-2])/Ts
95+
* TODO: add low pass filter for D term
96+
*/
97+
#define GUARD_BAND (2)
98+
void controller_handler(const double xk, double *yk)
99+
{
100+
double ek;
101+
double p_term, i_term, d_term;
102+
103+
ek = p_param.t_target - xk; /* error */
104+
if (ek >= 3.0) {
105+
syslog(LOG_DEBUG, "PID: %3.1f Below set point %3.1f, stop\n",
106+
xk, p_param.t_target);
107+
controller_reset();
108+
*yk = 0.0;
109+
return;
110+
}
111+
/* compute intermediate PID terms */
112+
p_term = -p_param.kp * (xk - xk_1);
113+
i_term = p_param.kp * p_param.ki * p_param.ts * ek;
114+
d_term = -p_param.kp * p_param.kd * (xk - 2 * xk_1 + xk_2) / p_param.ts;
115+
/* compute output */
116+
*yk += p_term + i_term + d_term;
117+
/* update sample data */
118+
xk_1 = xk;
119+
xk_2 = xk_1;
120+
121+
/* clamp output adjustment range */
122+
if (*yk < -LIMIT_HIGH)
123+
*yk = -LIMIT_HIGH;
124+
else if (*yk > -LIMIT_LOW)
125+
*yk = -LIMIT_LOW;
126+
127+
p_param.y_k = *yk;
128+
129+
set_ctrl_state(lround(fabs(p_param.y_k)));
130+
131+
}

0 commit comments

Comments
 (0)