Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trace thermal zone temperatures in the LISA kmodule #2170

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lisa/_assets/kmodules/lisa/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ ifneq ($(KERNELRELEASE),)

LISA_KMOD_NAME ?= lisa
obj-m := $(LISA_KMOD_NAME).o
$(LISA_KMOD_NAME)-y := main.o tp.o wq.o features.o pixel6.o introspection_data.o
$(LISA_KMOD_NAME)-y := main.o tp.o wq.o features.o pixel6.o introspection_data.o thermal.o

# -fno-stack-protector is needed to possibly undefined __stack_chk_guard symbol
ccflags-y := "-I$(MODULE_SRC)" -std=gnu11 -fno-stack-protector -Wno-declaration-after-statement -Wno-error
Expand Down
25 changes: 24 additions & 1 deletion lisa/_assets/kmodules/lisa/ftrace_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ TRACE_EVENT(lisa__pixel6_emeter,
),

TP_fast_assign(
__entry->ts = ts;
__entry->ts = ts;
__entry->device = device;
__entry->chan = chan;
__entry->value = value;
Expand All @@ -440,6 +440,29 @@ TRACE_EVENT(lisa__pixel6_emeter,
__entry->ts, __entry->device, __entry->chan, __entry->chan_name, __entry->value)
);

#include <uapi/linux/thermal.h> // THERMAL_NAME_LENGTH

TRACE_EVENT(lisa__thermal,
TP_PROTO(u64 ts, int id, int temp, const char *name),
TP_ARGS(ts, id, temp, name),

TP_STRUCT__entry(
__field(u64, ts )
__field(int, id )
__field(int, temp )
__array(char, name, THERMAL_NAME_LENGTH )
),

TP_fast_assign(
__entry->ts = ts;
__entry->id = id;
__entry->temp = temp;
strlcpy(__entry->name, name, sizeof(__entry->name));
),

TP_printk("ts=%llu id=%d name=%s temp=%d",
__entry->ts, __entry->id, __entry->name, __entry->temp)
);
#endif /* _FTRACE_EVENTS_H */

/* This part must be outside protection */
Expand Down
170 changes: 170 additions & 0 deletions lisa/_assets/kmodules/lisa/thermal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/stringify.h>
#include <linux/thermal.h>
#include <linux/types.h>

#include "main.h"

#include "features.h"
#include "ftrace_events.h"
#include "utils.h"
#include "wq.h"

/* Millisecond interval for polling temperatures. Clamped to [1,5000]. */
#ifdef CONFIG_POLL_INTERVAL_MS
# define POLL_INTERVAL_MS CLAMP((CONFIG_POLL_INTERVAL_MS), 1, 5000)
#else
# define POLL_INTERVAL_MS 100
#endif /* CONFIG_POLL_INTERVAL_MS */

/** Comma-separted list of names of thermal zones to monitor. */
#ifdef CONFIG_THERMAL_ZONE_LIST
static const char *thermal_zone_names[] = {STRINGIFY_ALL(CONFIG_THERMAL_ZONE_LIST)};
#else
static const char *thermal_zone_names[] = {"LITTLE","MID","BIG"};
#endif /* CONFIG_THERMAL_ZONE_LIST */

/* Number of items in THERMAL_ZONE_LIST. */
#define NUM_THERMAL_ZONES (ARRAY_SIZE(thermal_zone_names))

#define FEATURE_NAME lisa__thermal
#define TEMPERATURE_MIN -273100
#define TEMPERATURE_MAX 999999

/* Shorthands for allocators. */
#define kzalloc_k(N) (kzalloc((N), GFP_KERNEL))
#define kcalloc_k(N, SIZE) (kcalloc((N), (SIZE), GFP_KERNEL))

struct thermal_config {
int temps[NUM_THERMAL_ZONES];
struct thermal_zone_device *devs[NUM_THERMAL_ZONES];
struct work_item *work;
};

/* struct thermal_config accessors */
#define thermal_config_temp(CFG, I) ((CFG)->temps[(I)])
#define thermal_config_device(CFG, I) ((CFG)->devs[(I)])
#define trace_ith_tz(CFG, I, TS) \
trace_lisa__thermal( \
(TS), \
thermal_config_device((CFG), (I))->id, \
thermal_config_temp((CFG), (I)), \
thermal_config_device((CFG), (I))->type)

#define NANOS_TO_MILLIS 1000000

static int thermal_worker(void *data)
{
struct thermal_config *config = data;
/* Use same timestamp for each TZ to make parsing easier.
* Convert to millis for consistency with lisa__pixel6_emeter.
*/
u64 ts = ktime_get_real_ns()/NANOS_TO_MILLIS;
for (u32 i = 0; i < NUM_THERMAL_ZONES; i++) {
struct thermal_zone_device *dev;
int temp, ret;

dev = thermal_config_device(config, i);
ret = thermal_zone_get_temp(dev, &temp);
if (ret != 0) {
pr_err("Could not get temperature for %s: %d\n",
dev->type, ret);
continue;
}

temp = CLAMP(temp, TEMPERATURE_MIN, TEMPERATURE_MAX);
if (temp != thermal_config_temp(config, i)) {
thermal_config_temp(config, i) = temp;
trace_ith_tz(config, i, ts);
}
}

return WORKER_SAME_DELAY;
}

static void thermal_config_deinit(struct thermal_config *config)
{
if (!config)
return;
/* Destroy work first in case the worker is running */
destroy_work(config->work);
/* Now the worker is stopped */
kfree(config);
}

static int thermal_config_init(
struct feature *feature, struct thermal_config **pconfig)
{
int ret = 0;
struct thermal_config *config;

config = kzalloc_k(sizeof(*config));
if (!config) {
ret = -ENOMEM;
goto out;
}

for (int i = 0; i < NUM_THERMAL_ZONES; i++) {
config->devs[i] = thermal_zone_get_zone_by_name(thermal_zone_names[i]);
if (config->devs[i] == NULL) {
pr_err("No such device: %s\n", thermal_zone_names[i]);
return -ENOENT;
}

/* Initialise to an invalid value so the first trace always
* detects the temperature as having changed. */
config->temps[i] = THERMAL_TEMP_INVALID;
}

out:
if (ret != 0) {
thermal_config_deinit(config);
pr_warn("Initialise thermal zone list failed (err=%d)\n", ret);
return ret;
}

*pconfig = config;
pr_info("Thermal zone list initialised\n");
return ret;
}

static int thermal_disable(struct feature *feature)
{

thermal_config_deinit(feature->data);
feature->data = NULL;
return DISABLE_FEATURE(__worqueue);
}

static int thermal_enable(struct feature *feature)
{
struct thermal_config *config;
int ret = 0;

ret = ENABLE_FEATURE(__worqueue);
if (ret != 0)
return ret;

ret = thermal_config_init(feature, &config);
if (ret != 0)
goto out;

feature->data = config;

int delay_jiffies = (int)msecs_to_jiffies(POLL_INTERVAL_MS);
config->work = start_work(thermal_worker, delay_jiffies, config);
if (!config->work) {
ret = -ENOMEM;
goto out;
}

out:
if (ret != 0)
thermal_disable(feature);
return ret;
}

DEFINE_FEATURE(FEATURE_NAME, thermal_enable, thermal_disable);
20 changes: 20 additions & 0 deletions lisa/_assets/kmodules/lisa/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,24 @@

#include "linux/kernel.h"

#define __STRINGIFY_12(X, ...) __stringify(X), __STRINGIFY_11(__VA_ARGS__)
#define __STRINGIFY_11(X, ...) __stringify(X), __STRINGIFY_10(__VA_ARGS__)
#define __STRINGIFY_10(X, ...) __stringify(X), __STRINGIFY_9(__VA_ARGS__)
#define __STRINGIFY_9(X, ...) __stringify(X), __STRINGIFY_8(__VA_ARGS__)
#define __STRINGIFY_8(X, ...) __stringify(X), __STRINGIFY_7(__VA_ARGS__)
#define __STRINGIFY_7(X, ...) __stringify(X), __STRINGIFY_6(__VA_ARGS__)
#define __STRINGIFY_6(X, ...) __stringify(X), __STRINGIFY_5(__VA_ARGS__)
#define __STRINGIFY_5(X, ...) __stringify(X), __STRINGIFY_4(__VA_ARGS__)
#define __STRINGIFY_4(X, ...) __stringify(X), __STRINGIFY_3(__VA_ARGS__)
#define __STRINGIFY_3(X, ...) __stringify(X), __STRINGIFY_2(__VA_ARGS__)
#define __STRINGIFY_2(X, ...) __stringify(X), __STRINGIFY_1(__VA_ARGS__)
#define __STRINGIFY_1(X) __stringify(X)
#define __STRINGIFY_0()

/** Stringify up to 12 args. */
#define STRINGIFY_ALL(...) CONCATENATE(__STRINGIFY_, COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)

/** Clamp X to a value in [A,B]. */
#define CLAMP(X, A, B) ((X) < (A) ? (A) : ((X) > (B) ? (B) : (X)))

#endif /* _UTILS_H */
8 changes: 8 additions & 0 deletions lisa/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,14 @@ class TxtTraceParser(TxtTraceParserBase):
'util_avg': _KERNEL_DTYPE['util'],
},
),
'lisa__thermal': dict(
fields={
'ts': 'uint64',
'id': 'int32',
'temp': 'int32',
'name': 'str'
}
)
}

@PartialInit.factory
Expand Down