Messages in this thread | | | Date | Fri, 4 Feb 2022 23:16:21 +0100 | Subject | Re: [PATCH] tools/lib/thermal: Add a thermal library | From | Daniel Lezcano <> |
| |
Hi Srinivas,
On 04/02/2022 20:32, srinivas pandruvada wrote: > On Fri, 2022-02-04 at 18:11 +0100, Rafael J. Wysocki wrote: >> CC Rui and Srinivas >> >> On Fri, Feb 4, 2022 at 5:15 PM Daniel Lezcano >> <daniel.lezcano@linaro.org> wrote: >>> >>> The thermal framework implements a netlink notification mechanism >>> to >>> be used by the userspace to have a thermal configuration discovery, >>> trip point changes or violation, cooling device changes >>> notifications, >>> etc... >>> >>> This library provides a level of abstraction for the thermal >>> netlink >>> notification allowing the userspace to connect to the notification >>> mechanism more easily. The library is callback oriented. >>> >>> As it is the very first iteration, the API may be subject to >>> changes. For this reason, the documentation will be provided after >>> those are stabilized. >> >> So shouldn't this be an RFC? >> >> Also, I would prefer documentation to be provided or at least some >> intended usage examples to be given. >> >>> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> >>> --- >>> tools/Makefile | 14 +- >>> tools/include/uapi/linux/thermal.h | 91 ++++++ > This is duplicating the file at include/uapi/linux. I know this is done > for other tools also. In my use I am copying and using symbolic link.
Why copy and symbolic link ? Should it be create a symbolic link only ?
> BTW I have potential usage of netlink targeted for next release in > linux tools. > > https://github.com/spandruvada/linux-kernel/blob/intel-sst/tools/power/x86/intel-speed-select/hfi-events.c > > I can replace with libthermal calls once ready. I will check the code > below next week.
Great, thanks!
In attachment a test file as an example of the library usage.
-- <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog/* SPDX-License-Identifier: LGPL-2.1+ */ #include <errno.h> #include <fcntl.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h>
#include <sys/epoll.h> #include <sys/stat.h> #include <sys/types.h>
#include <thermal.h>
#define MAX_EVENTS 10
static int show_trip(struct thermal_trip *tt, void *arg) { printf("trip id=%d, type=%d, temp=%d, hyst=%d\n", tt->id, tt->type, tt->temp, tt->hyst);
return 0; }
static int show_temp(struct thermal_zone *tz, void *arg) { thermal_cmd_get_temp(arg, tz);
printf("temperature: %d\n", tz->temp);
return 0; }
static int show_governor(struct thermal_zone *tz, void *arg) { thermal_cmd_get_governor(arg, tz);
printf("governor: '%s'\n", tz->governor); return 0; }
static int show_tz(struct thermal_zone *tz, void *arg) { printf("thermal zone '%s', id=%d\n", tz->name, tz->id);
for_each_thermal_trip(tz->trip, show_trip, NULL);
show_temp(tz, arg); show_governor(tz, arg); return 0; }
static int tz_create(const char *name, int tz_id, void *arg) { printf("Thermal zone '%s'/%d created\n", name, tz_id);
return 0; }
static int tz_delete(int tz_id, void *arg) { printf("Thermal zone %d deleted\n", tz_id);
return 0; }
static int tz_disable(int tz_id, void *arg) { printf("Thermal zone %d disabled\n", tz_id);
return 0; }
static int tz_enable(int tz_id, void *arg) { printf("Thermal zone %d enabled\n", tz_id);
return 0; }
static int tz_temp(int tz_id, int temp, void *arg) { printf("Thermal zone %d temperature: %d\n", tz_id, temp);
return 0; }
static int trip_high(int tz_id, int trip_id, int temp, void *arg) { printf("Thermal zone %d: trip point %d crossed way up with %d °C\n", tz_id, trip_id, temp);
return 0; }
static int trip_low(int tz_id, int trip_id, int temp, void *arg) { printf("Thermal zone %d: trip point %d crossed way down with %d °C\n", tz_id, trip_id, temp);
return 0; }
static int trip_add(int tz_id, int trip_id, int type, int temp, int hyst, void *arg) { printf("Trip point added %d: id=%d, type=%d, temp=%d, hyst=%d\n", tz_id, trip_id, type, temp, hyst);
return 0; }
static int trip_delete(int tz_id, int trip_id, void *arg) { printf("Trip point deleted %d: id=%d\n", tz_id, trip_id);
return 0; }
static int trip_change(int tz_id, int trip_id, int type, int temp, int hyst, void *arg) { printf("Trip point changed %d: id=%d, type=%d, temp=%d, hyst=%d\n", tz_id, trip_id, type, temp, hyst);
return 0; }
static int cdev_add(const char *name, int cdev_id, int max_state, void *arg) { printf("Cooling device '%s'/%d (max state=%d) added", name, cdev_id, max_state);
return 0; }
static int cdev_delete(int cdev_id, void *arg) { printf("Cooling device %d deleted", cdev_id);
return 0; }
static int cdev_update(int cdev_id, int cur_state, void *arg) { printf("cdev:%d state:%d\n", cdev_id, cur_state);
return 0; }
static int gov_change(int tz_id, const char *name, void *arg) { printf("tz %d, governor=%s\n", tz_id, name);
return 0; }
static struct thermal_ops ops = { .sampling.tz_temp = tz_temp, .events.tz_create = tz_create, .events.tz_delete = tz_delete, .events.tz_disable = tz_disable, .events.tz_enable = tz_enable, .events.trip_high = trip_high, .events.trip_low = trip_low, .events.trip_add = trip_add, .events.trip_delete = trip_delete, .events.trip_change = trip_change, .events.cdev_add = cdev_add, .events.cdev_delete = cdev_delete, .events.cdev_update = cdev_update, .events.gov_change = gov_change };
static int stop = 0;
static void sighandler(int sig) { stop = 1; };
static int thermal_netlink_get_temp_bench(struct thermal_handler *th, struct thermal_zone *tz) { int nr_messages = 0; int nr_secs = 5; unsigned long long sum = 0; printf("Benchmarking netlink... wait %d secs\n", nr_secs); signal(SIGALRM, sighandler); alarm(nr_secs); while (!stop) { thermal_cmd_get_temp(th, tz); sum += tz->temp; nr_messages++; } printf("Temperature reading %d msg/sec (%llu usec/msg), avg temp=%llu\n", nr_messages / nr_secs, 1000000ULL / (nr_messages / nr_secs), sum / nr_messages);
return 0; }
static int thermal_sysfs_get_temp_bench(struct thermal_zone *tz) { int nr_messages = 0; int nr_secs = 5; unsigned long long sum = 0; char path[PATH_MAX]; int fd;
snprintf(path, PATH_MAX, "/sys/class/thermal/thermal_zone%d/temp", tz->id);
fd = open(path, O_RDONLY); if (fd < 0) return -1;
printf("Benchmarking sysfs... wait %d secs\n", nr_secs);
signal(SIGALRM, sighandler); alarm(nr_secs); stop = 0; while (!stop) { char buffer[128] = { 0 };
pread(fd, buffer, 127, 0); sum += atoi(buffer); nr_messages++; }
if (!nr_messages) { fprintf(stderr, "No message read\n"); return -1; } printf("Temperature reading %d msg/sec (%llu usec/msg), avg temp=%llu\n", nr_messages / nr_secs, 1000000ULL / (nr_messages / nr_secs), sum / nr_messages);
close(fd);
return 0; }
int main(void) { struct thermal_zone *tz; struct thermal_handler *th; struct epoll_event ev; struct epoll_event events[MAX_EVENTS]; int epollfd; int nfds; int i;
th = thermal_init(&ops); if (!th) return -1;
tz = thermal_zone_discover(th); if (!tz) return -1;
thermal_netlink_get_temp_bench(th, tz);
thermal_sysfs_get_temp_bench(tz);
for_each_thermal_zone(tz, show_tz, th); epollfd = epoll_create1(0); if (epollfd < 0) return -1;
ev.events = EPOLLIN; ev.data.ptr = thermal_events_handle;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, thermal_events_fd(th), &ev) == -1) return -1;
ev.events = EPOLLIN; ev.data.ptr = thermal_sampling_handle; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, thermal_sampling_fd(th), &ev) == -1) return -1; while (1) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); for (i = 0; i < nfds; i++) { if (events[i].data.ptr == thermal_events_handle) { thermal_events_handle(th, NULL); } else if (events[i].data.ptr == thermal_sampling_handle) { thermal_sampling_handle(th, NULL); } } }
return 0; }
| |