Monitor算法温控的常见算法之一,在main函数中调用了thermal_monitor函数.Monitor算法是一种静态算法,当超过每一个设置的温度值就会调频,当小于clr的温度就会停止调频算法。
thermal_monitor函数先是从dev_list中获取了各个device_info放入device_info_arr中,然后过滤setting放入tm_states的setting中,然后执行了sensor_up以及创建了一个thread执行函数sensor_monitor来监控是否触发monitor算法。
void thermal_monitor(struct thermal_setting_t *settings)
{
struct setting_info *cfg_setting;
union device_request req;
/* Build Device Info List */
if (devices_manager_get_list(NULL, &device_info_arr_len)) {//先获取dev_list的长度
msg("Failed to get device list length\n");
return;
}
device_info_arr = (struct device_info *)//根据device的长度 malloc
malloc(sizeof(struct device_info)*device_info_arr_len);
if (device_info_arr == NULL) {
msg("Failed to alloc device_info_arr\n");
return;
}
if (devices_manager_get_list(device_info_arr,//得到device_info
&device_info_arr_len)) {
msg("Failed to get device list\n");
free(device_info_arr);
return;
}
cfg_setting = settings->list;
while (cfg_setting && (tm_cnt < MAX_TM_INSTANCES_SUPPORTED)) {
if ((cfg_setting->algo_type != MONITOR_ALGO_TYPE) ||//不是Monitor continue
(cfg_setting->err_disable != 0)) {//坏的setting continue
cfg_setting = cfg_setting->next;
continue;
}
dbgmsg("%s: Import %s", __func__, cfg_setting->desc);
tm_states[tm_cnt].setting = cfg_setting;//放入tm_states数组的setting
tm_states[tm_cnt].disable = cfg_setting->disable;
tm_cnt++;
if (!cfg_setting->disable)//没有disable 打印
print_setting(cfg_setting);
/* KEEP at end of while block */
cfg_setting = cfg_setting->next;
}
if (!sensors_setup()) {//
msg("Failed to setup at least one sensor for monitoring\n");
return;
}
/* Vote to keep kernel mitigation enabled until thermal monitor has
processed initial thresholds. */
kernel_dev = devices_manager_reg_clnt("kernel");
if (kernel_dev == NULL) {
msg("%s Failed to create kernel device handle\n", __func__);
return;
}
req.value = 1;
device_clnt_request(kernel_dev, &req);//继续keep KTM
if (pthread_create(&tm_thread, NULL, (void *)&sensor_monitor,//sensor_monitor监控
(void *)NULL) != 0) {
msg("Error initializing thermal monitor\n");
device_clnt_cancel_request(kernel_dev);//失败就取消之前keep KTM的命令
}
}
我们来看下devices_manager_get_list 函数,配合上面thermal_monitor函数,第一次传进来的info_arr为NULL,因此获取了device的长度,第二次再从dev_list中获取dev_info放入dev_info_arr.
int devices_manager_get_list(struct device_info *info_arr, uint32_t *info_arr_len)
{
uint32_t dev_idx;
struct devices_manager_dev *curr = dev_list;
if ((info_arr == NULL) && (info_arr_len == NULL)) {
msg("%s: Invalid args.\n", __func__);
return -(EINVAL);
}
if (info_arr == NULL) {//第一次获取长度
/* Interpret as request for number of dev's present. */
*info_arr_len = dev_cnt;
return 0;
}
/* Don't exceed end of info_array */
*info_arr_len = MIN(*info_arr_len, dev_cnt);
for (dev_idx = 0; (dev_idx < *info_arr_len) && (curr != NULL); dev_idx++) {//第二次遍历dev_list获取dev_info
memcpy(&(info_arr[dev_idx]), &(curr->dev_info),
sizeof(struct device_info));
curr = curr->next_dev;
}
return 0;
}
下面我们再来看sensors_setup函数,这个函数我们需要结合monitor算法实际的配置来看。
static int sensors_setup(void)
{
uint32_t i = 0;
int sensor_count = 0;
if (!tm_cnt)
return 0;
/* Set up tm instances */
dbgmsg("%s: tm_cnt %d", __func__, tm_cnt);
for (i = 0; i < tm_cnt; i++) {//遍历所有的tm_states
struct tm_instance_info *tm_instance_info;
struct setting_info *setting;
struct tm_setting *tm_setting_info;
tm_instance_info = &tm_states[i];
setting = tm_instance_info->setting;
tm_setting_info = &(setting->data.tm);
dbgmsg("%s: TM Id %s Sensor %s num_thresholds %d", __func__,
setting->desc, tm_setting_info->sensor,
tm_setting_info->num_thresholds);
if (tm_setting_info->num_thresholds > 0) {//结合下面num_thresholds为3
/* Create sensor client */
tm_instance_info->ts_clnt =
sensors_manager_reg_clnt(tm_setting_info->sensor);//结合下面看我们的sensor是tsens_tz_sensor1
if (tm_instance_info->ts_clnt == NULL) {//上面是创建一个sensor的client
msg("%s: Can't create client for %s.\n",
__func__, tm_setting_info->sensor);
tm_instance_info->disable = 1;
continue;
}
/* Create necessary device clients */
if (create_device_clnts(tm_instance_info) == 0)//这里处理每一个action
sensor_count++;
else
tm_instance_info->disable = 1;
}
}
return sensor_count;
}
下面是一个8909的Monitor算法的一部分:
{
.desc = "CAMERA_CAMCORDER_MONITOR",
.algo_type = MONITOR_ALGO_TYPE,
.data.tm = {
.sensor = "tsens_tz_sensor1",
.sampling_period_ms = 250,
.num_thresholds = 3,//t的个数
._n_thresholds = 3,
._n_to_clear = 3,
._n_actions = 3,
._n_action_info = 3,
.t[0] = {
.lvl_trig = 80000,
.lvl_clr = 75000,
.num_actions = 2,//action的个数
.actions[0] = {
.device = "camera",
.info = 1,
},
.actions[1] = {
.device = "camcorder",
.info = 1,
},
},
.t[1] = {
.lvl_trig = 85000,
.lvl_clr = 80000,
.num_actions = 2,
.actions[0] = {
.device = "camera",
.info = 2,
},
.actions[1] = {
.device = "camcorder",
.info = 2,
},
},
.t[2] = {
.lvl_trig = 88000,
.lvl_clr = 85000,
.num_actions = 2,
.actions[0] = {
.device = "camera",
.info = 10,
},
.actions[1] = {
.device = "camcorder",
.info = 10,
},
}
},
},
sensors_manager_reg_clnt函数就是为sensor创建一个client
sensor_clnt_handle sensors_manager_reg_clnt(const char *sensor_name)
{
struct sensor_client_type *client = NULL;
struct sensors_mgr_sensor_info *sensor_mgr = NULL;
if (sensor_name == NULL) {
msg("%s: Invalid args.\n", __func__);
return client;
}
sensor_mgr = find_sensor(sensor_name);//从sensor_list中找到sensor
if (sensor_mgr == NULL) {
msg("%s: Invalid sensor %s.\n", __func__, sensor_name);
return client;
}
client = malloc(sizeof(struct sensor_client_type));
if (client == NULL) {
msg("%s: Alloc. failed for %s.\n", __func__, sensor_name);
return client;
}
memset(client, 0x0, sizeof(struct sensor_client_type));
THERM_MUTEX_LOCK(&ts_clnt_mtx);
/* Insert the client */
client->sensor_mgr = sensor_mgr;
client->next_clnt = sensor_mgr->client_list;
sensor_mgr->client_list = client;
THERM_MUTEX_UNLOCK(&ts_clnt_mtx);
return client;
}
我们再来看下create_device_clnts函数
static int create_device_clnts(struct tm_instance_info *tm_instance_info)
{
int ret_val = 0;
uint32_t t_idx, a_idx;
struct tm_devices_list list;//创建一个list
struct tm_setting *tm_setting_info = &tm_instance_info->setting->data.tm;
memset(&list, 0x0, sizeof(struct tm_devices_list));
/* Create list of unique actions */
for (t_idx = 0; t_idx < tm_setting_info->num_thresholds; t_idx++) {//先遍历num_therosholds就是t的个数
for (a_idx = 0; a_idx < tm_setting_info->t[t_idx].num_actions;//再遍历每个t下面的num_actions就是action的个数
a_idx++) {
/* Index used by tm to make requests on correct device
client */
tm_setting_info->t[t_idx].actions[a_idx].device_idx =
add_device_to_list(tm_instance_info, &list,
tm_setting_info->t[t_idx].actions[a_idx].device);
if (tm_setting_info->t[t_idx].actions[a_idx].device_idx < 0) {
msg("%s: Error adding device %s\n", __func__,
tm_setting_info->t[t_idx].actions[a_idx].device);
ret_val = -(EFAULT);
goto error_handler;
}
}
}
error_handler:
return ret_val;
}
我们再来看add_device_to_list函数就是为每个action的device得到deviceinfo放到tm_instance_info的dev_info_list,并且创建一个client放在dev_cln_list,并且把索引保存在每个action的device_idx中。
static int add_device_to_list(struct tm_instance_info *tm_instance_info,
struct tm_devices_list *list, const char *device)
{
uint32_t i;
/* Search for match or first available slot. */
for (i = 0; i < MAX_ACTIONS_PER_TM_INSTANCE; i++) {
/* Add to first empty entry, if no previous match. */
if (list->device[i] == NULL)
break;
if (strncasecmp(list->device[i], device,
DEVICES_MAX_NAME_LEN) == 0)
break;
}
if (i >= MAX_ACTIONS_PER_TM_INSTANCE) {
msg("%s: No room for device %s", __func__, device);
return -1;
}
/* Check if we need to create the device client */
if (list->device[i] == NULL) {
tm_instance_info->dev_info_list[i] = get_device_info(device);//每一个tm_instace_info找到每个action的deviceinfo
if (tm_instance_info->dev_info_list[i] == NULL)
return -1;
tm_instance_info->dev_clnt_list[i] =//为该device创建一个client
devices_manager_reg_clnt(device);
if (tm_instance_info->dev_clnt_list[i] == NULL)
return -1;
list->device[i] = (char*)device;
list->cnt++;
}
return (int)i;//记录该action下的device在tm_instace_info的dev_info_list的索引
}
我们在thermal_monitor中创建了一个thread执行sensor_monitor来监控,这里我们来看下这个函数,这里主要就是循环调用handle_thresh_sig来监控温度,这里有一个重要的地方就是在while循环中会等待condition,直到有其他地方把这个condition broadcast了。
static void *sensor_monitor(void *data)
{
uint32_t idx;
for (idx = 0; idx < tm_cnt; idx++)
THRESH_MASK_SET(idx);
/* Set initial thresholds */
handle_thresh_sig();//第一个调用
/* Vote okay to disable kernel mitigation */
device_clnt_cancel_request(kernel_dev);
thermal_server_register_client_req_handler("override", override_notify, NULL);//之前分析为client注册回调
thermal_server_register_client_req_handler(CONFIG_QUERY_CLIENT, config_query_notify, NULL);
thermal_server_register_client_req_handler(CONFIG_SET_CLIENT, config_set_notify, NULL);
while (exit_daemon != 1) {
dbgmsg("%s: Wait for EV", __func__);
pthread_mutex_lock(&wait_mutex);
if (!THRESH_MASK_ANY_SET) {
pthread_cond_wait(&wait_cond, &wait_mutex);//等待condition
}
pthread_mutex_unlock(&wait_mutex);
dbgmsg("%s: Thresh EVT", __func__);
handle_thresh_sig();//循环调用handle_thresh_sig来监控sensor温度是否满足monitor算法
}
free(device_info_arr);
return NULL;
}
我们来看下handle_thresh_sig函数,先遍历所有的tm_instance_info,然后过滤器setting下面的data.tm num_thresholds小于1,以及disable的tm_instance_info,然后获取温度
static void handle_thresh_sig(void)
{
......
struct tm_instance_info *sensor;
struct setting_info *info;
struct tm_setting *tm_info;
union device_request req;
/* Get temp and handle */
for (idx = 0; idx < tm_cnt; idx++) {
if (THRESH_MASK_IS_SET(idx) == 0) {
continue;
}
sensor = &tm_states[idx];
info = sensor->setting;
tm_info = &(info->data.tm);
if ((tm_info->num_thresholds < 1) ||
(sensor->disable)) {//过滤disable以及num_thresholds
/* Unmask TM instance as handled */
THRESH_MASK_CLR(idx);
continue;
}
max_thr = (int)tm_info->num_thresholds;
sensor_temp = sensor_get_temperature(sensor);//获取温度
dbgmsg("%s: TM Id %s Sensor %s Temp %d\n", __func__,
info->desc, tm_info->sensor, sensor_temp);
lvl_max = -1;
lvl_min = INT_MAX;
for (i = max_thr - 1; i >= 0; i--) {//遍历每一个setting下的t数组
/* Scan for new alarm conditions */
if (sensor_threshold_trigger(sensor_temp, sensor, i)) {//是否触发阈值了
if (sensor->lvl_alarm[i] == 0) {//之前没有记录触发
thermalmsg(LOG_LVL_DBG,
(LOG_LOGCAT | LOG_TRACE),
"TM Id '%s' Sensor '%s' - alarm "
" raised %d at %d.%d degC\n",
info->desc, tm_info->sensor, i + 1,
RCONV(sensor_temp),
(sensor_temp%1000)/100);
sensor->lvl_alarm[i] = 1;//记录
alarm_raised = 1;//需要触发
}
if (i > lvl_max)
lvl_max = i;//lvl_max就是记录触发的t数组的最后一个index
}
/* Scan for alarm clearing conditions */
if (sensor_threshold_clear(sensor_temp, sensor, i)) {//是否低于小的阈值了(clr的温度值)
if (sensor->lvl_alarm[i] == 1) {//之前记录触发了
thermalmsg(LOG_LVL_DBG,
(LOG_LOGCAT | LOG_TRACE),
"TM Id '%s' Sensor '%s' - alarm "
"cleared %d at %d.%d degC\n",
info->desc, tm_info->sensor, i + 1,
RCONV(sensor_temp),
(sensor_temp%1000)/100);
sensor->lvl_alarm[i] = 0;//触发的记录清除
alarm_cleared = 1;//清除
}
if (i < lvl_min)
lvl_min = i;//清除的t数组最小的index
}
}
/* Update temperature thresholds */
if (alarm_raised) {
threshold_type = THRESHOLD_CROSS;
threshold_level = lvl_max + 1;
} else if (alarm_cleared) {
threshold_type = THRESHOLD_CLEAR;
threshold_level = lvl_min;
} else {
threshold_type = THRESHOLD_NOCHANGE;
threshold_level = sensor->last_lvl;
}
sensor->last_lvl = threshold_level;
pthread_mutex_lock(&wait_mutex);
/* Unmask TM instance as handled */
THRESH_MASK_CLR(idx);
pthread_mutex_unlock(&wait_mutex);
sensor_update_thresholds(sensor, threshold_type,
threshold_level, idx);
if (!alarm_raised && !alarm_cleared) {//没有新的触发或者清除之前continue
continue;
}
/* Perform actions on highest level alarm */
for (i = max_thr - 1; i >= 0; i--) {//从settings最大的开始
if (sensor->lvl_alarm[i] == 0)//不满足触发条件的continue
continue;
for (j = 0; j < tm_info->t[i].num_actions; j++) {//满足每一个t数组的sensor温度触发,t数组的所有device都执行action
action_idx = tm_info->t[i].actions[j].device_idx;//获取每个setting的action的device index
dev_info = sensor->dev_info_list[action_idx];
if (dev_info == NULL)
continue;
action_info = tm_info->t[i].actions[j].info;//调整的值
sensor->action_mask |= (1U << action_idx);
req.value = action_info;
switch(dev_info->dev_type) {根据类型区分
......
case DEVICE_OP_VALUE_TYPE:
case DEVICE_GENERIC_TYPE:
device_clnt_request(sensor->dev_clnt_list[action_idx], &req);//每一个device的client申请调整
break;
case DEVICE_NONE_TYPE:
break;
default:
msg("Unknown action %s\n", dev_info->name);
}
}
break;
}
我们来看下获取温度的函数sensor_get_temperature函数,是通过sensors_manager_read_trip_temp函数,传进去的参数是每个tm_instnace_info的sensor的client,每一个tm_instance_info都为其sensor创建一个client。
static int sensor_get_temperature(struct tm_instance_info *setting)
{
int temp = 0;
if (setting == NULL ||
setting->ts_clnt == NULL) {
return -EFAULT;
}
temp = sensors_manager_read_trip_temp(setting->ts_clnt);
dbgmsg("TM Id %s Sensor %s Reading %d\n",
setting->setting->desc,
setting->setting->data.tm.sensor, temp);
return temp;
}
sensors_manager_read_trip_temp函数还是通过client的sensor来获取温度,sensors_manager_read函数还是通过sensor的get_temperature函数。
int sensors_manager_read_trip_temp(sensor_clnt_handle clnt)
{
struct sensors_mgr_sensor_info *sensor_mgr = NULL;
struct sensor_client_type *client = clnt;
int ret_val = INT32_MIN;
if (client == NULL) {
msg("%s: Invalid args.\n", __func__);
return ret_val;
}
if (validate_clnt(client) != 0)
return ret_val;
sensor_mgr = client->sensor_mgr;
if (!sensor_mgr->get_trip_temperature)//没有赋值这个函数
return sensors_manager_read(clnt);
ret_val = sensor_mgr->get_trip_temperature(sensor_mgr);
thermalmsg(LOG_LVL_DBG, (LOG_LOGCAT | LOG_LOCAL_SOCKET
| LOG_TRACE), "%s:%s:%d mC\n", SENSORS,
sensor_mgr->name, ret_val);
return ret_val;
}
我们再来看sensor_threshold_trigger函数,正常流程是走else的而且是没有override_mode的,因此只要温度大于lvl_trig就是触发了。
static int sensor_threshold_trigger(int value, struct tm_instance_info *sensor, int level)
{
struct tm_setting *tm_info = &(sensor->setting->data.tm);
if (tm_info->descending_thresh) {
if (value <= tm_info->t[level].lvl_trig)
return 1;
else
return 0;
} else {
int active_trig = tm_info->t[level].lvl_trig;
if (override_mode)
active_trig += tm_info->override;;
if (value >= active_trig)
return 1;
else
return 0;
}
}
还是分析handle_thresh_sig函数,触发之后最后还是调用了device_clnt_request,每一个setting下面action满足条件的device的client都会申请一个request,device_clnt_request这个函数我们在分析device初始化的时候分析过了。像device的type是DEVICE_OP_VALUE_TYPE类型的值我们会取所有client的最小值(比如cpu),像device的type是DEVICE_GENERIC_TYPE我们会取所有client的最大值,最终会到device的action函数来控制。
int device_clnt_request(device_clnt_handle clnt, union device_request *req)
{
struct devices_manager_dev *dev_mgr = NULL;
struct device_clnt *client = clnt;
int ret_val = 0;
if ((client == NULL) || (req == NULL)) {
msg("%s: Invalid args.\n", __func__);
return -(EINVAL);
}
ret_val = validate_clnt(client);
if (ret_val != 0)
return ret_val;
dev_mgr = client->dev_mgr;
switch (dev_mgr->dev_info.dev_type) {
case DEVICE_GENERIC_TYPE:
ret_val = devices_manager_set_lvl(dev_mgr, client, req->value);
break;
case DEVICE_OP_VALUE_TYPE:
ret_val = devices_manager_set_op_value(dev_mgr, client,
req->value);
break;
case DEVICE_DIRECT_ACTION_TYPE:
ret_val = devices_manager_set_direct_action(dev_mgr, client,
req);
break;
default:
dbgmsg("%s: Unhandled dev_type %d", __func__,
dev_mgr->dev_info.dev_type);
break;
}
return ret_val;
}
比如我们拿gpu举例,会调用devices_manager_set_op_value函数
static int devices_manager_set_op_value(struct devices_manager_dev *dev_mgr,
struct device_clnt *client,
int dev_op_value)
{
uint32_t lvl_idx = 0;
if (dev_op_value < 0) {
msg("%s: Invalid args.\n", __func__);
return -(EINVAL);
}
dev_mgr = client->dev_mgr;
if (dev_mgr->dev_info.max_dev_op_value_valid == 0) {
msg("%s: dev_op invalid.\n", __func__);
return -(EFAULT);
}
dev_op_value = MIN(dev_op_value, dev_mgr->dev_info.max_dev_op_value);//去client和device的max_dev_op_value的最小值
if (dev_mgr->lvl_info && (dev_mgr->dev_info.num_of_levels > 0)) {
/* Translate to dev_op_value to supported mitigation value */
for (lvl_idx = 0; lvl_idx < dev_mgr->dev_info.num_of_levels; lvl_idx++) {
if (dev_mgr->lvl_info[lvl_idx].lvl.value <= dev_op_value)
break;
}
if (lvl_idx >= dev_mgr->dev_info.num_of_levels) {
/* Apply highest lvl of mitigation possible */
lvl_idx = dev_mgr->dev_info.num_of_levels - 1U;
}
dev_op_value = dev_mgr->lvl_info[lvl_idx].lvl.value;//找到gpu合适的一个档位(就是刚比client的值小)
}
pthread_mutex_lock(&clnt_mtx);
client->request_active = 1;
client->request.value = dev_op_value;
pthread_mutex_unlock(&clnt_mtx);
dbgmsg("%s: DEV %s, op_value %d\n", __func__, dev_mgr->dev_info.name,
dev_op_value);
update_dev_state(dev_mgr);
return dev_mgr->active_req.value;
}
update_dev_state函数就是得到类型为DEVICE_OP_VALUE_TYPE的client的最小值,然后去执行device的action操作,value就是这个所有client的最小值。
static int update_dev_state(struct devices_manager_dev *dev_mgr)
{
union device_request req;
struct device_clnt *client = dev_mgr->client_list;
if ((dev_mgr->dev_info.dev_type != DEVICE_GENERIC_TYPE) &&
(dev_mgr->dev_info.dev_type != DEVICE_OP_VALUE_TYPE))
return -(EFAULT);
pthread_mutex_lock(&clnt_mtx);
if (dev_mgr->dev_info.dev_type == DEVICE_GENERIC_TYPE) {
/* Start from min level to find the highest existing client request */
req.value = dev_mgr->dev_info.min_lvl;
/* Walk client list to find highest mitigation level */
while (client != NULL) {
if (client->request_active)//这个类型找最大的
req.value = MAX(req.value, client->request.value);
client = client->next_clnt;
}
} else if (dev_mgr->dev_info.dev_type == DEVICE_OP_VALUE_TYPE) {
/* Start from max allowable value find lowest request */
req.value = dev_mgr->dev_info.max_dev_op_value;
/* Walk client list to find highest mitigation level */
while (client != NULL) {
if (client->request_active)
req.value = MIN(req.value, client->request.value);//gpu这种找所有client的最小的
client = client->next_clnt;
}
}
if (dev_mgr->active_req.value != req.value) {
dev_mgr->active_req.value = req.value;
if (dev_mgr->action)
dev_mgr->action(dev_mgr);//执行device的action函数。
/* Notify clients */
client = dev_mgr->client_list;
while (client != NULL) {
if (client->cb_func != NULL)
client->cb_func(client, &req,//调用client的回调
client->cb_usr_data);
client = client->next_clnt;
}
}
pthread_mutex_unlock(&clnt_mtx);
return 0;
}
我们继续分析handle_thresh_sig函数,当alarm_cleared而且当lvl_min为0,这个代表一个setting下面的t数组所有的触发都清除了,这个时候我们再调用clear_all_alarms函数。
if (alarm_cleared) {
/* Handle alarm clearing cases */
if (lvl_min == 0) {
dbgmsg("Clearing all alarms\n");
clear_all_alarms(sensor);
}
clear_all_alarms是该setting下的所有的device的client之前像device的申请的request都取消。
static void clear_all_alarms(struct tm_instance_info *sensor)
{
uint32_t i;
for (i = 0; i < MAX_ACTIONS_PER_TM_INSTANCE; i++) {
if (sensor->dev_clnt_list[i] == NULL)
continue;
/* check if action may have been set */
if ((sensor->action_mask & (1U << i)) == 0)
continue;
switch(sensor->dev_info_list[i]->dev_type) {
case DEVICE_GENERIC_TYPE:
case DEVICE_OP_VALUE_TYPE:
device_clnt_cancel_request(sensor->dev_clnt_list[i]);
break;
default:
dbgmsg("%s: No clearing of action %s\n", __func__,
sensor->dev_info_list[i]->name);
}
}
sensor->action_mask = 0;
}
这样monitor大致流程我们知道了。我们再来看下handle_thresh_sig下面这段代码,逆序遍历每个setting下面的t数组如果温度超过了设置的值且没有记录,就记为需要触发,并且我们会记录下lvl_max就是触发的那个最大的t数组的index。同时也会记录被清除的t数组的最小index。然后调用sensor_update_thresholds函数。
for (i = max_thr - 1; i >= 0; i--) {
/* Scan for new alarm conditions */
if (sensor_threshold_trigger(sensor_temp, sensor, i)) {
if (sensor->lvl_alarm[i] == 0) {
thermalmsg(LOG_LVL_DBG,
(LOG_LOGCAT | LOG_TRACE),
"TM Id '%s' Sensor '%s' - alarm "
" raised %d at %d.%d degC\n",
info->desc, tm_info->sensor, i + 1,
RCONV(sensor_temp),
(sensor_temp%1000)/100);
sensor->lvl_alarm[i] = 1;
alarm_raised = 1;
}
if (i > lvl_max)
lvl_max = i;//记录触发的t数组的最大index
}
/* Scan for alarm clearing conditions */
if (sensor_threshold_clear(sensor_temp, sensor, i)) {
if (sensor->lvl_alarm[i] == 1) {
thermalmsg(LOG_LVL_DBG,
(LOG_LOGCAT | LOG_TRACE),
"TM Id '%s' Sensor '%s' - alarm "
"cleared %d at %d.%d degC\n",
info->desc, tm_info->sensor, i + 1,
RCONV(sensor_temp),
(sensor_temp%1000)/100);
sensor->lvl_alarm[i] = 0;
alarm_cleared = 1;
}
if (i < lvl_min)
lvl_min = i;//清除就是记录t数组最小的index
}
}
/* Update temperature thresholds */
if (alarm_raised) {//如果这次是升温超过某个设定值
threshold_type = THRESHOLD_CROSS;
threshold_level = lvl_max + 1;//该值为最大值+1
} else if (alarm_cleared) {//这次是降温,小于某个clr的温度值
threshold_type = THRESHOLD_CLEAR;
threshold_level = lvl_min;//该值为最小值。
} else {
threshold_type = THRESHOLD_NOCHANGE;
threshold_level = sensor->last_lvl;
}
sensor->last_lvl = threshold_level;
pthread_mutex_lock(&wait_mutex);
/* Unmask TM instance as handled */
THRESH_MASK_CLR(idx);
pthread_mutex_unlock(&wait_mutex);
sensor_update_thresholds(sensor, threshold_type,
threshold_level, idx);
我们再来看sensor_update_thresholds函数,不得不说上面的设计挺巧妙的,我们现在无非两种情况:
1.如果现在是升温超过某个设定值,那么下一个升温的温度时,现在t数组触发最大的那个index+1的温度值,而clr的温度应该就是t数组最大的那个index当前的set_point_clr值。而这两个值就是sensor去监控的时候满足了,就会触发monitor算法的流程。
2. 如果现在是降温低于某个set_point_clr值了,那么下一个sensor要检测升温的值应该就是t数组记录的最小值index的set_point的温度值,而下一个降温的值就是当前t数组最小值index-1
现在把下一次sensor要检测的low和high记录好了,就可以往下调用sensors_manager_set_thresh_lvl函数。
static void sensor_update_thresholds(struct tm_instance_info *setting,
int threshold_type, int level,
uint32_t idx)
{
struct sensor_thresh_req ts_thresh_req;
struct thresholds_req_t *thresh = &ts_thresh_req.thresh;
struct tm_setting *tm_info = NULL;
if (setting == NULL ||
setting->ts_clnt == NULL) {
msg("%s: Unexpected NULL", __func__);
return;
}
tm_info = &(setting->setting->data.tm);
memset(&ts_thresh_req, 0, sizeof(struct sensor_thresh_req));
ts_thresh_req.notify_cb_func = sensor_thresh_notify;
ts_thresh_req.notify_cb_data = (void *)(uintptr_t)idx;
ts_thresh_req.polling_interval_valid = 1;
ts_thresh_req.polling_interval = tm_info->sampling_period_ms;
thresh->high_valid = 1;
thresh->low_valid = 1;
if (tm_info->descending_thresh) {//不分析
.......
} else {
thresh->descending_threshold = 0;
/* Rising trigger */
if ((uint32_t)level >= tm_info->num_thresholds) {
/* handle corner high case */
thresh->high = tm_info->t[tm_info->num_thresholds - 1].lvl_trig;
thresh->high_valid = 0;
} else
thresh->high = tm_info->t[level].lvl_trig;
if (level <= 0) {
/* handle corner low case */
thresh->low = tm_info->t[0].lvl_clr;
thresh->low_valid = 0;
} else
thresh->low = tm_info->t[level - 1].lvl_clr;
if (override_mode) {
thresh->high += tm_info->override;
thresh->low += tm_info->override;
}
}
sensors_manager_set_thresh_lvl(setting->ts_clnt, &ts_thresh_req);
}
sensors_manager_set_thresh_lvl函数主要就是把thresh_info放入client的request,然后将request_active的标志位置1,然后调用update_active_thresh函数。
int sensors_manager_set_thresh_lvl(sensor_clnt_handle clnt,
struct sensor_thresh_req *thresh_info)
{
struct sensors_mgr_sensor_info *sensor_mgr = NULL;
struct sensor_client_type *client = clnt;
int ret_val = 0;
if (client == NULL) {
msg("%s: Invalid args.\n", __func__);
return -(EINVAL);
}
ret_val = validate_clnt(client);//验证client
if (ret_val != 0)
return ret_val;
sensor_mgr = client->sensor_mgr;
THERM_MUTEX_LOCK(&ts_clnt_mtx);
if ( thresh_info == NULL) {
/* Clear client request */
client->request_active = 0;
dbgmsg("%s: %s clear request.\n", __func__, sensor_mgr->name);
} else if (validate_thresh_info(thresh_info) == 0) {
memcpy(&client->request, thresh_info,
sizeof(struct sensor_thresh_req));
client->request_active = 1;//申请的标志位
}
THERM_MUTEX_UNLOCK(&ts_clnt_mtx);
/* Update thresholds. */
update_active_thresh(sensor_mgr);
return 0;
}
update_active_thresh函数就是去更新下sensor的thresh的值。
static int update_active_thresh(struct sensors_mgr_sensor_info *sensor_mgr)
{
struct sensor_client_type *client = NULL;
struct sensor_thresh_req *active = NULL;
uint8_t active_req = 0;
if (sensor_mgr == NULL)
return -(EINVAL);
active = &sensor_mgr->active_thresh;
memset(active, 0, sizeof(struct sensor_thresh_req));
active->thresh.low = INT32_MIN;
active->thresh.high = INT32_MAX;
active->polling_interval = UINT32_MAX;
client = sensor_mgr->client_list;
THERM_MUTEX_LOCK(&ts_clnt_mtx);
while (client != NULL) {
if (!client->request_active) {//client没有申请的吧标志位直接continue
client = client->next_clnt;
continue;
}
struct sensor_thresh_req *thresh = &client->request;
if (thresh->thresh.descending_threshold)
active->thresh.descending_threshold = 1;
/* Find active high */
if (thresh->thresh.high_valid) {
active->thresh.high_valid = 1;
active->thresh.high = MIN(active->thresh.high,
thresh->thresh.high);
}
/* Find active low */
if (thresh->thresh.low_valid) {
active->thresh.low_valid = 1;
active->thresh.low = MAX(active->thresh.low,
thresh->thresh.low);
}
/* Find min polling interval */
if (thresh->polling_interval_valid) {
active->polling_interval_valid = 1;
active->polling_interval = MIN(active->polling_interval,
thresh->polling_interval);
}
active_req = 1;
client = client->next_clnt;
}
if ((active->thresh.high > active->thresh.low) &&
(active->thresh.high_valid || active->thresh.low_valid)) {
/* We can take advantage of interrupt */
sensor_mgr->active_thresh_valid = 1;
} else {
sensor_mgr->active_thresh_valid = 0;
}
/* Room for optimization if thresholds didn't change. */
if (sensor_mgr->active_thresh_valid &&
sensor_mgr->update_thresholds) {
sensor_mgr->update_thresholds(sensor_mgr);
}
if (!sensor_mgr->req_active && active_req) {
/* Advertise there is now an active request available */
pthread_mutex_lock(&(sensor_mgr->req_wait_mutex));
sensor_mgr->req_active = 1;//sensor的申请标志置1
pthread_cond_broadcast(&(sensor_mgr->req_wait_cond));
pthread_mutex_unlock(&(sensor_mgr->req_wait_mutex));
} else {
sensor_mgr->req_active = active_req;
}
THERM_MUTEX_UNLOCK(&ts_clnt_mtx);
return 0;
}
好到这里monitor算法的函数分析完了。
但是一般当我们第一次调用handle_thresh_sig函数的时候,这个时候通常不会超过设定的温度值,这个时候其实根本没有调频但是我们再去看sensor_monitor函数的主循环的时候,这个时候不能往下执行,因为在wait condition。
while (exit_daemon != 1) {
dbgmsg("%s: Wait for EV", __func__);
pthread_mutex_lock(&wait_mutex);
if (!THRESH_MASK_ANY_SET) {
pthread_cond_wait(&wait_cond, &wait_mutex);
}
pthread_mutex_unlock(&wait_mutex);
dbgmsg("%s: Thresh EVT", __func__);
handle_thresh_sig();
}
这个时候就要看sensor的sensor_monitor函数,之前分析sensor的博客我们分析过每一个sensor都会起一个thread执行sensor_monitor函数来监控每个sensor的温度。
static void *sensor_monitor(void *vsensor_mgr)
{
struct sensors_mgr_sensor_info *sensor_mgr = vsensor_mgr;
while (sensor_mgr->thread_shutdown != 1) {
/* Wait here until there is actually a request to process */
if (!sensor_mgr->req_active) {//需要sensor申请的标志位为1
dbgmsg("%s: %s Wait for client request.\n", __func__, sensor_mgr->name);
pthread_mutex_lock(&(sensor_mgr->req_wait_mutex));
while (!sensor_mgr->req_active) {
pthread_cond_wait(&(sensor_mgr->req_wait_cond),
&(sensor_mgr->req_wait_mutex));
}
pthread_mutex_unlock(&(sensor_mgr->req_wait_mutex));
}
dbgmsg("%s: %s Sensor wait.\n", __func__, sensor_mgr->name);
sensor_wait(sensor_mgr);
if (sensor_mgr->get_trip_temperature)
sensor_mgr->last_reading =
sensor_mgr->get_trip_temperature(sensor_mgr);
else
sensor_mgr->last_reading =//获取温度保存在last_reading
sensor_mgr->get_temperature(sensor_mgr);
notify_clnts(sensor_mgr);
}
return NULL;
}
我们再来看notify_clnts函数,这个时候我们还是遍历client,看每个client是否有申请,只有上一次sensor读取的温度大于最高值,或者小于最小值,才会调用client的回调函数。这样其实好处很明显不用核心的算法线程,一直跑,只要超过high的值,或者低于low的值才会重新开启算法的流程。
static int notify_clnts(struct sensors_mgr_sensor_info *sensor_mgr)
{
struct sensor_client_type *client = NULL;
enum sensor_notify_event_type thresh_event;
if (sensor_mgr == NULL)
return -(EINVAL);
client = sensor_mgr->client_list;
THERM_MUTEX_LOCK(&ts_clnt_mtx);
while (client != NULL) {//遍历每个client
if (client->request_active) {//client的申请为为1
struct thresholds_req_t *thresh = &client->request.thresh;
/* Notify clients of thresh crossings */
thresh_event = SENSOR_NOTIFY_NORMAL_THRESH_EVENT;
if (thresh->high_valid &&
(sensor_mgr->last_reading >= thresh->high)) {
thresh_event = SENSOR_NOTIFY_HIGH_THRESH_EVENT;
} else if (thresh->low_valid &&
(sensor_mgr->last_reading <= thresh->low)) {
thresh_event = SENSOR_NOTIFY_LOW_THRESH_EVENT;
}
if (thresh_event != SENSOR_NOTIFY_NORMAL_THRESH_EVENT) {
client->request_active = 0;
client->request.notify_cb_func(client,
thresh_event,
sensor_mgr->last_reading,
client->request.notify_cb_data);
}
}
client = client->next_clnt;
}
THERM_MUTEX_UNLOCK(&ts_clnt_mtx);
update_active_thresh(sensor_mgr);//这个方法上面分析过了,就是重新更新下sensor的thresh
return 0;
}
然后我们再来看Monitor算法sensor_thresh_notify函数,就是会去broadcast condition。
static void sensor_thresh_notify(sensor_clnt_handle clnt,
enum sensor_notify_event_type event,
int reading,
void *data)
{
if (NULL == clnt) {
msg("%s: unexpected NULL", __func__);
return;
}
if (((uintptr_t)data) >= tm_cnt) {
msg("%s: unexpected idx %zd", __func__, (uintptr_t)data);
return;
}
dbgmsg("%s: Update recieved %s %d", __func__,
tm_states[(uintptr_t)data].setting->desc,
reading);
/* Notify the waiting thread */
pthread_mutex_lock(&wait_mutex);
THRESH_MASK_SET((uintptr_t)data);
pthread_cond_broadcast(&wait_cond);
pthread_mutex_unlock(&wait_mutex);
}
这个时候sensor_monitor函数才会继续执行。
while (exit_daemon != 1) {
dbgmsg("%s: Wait for EV", __func__);
pthread_mutex_lock(&wait_mutex);
if (!THRESH_MASK_ANY_SET) {
pthread_cond_wait(&wait_cond, &wait_mutex);
}
pthread_mutex_unlock(&wait_mutex);
dbgmsg("%s: Thresh EVT", __func__);
handle_thresh_sig();
}
Monitor算法是一种静态算法,sensor的sensor_monitor会去不断检测这个sensor的温度,当大于每个setting设置的high的温度或者小于low的温度,就会去启动monitor算法流程。
monitor的算法配置中,当每一个t数组中的一项lvl_trig的温度满足时,该下面的所有的aciton中的device都会执行(每个device的client都会申请,最后device执行action函数),而只有当sensor温度小于每一个t数组中最小一档的lvl_clr,该t数组下所有的device的client的申请才会被取消,才会重新统计每个device的所有client的最大或最小值(根据device的type不同)再调用device的action函数。
{
.desc = "CAMERA_CAMCORDER_MONITOR",
.algo_type = MONITOR_ALGO_TYPE,
.data.tm = {
.sensor = "tsens_tz_sensor1",
.sampling_period_ms = 250,
.num_thresholds = 3,
._n_thresholds = 3,
._n_to_clear = 3,
._n_actions = 3,
._n_action_info = 3,
.t[0] = {
.lvl_trig = 80000,
.lvl_clr = 75000,
.num_actions = 2,
.actions[0] = {
.device = "camera",
.info = 1,
},
.actions[1] = {
.device = "camcorder",
.info = 1,
},
},
.t[1] = {
.lvl_trig = 85000,
.lvl_clr = 80000,
.num_actions = 2,
.actions[0] = {
.device = "camera",
.info = 2,
},
.actions[1] = {
.device = "camcorder",
.info = 2,
},
},
.t[2] = {
.lvl_trig = 88000,
.lvl_clr = 85000,
.num_actions = 2,
.actions[0] = {
.device = "camera",
.info = 10,
},
.actions[1] = {
.device = "camcorder",
.info = 10,
},
}
},