void cthd_cdev_rapl_msr::set_curr_state(int state, int arg) { int new_state; if (!control_start && state == inc_dec_val) { thd_log_debug("rapl state control begin\n"); rapl.store_pkg_power_limit(); control_start = true; } if (state < inc_dec_val) { new_state = 0; curr_state = 0; } else { new_state = phy_max - state; curr_state = state; thd_log_debug("rapl state = %d new_state = %d\n", state, new_state); rapl.set_pkg_power_limit(1, new_state); //thd_engine->def_poll_interval/1000 - 1, new_state); } if (state < inc_dec_val) { thd_log_debug("rapl state control end\n"); rapl.restore_pkg_power_limit(); control_start = false; } }
// Callback function called to get value via dbus gboolean thd_dbus_interface_get_current_preference(PrefObject *obj, gdouble *value_out, GError **error) { thd_log_debug("thd_dbus_interface_get_current_preference\n"); g_assert(obj != NULL); cthd_preference thd_pref; value_out = (gdouble*)thd_pref.get_preference_cstr(); thd_log_debug("thd_dbus_interface_get_current_preference out :%s\n", (char*) value_out); return TRUE; }
int cthd_nl_wrapper::genl_parse_event_message(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtattr *tb[ACPI_GENL_ATTR_MAX + 1]; struct genlmsghdr *ghdr = (struct genlmsghdr *)NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *attrs; if (n->nlmsg_type != acpi_event_family_id) { fprintf(stderr, "Not a acpi event message, nlmsg_len=%d " "nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type); return 0; } len -= NLMSG_LENGTH(GENL_HDRLEN); if (len < 0) { fprintf(stderr, "wrong controller message len %d\n", len); return -1; } attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); parse_rtattr(tb, ACPI_GENL_ATTR_MAX, attrs, len); if (tb[ACPI_GENL_ATTR_EVENT]) { struct acpi_genl_event *event = (struct acpi_genl_event *)RTA_DATA(tb[ACPI_GENL_ATTR_EVENT]); if (!strcmp(event->device_class, "thermal_zone")) { thermal_zone_notify_t msg; char *zone_str; msg.zone = 0; if (!strncmp(event->bus_id, "LNXTHERM:", strlen("LNXTHERM:"))) { zone_str = event->bus_id + strlen("LNXTHERM:"); sscanf(zone_str, "%d", &msg.zone); thd_log_debug("matched %s\n", zone_str); } msg.type = event->type; msg.data = event->data; thd_engine->send_message(THERMAL_ZONE_NOTIFY, sizeof(msg), (unsigned char*)&msg); thd_log_debug("%15s[zone %d] %08x %08x\n", event->bus_id, msg.zone, event->type, event->data); } return 0; } return -1; }
int cthd_msr::get_clock_mod_duty_cycle() { int ret, state = 0; unsigned long long val; // Just get for cpu 0 and return ret = read_msr(0, MSR_IA32_THERM_CONTROL, &val); thd_log_debug("get_clock_mod_duty_cycle current %x\n", (unsigned int) val); if (ret < 0) return THD_ERROR; if (val & MSR_IA32_CLK_MOD_ENABLE) { state = val & MSR_IA32_CLK_MOD_DUTY_CYCLE_MASK; state = state >> 1; thd_log_debug("current state %x\n", state); }
int cthd_topology::check_temperature(int index) { ssize_t retval; char pathname[64]; char temp_str[10]; int fd; unsigned int temperature; int current_moving_average; if(index >= no_sensors) return 0; sprintf(pathname, "/sys/devices/platform/coretemp.0/temp%d_input", index); fd = open(pathname, O_RDONLY); if(fd < 0) return - 1; retval = pread(fd, temp_str, sizeof(temp_str), 0); temperature = atoi(temp_str); current_moving_average = moving_average(temp_data, index, temperature); temp_data[index].last_moving_average = current_moving_average; thd_log_debug("DTS sensor %d mov average %u \n", index, current_moving_average) ; close(fd); return temperature; }
void cthd_sysfs_cdev_rapl::set_curr_state_raw(int state, int arg) { std::stringstream state_str; std::stringstream tc_state_dev; int new_state; if (state <= min_state) new_state = phy_max; else { if (dynamic_phy_max_enable) { if (!calculate_phy_max()) { curr_state = state; return; } } new_state = phy_max - state; } curr_state = state; state_str << new_state; tc_state_dev << "constraint_" << constraint_index << "_power_limit_uw"; if (cdev_sysfs.write(tc_state_dev.str(), state_str.str()) < 0) curr_state = (state == 0) ? 0 : max_state; thd_log_debug("set cdev state raw index %d state %d wr:%d\n", index, state, new_state); }
bool cthd_parse::platform_matched() { csys_fs thd_sysfs("/sys/class/dmi/id/"); if (thd_sysfs.exists(std::string("product_uuid"))) { thd_log_debug("checking UUID\n"); std::string str; if(thd_sysfs.read("product_uuid", str) >= 0) { thd_log_info("UUID is [%s]\n", str.c_str()); for (unsigned int i=0; i<thermal_info_list.size(); ++i) { if (thermal_info_list[i].uuid == str) { matched_thermal_info_index = i; thd_log_info("Product UUID matched \n"); return true; } } } } if (thd_sysfs.exists(std::string("product_name"))) { thd_log_debug("checking product name\n"); char product_name[128]; // Use different read method as the product name contains spaces if(thd_sysfs.read("product_name", product_name, 127) >= 0) { product_name[127] = '\0'; int len = strlen(product_name); if (!len) return false; for (int i=0; i<len; ++i) if (product_name[i] == '\n') product_name[i] = '\0'; thd_log_info("product name is[%s]\n", product_name); for (unsigned int i=0; i<thermal_info_list.size(); ++i) { if (!thermal_info_list[i].product_name.size()) continue; if (thermal_info_list[i].product_name.compare(0, strlen(product_name), product_name) == 0) { matched_thermal_info_index = i; thd_log_info("Product Name matched \n"); return true; } } } } return false; }
int cthd_cdev_rapl_msr::update() { int ret; if (!rapl.pkg_domain_present()) return THD_ERROR; if (!rapl.pp0_domain_present()) return THD_ERROR; if (rapl.get_power_unit() < 0) return THD_ERROR; if (rapl.get_time_unit() < 0) return THD_ERROR; ret = rapl.get_pkg_power_info(&thermal_spec_power, &max_power, &min_power, &max_time_window); if (ret < 0) return ret; thd_log_debug("Pkg Power Info: Thermal spec %f watts, max %f watts, min %f watts, max time window %f seconds\n", thermal_spec_power, max_power, min_power, max_time_window); max_state = 0; if (thermal_spec_power > 0) phy_max = (int)thermal_spec_power * 1000; // change to milliwatts else if(max_power > 0) phy_max = (int)max_power * 1000; // // change to milliwatts else return THD_ERROR; set_inc_dec_value(phy_max * (float)rapl_power_dec_percent/100); if (inc_dec_val == 0) set_inc_dec_value(phy_max * (float)rapl_power_dec_percent*2/100); if (inc_dec_val == 0) // power limit is too small inc_dec_val = 1; max_state = phy_max - ((float)phy_max * rapl_low_limit_percent/100); thd_log_debug("RAPL phy_max %d max_state %d inc_dec %d \n", phy_max, max_state, inc_dec_val); return THD_SUCCESS; }
cthd_trip_point::cthd_trip_point(int _index, trip_point_type_t _type, unsigned int _temp, unsigned int _hyst, int _zone_id, int _sensor_id, trip_control_type_t _control_type) : index(_index), type(_type), temp(_temp), hyst(_hyst), control_type( _control_type), zone_id(_zone_id), sensor_id(_sensor_id), trip_on( false), poll_on(false) { thd_log_debug("Add trip pt %d:%d:0x%x:%d:%d\n", type, zone_id, sensor_id, temp, hyst); }
// Callback function called to inform a sent value via dbus gboolean thd_dbus_interface_set_current_preference(PrefObject *obj, gint *value_out, GError **error) { int ret; thd_log_debug("thd_dbus_interface_set_current_preference %s\n", (char*) value_out); g_assert(obj != NULL); cthd_preference thd_pref; ret = thd_pref.set_preference((char*)value_out); thd_engine->send_message(PREF_CHANGED, 0, NULL); }
bool cthd_sysfs_cdev_rapl::calculate_phy_max() { if (dynamic_phy_max_enable) { unsigned int curr_max_phy; curr_max_phy = thd_engine->rapl_power_meter.rapl_action_get_power( PACKAGE); thd_log_debug("curr_phy_max = %u \n", curr_max_phy); if (curr_max_phy < rapl_min_default_step) return false; if (phy_max < curr_max_phy) { phy_max = curr_max_phy; set_inc_dec_value(phy_max * (float) rapl_power_dec_percent / 100); max_state = phy_max; max_state -= (float) max_state * rapl_low_limit_percent / 100; thd_log_debug("PHY_MAX %lu, step %d, max_state %d\n", phy_max, inc_dec_val, max_state); } } return true; }
// Callback function called to get value via dbus gboolean thd_dbus_interface_get_current_preference(PrefObject *obj, gchar **pref_out, GError **error) { thd_log_debug("thd_dbus_interface_get_current_preference\n"); g_assert(obj != NULL); gchar *value_out; static char *pref_str; pref_str = g_new(char, MAX_DBUS_REPLY_STR_LEN); if (!pref_str) return FALSE; cthd_preference thd_pref; value_out = (gchar*) thd_pref.get_preference_cstr(); strncpy(pref_str, value_out, MAX_DBUS_REPLY_STR_LEN); thd_log_debug("thd_dbus_interface_get_current_preference out :%s\n", pref_str); *pref_out = pref_str; return TRUE; }
gboolean thd_dbus_interface_set_user_max_temperature(PrefObject *obj, gchar *zone_name, gchar *temperature, GError **error) { thd_log_debug("thd_dbus_interface_set_user_set_point %s:%s\n", zone_name, temperature); g_assert(obj != NULL); cthd_preference thd_pref; if (thd_engine->thd_engine_set_user_max_temp(zone_name, (char*) temperature) == THD_SUCCESS) thd_engine->send_message(PREF_CHANGED, 0, NULL); return TRUE; }
int cthd_msr::set_clock_mod_duty_cycle(int state) { int cpu_count = get_no_cpus(); unsigned long long val; int ret; thd_log_info("Set T stated %d \n", state); // First bit is reserved state = state << 1; for (int i = 0; i < cpu_count; ++i) { ret = read_msr(i, MSR_IA32_THERM_CONTROL, &val); if (ret < 0) { thd_log_debug("set_clock_mod_duty_cycle current MSR read failed\n"); return THD_ERROR; } thd_log_debug("set_clock_mod_duty_cycle current %x\n", (unsigned int) val); if (!state) { val &= ~MSR_IA32_CLK_MOD_ENABLE; } else { val |= MSR_IA32_CLK_MOD_ENABLE; } val &= ~MSR_IA32_CLK_MOD_DUTY_CYCLE_MASK; val |= (state & MSR_IA32_CLK_MOD_DUTY_CYCLE_MASK); thd_log_debug("set_clock_mod_duty_cycle current set to %x\n", (unsigned int) val); ret = write_msr(i, MSR_IA32_THERM_CONTROL, val); if (ret < 0) { thd_log_warn( "set_clock_mod_duty_cycle current set failed to write\n"); return THD_ERROR; } } return THD_SUCCESS; }
int cthd_cdev::thd_cdev_set_min_state(int zone_id) { zone_mask &= ~(1 << zone_id); if (zone_mask != 0) { thd_log_debug( "skip to reduce current state as this is controlled by two zone actions and one is still on %x\n", (unsigned int) zone_mask); return THD_SUCCESS; } trend_increase = false; set_curr_state(min_state, zone_id); return THD_SUCCESS; }
void cthd_zone::thermal_zone_temp_change(int id, unsigned int temp, int pref) { int i, count; bool updated_max = false; bool reset = false; count = trip_points.size(); for (i = count - 1; i >= 0; --i) { cthd_trip_point &trip_point = trip_points[i]; if (trip_point.get_trip_type() == MAX) { thd_model.add_sample(zone_temp); if (thd_model.is_set_point_reached()) { int set_point; set_point = thd_model.get_set_point(); thd_log_debug("new set point %d \n", set_point); trip_point.thd_trip_update_set_point(set_point); updated_max = true; } } trip_point.thd_trip_point_check(id, temp, pref, &reset); // Force all cooling devices to min state if (reset) { zone_reset(); break; } } // Re-adjust polling thresholds if (updated_max) { for (i = count - 1; i >= 0; --i) { cthd_trip_point &trip_point = trip_points[i]; if (trip_point.get_trip_type() == POLLING) { thd_log_debug("new poll point %d \n", thd_model.get_hot_zone_trigger_point()); trip_point.thd_trip_update_set_point( thd_model.get_hot_zone_trigger_point()); trip_point.thd_trip_point_check(id, temp, pref, &reset); } } } }
unsigned int cthd_zone_dts_sensor::read_cpu_mask() { std::stringstream filename; unsigned int mask = 0; filename << TDCONFDIR << "/" << "dts_" << index << "_sensor_mask.conf"; thd_log_debug("read_cpu_mask file name %s\n", filename.str().c_str()); std::ifstream ifs(filename.str().c_str(), std::ifstream::in); if(ifs.good()) { ifs >> mask; conf_present = true; }
void cthd_trip_point::thd_trip_cdev_state_reset() { thd_log_info("thd_trip_cdev_state_reset \n"); for (int i = cdevs.size() - 1; i >= 0; --i) { cthd_cdev *cdev = cdevs[i].cdev; thd_log_info("thd_trip_cdev_state_reset index %d:%s\n", cdev->thd_cdev_get_index(), cdev->get_cdev_type().c_str()); if (cdev->in_min_state()) { thd_log_debug("Need to switch to next cdev \n"); // No scope of control with this cdev continue; } cdev->thd_cdev_set_min_state(zone_id); } }
cthd_rapl_power_meter::cthd_rapl_power_meter(unsigned int mask) : rapl_present(true), rapl_sysfs("/sys/class/powercap/intel-rapl/"), domain_list( 0), last_time(0), poll_thread(0), measure_mask(mask), enable_measurement( false) { if (rapl_sysfs.exists()) { thd_log_debug("RAPL sysfs present \n"); rapl_present = true; last_time = time(NULL); rapl_read_domains(rapl_sysfs.get_base_path()); } else { thd_log_warn("NO RAPL sysfs present \n"); rapl_present = false; } }
int cthd_zone_surface::read_trip_points() { cthd_trip_point *trip_ptr = NULL; bool add = false; if (!sensor) return THD_ERROR; for (unsigned int j = 0; j < trip_points.size(); ++j) { if (trip_points[j].get_trip_type() == PASSIVE) { thd_log_debug("updating existing trip temp \n"); trip_points[j].update_trip_temp(passive_trip_temp); trip_points[j].update_trip_hyst(passive_trip_hyst); trip_ptr = &trip_points[j]; break; } } if (!trip_ptr) { trip_ptr = new cthd_trip_point(trip_points.size(), PASSIVE, passive_trip_temp, passive_trip_hyst, index, sensor->get_index(), SEQUENTIAL); if (!trip_ptr) { thd_log_warn("Mem alloc error for new trip \n"); return THD_ERROR; } add = true; } cthd_cdev *cdev = thd_engine->search_cdev("rapl_controller"); if (cdev) { trip_ptr->thd_trip_point_add_cdev(*cdev, cthd_trip_point::default_influence, surface_sampling_period); } cdev = thd_engine->search_cdev("intel_powerclamp"); if (cdev) { trip_ptr->thd_trip_point_add_cdev(*cdev, cthd_trip_point::default_influence, surface_sampling_period); } if (add) { trip_points.push_back(*trip_ptr); } return THD_SUCCESS; }
bool cthd_sysfs_cdev_rapl::read_ppcc_power_limits() { csys_fs sys_fs; if (sys_fs.exists("/sys/bus/pci/devices/0000:00:04.0/power_limits/")) sys_fs.update_path("/sys/bus/pci/devices/0000:00:04.0/power_limits/"); else if (sys_fs.exists("/sys/bus/pci/devices/0000:00:0b.0/power_limits/")) sys_fs.update_path("/sys/bus/pci/devices/0000:00:0b.0/power_limits/"); else if (sys_fs.exists( "/sys/bus/platform/devices/INT3401:00/power_limits/")) sys_fs.update_path( "/sys/bus/platform/devices/INT3401:00/power_limits/"); else return false; if (sys_fs.exists("power_limit_0_max_uw")) { if (sys_fs.read("power_limit_0_max_uw", &pl0_max_pwr) <= 0) return false; } if (sys_fs.exists("power_limit_0_min_uw")) { if (sys_fs.read("power_limit_0_min_uw", &pl0_min_pwr) <= 0) return false; } if (sys_fs.exists("power_limit_0_tmin_us")) { if (sys_fs.read("power_limit_0_tmin_us", &pl0_min_window) <= 0) return false; } if (sys_fs.exists("power_limit_0_step_uw")) { if (sys_fs.read("power_limit_0_step_uw", &pl0_step_pwr) <= 0) return false; } if (pl0_max_pwr && pl0_min_pwr && pl0_min_window && pl0_step_pwr) { thd_log_debug("ppcc limits max:%u min:%u min_win:%u step:%u\n", pl0_max_pwr, pl0_min_pwr, pl0_min_window, pl0_step_pwr); return true; } return false; }
bool cthd_preference::set_preference(const char *pref_str) { std::string str(pref_str); int pref = string_pref_to_int(str); std::stringstream filename; filename << TDRUNDIR << "/" << "thd_preference.conf"; std::ofstream fout(filename.str().c_str()); if (!fout.good()) { return false; } fout << pref; fout.close(); // Save the old preference old_preference = preference; std::stringstream filename_save; filename_save << TDRUNDIR << "/" << "thd_preference.conf.save"; std::ofstream fout_save(filename_save.str().c_str()); if (!fout_save.good()) { return false; } fout_save << old_preference; fout_save.close(); std::ifstream ifs(filename.str().c_str(), std::ifstream::in); if (!ifs.good()) { preference = PREF_PERFORMANCE; } else { //ifs.read(reinterpret_cast < char * > (&preference), sizeof(preference)); ifs >> preference; } ifs.close(); thd_log_debug("old_preference %d new preference %d\n", old_preference, preference); return true; }
void cthd_zone::update_zone_preference() { if (!zone_active) return; thd_log_debug("update_zone_preference\n"); thd_model.update_user_set_max_temp(); for (unsigned int i = 0; i < sensors.size(); ++i) { cthd_sensor *sensor; sensor = sensors[i]; zone_temp = sensor->read_temperature(); thermal_zone_temp_change(sensor->get_index(), 0, thd_engine->get_preference()); } for (unsigned int i = 0; i < sensors.size(); ++i) { cthd_sensor *sensor; sensor = sensors[i]; zone_temp = sensor->read_temperature(); thermal_zone_temp_change(sensor->get_index(), zone_temp, thd_engine->get_preference()); } }
int cthd_sysfs_cdev_rapl::update() { int i; std::stringstream temp_str; int _index = -1; unsigned long constraint_phy_max; bool ppcc = false; std::string domain_name; for (i = 0; i < rapl_no_time_windows; ++i) { temp_str << "constraint_" << i << "_name"; if (cdev_sysfs.exists(temp_str.str())) { std::string type_str; cdev_sysfs.read(temp_str.str(), type_str); if (type_str == "long_term") { _index = i; break; } } } if (_index < 0) { thd_log_info("powercap RAPL no long term time window\n"); return THD_ERROR; } cdev_sysfs.read("name", domain_name); if (domain_name == "package-0") ppcc = read_ppcc_power_limits(); if (ppcc) { phy_max = pl0_max_pwr; set_inc_dec_value(pl0_step_pwr); max_state = pl0_max_pwr - pl0_min_pwr; } else { temp_str.str(std::string()); temp_str << "constraint_" << _index << "_max_power_uw"; if (!cdev_sysfs.exists(temp_str.str())) { thd_log_info("powercap RAPL no max power limit range %s \n", temp_str.str().c_str()); return THD_ERROR; } if (cdev_sysfs.read(temp_str.str(), &phy_max) < 0) { thd_log_info("powercap RAPL invalid max power limit range \n"); thd_log_info("Calculate dynamically phy_max \n"); phy_max = 0; thd_engine->rapl_power_meter.rapl_start_measure_power(); max_state = rapl_min_default_step; set_inc_dec_value(rapl_min_default_step); dynamic_phy_max_enable = true; return THD_SUCCESS; } std::stringstream temp_power_str; temp_power_str.str(std::string()); temp_power_str << "constraint_" << _index << "_power_limit_uw"; if (!cdev_sysfs.exists(temp_power_str.str())) { thd_log_info("powercap RAPL no power limit uw %s \n", temp_str.str().c_str()); return THD_ERROR; } if (cdev_sysfs.read(temp_power_str.str(), &constraint_phy_max) <= 0) { thd_log_info("powercap RAPL invalid max power limit range \n"); constraint_phy_max = 0; } if (constraint_phy_max > phy_max) { thd_log_info( "Default constraint power limit is more than max power %lu:%lu\n", constraint_phy_max, phy_max); phy_max = constraint_phy_max; } thd_log_info("powercap RAPL max power limit range %lu \n", phy_max); set_inc_dec_value(phy_max * (float) rapl_power_dec_percent / 100); max_state = phy_max; max_state -= (float) max_state * rapl_low_limit_percent / 100; } std::stringstream time_window; temp_str.str(std::string()); temp_str << "constraint_" << _index << "_time_window_us"; if (!cdev_sysfs.exists(temp_str.str())) { thd_log_info("powercap RAPL no time_window_us %s \n", temp_str.str().c_str()); return THD_ERROR; } if (pl0_min_window) time_window << pl0_min_window; else time_window << def_rapl_time_window; cdev_sysfs.write(temp_str.str(), time_window.str()); std::stringstream enable; temp_str.str(std::string()); temp_str << "enabled"; if (!cdev_sysfs.exists(temp_str.str())) { thd_log_info("powercap RAPL no enabled %s \n", temp_str.str().c_str()); return THD_ERROR; } cdev_sysfs.write(temp_str.str(), "0"); thd_log_debug("RAPL max limit %d increment: %d\n", max_state, inc_dec_val); constraint_index = _index; set_pid_param(1000, 100, 10); return THD_SUCCESS; }
// Setup dbus server static int thd_dbus_server_proc(gboolean no_daemon) { DBusGConnection *bus; DBusGProxy *bus_proxy; GMainLoop *main_loop; GError *error = NULL; guint result; PrefObject *value_obj; thd_engine = NULL; // Initialize the GType/GObject system g_type_init(); // Create a main loop that will dispatch callbacks g_main_loop = main_loop = g_main_loop_new(NULL, FALSE); if (main_loop == NULL) { thd_log_error("Couldn't create GMainLoop:"); return THD_FATAL_ERROR; } if (dbus_enable) { bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); if (error != NULL) { thd_log_error("Couldn't connect to session bus: %s:", error->message); return THD_FATAL_ERROR; } // Get a bus proxy instance bus_proxy = dbus_g_proxy_new_for_name(bus, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); if (bus_proxy == NULL) { thd_log_error("Failed to get a proxy for D-Bus:"); return THD_FATAL_ERROR; } thd_log_debug("Registering the well-known name (%s)\n", THD_SERVICE_NAME); // register the well-known name if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error, G_TYPE_STRING, THD_SERVICE_NAME, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID)) { thd_log_error("D-Bus.RequestName RPC failed: %s\n", error->message); return THD_FATAL_ERROR; } thd_log_debug("RequestName returned %d.\n", result); if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { thd_log_error("Failed to get the primary well-known name:"); return THD_FATAL_ERROR; } value_obj = (PrefObject*) g_object_new(PREF_TYPE_OBJECT, NULL); if (value_obj == NULL) { thd_log_error("Failed to create one Value instance:"); return THD_FATAL_ERROR; } thd_log_debug("Registering it on the D-Bus.\n"); dbus_g_connection_register_g_object(bus, THD_SERVICE_OBJECT_PATH, G_OBJECT(value_obj)); } if (!no_daemon) { printf("Ready to serve requests: Daemonizing.. %d\n", thd_daemonize); thd_log_info( "thermald ver %s: Ready to serve requests: Daemonizing..\n", TD_DIST_VERSION); if (daemon(0, 1) != 0) { thd_log_error("Failed to daemonize.\n"); return THD_FATAL_ERROR; } } thd_engine = new cthd_engine_default(); if (exclusive_control) thd_engine->set_control_mode(EXCLUSIVE); // Initialize thermald objects thd_engine->set_poll_interval(thd_poll_interval); if (thd_engine->thd_engine_start(ignore_cpuid_check) != THD_SUCCESS) { thd_log_error("THD engine start failed: "); closelog(); exit(1); } // Start service requests on the D-Bus thd_log_debug("Start main loop\n"); g_main_loop_run(main_loop); thd_log_warn("Oops g main loop exit..\n"); return THD_SUCCESS; }
int cthd_cdev::thd_cdev_exponential_controller(int set_point, int target_temp, int temperature, int state, int zone_id) { curr_state = get_curr_state(); if ((min_state < max_state && curr_state < min_state) || (min_state > max_state && curr_state > min_state)) curr_state = min_state; max_state = get_max_state(); thd_log_debug("thd_cdev_set_%d:curr state %d max state %d\n", index, curr_state, max_state); if (state) { if ((min_state < max_state && curr_state < max_state) || (min_state > max_state && curr_state > max_state)) { int state = curr_state + inc_dec_val; if (trend_increase) { if (curr_pow == 0) base_pow_state = curr_state; ++curr_pow; state = base_pow_state + int_2_pow(curr_pow) * inc_dec_val; thd_log_info( "cdev index:%d consecutive call, increment exponentially state %d\n", index, state); if ((min_state < max_state && state >= max_state) || (min_state > max_state && state <= max_state)) { state = max_state; curr_pow = 0; curr_state = max_state; } } else { curr_pow = 0; } trend_increase = true; if ((min_state < max_state && state > max_state) || (min_state > max_state && state < max_state)) state = max_state; thd_log_debug("op->device:%s %d\n", type_str.c_str(), state); set_curr_state(state, zone_id); } } else { curr_pow = 0; trend_increase = false; if (((min_state < max_state && curr_state > min_state) || (min_state > max_state && curr_state < min_state)) && auto_down_adjust == false) { int state = curr_state - inc_dec_val; if ((min_state < max_state && state < min_state) || (min_state > max_state && state > min_state)) state = min_state; thd_log_debug("op->device:%s %d\n", type_str.c_str(), state); set_curr_state(state, zone_id); } else { thd_log_debug("op->device: force min %s %d\n", type_str.c_str(), min_state); set_curr_state(min_state, zone_id); } } thd_log_info( "Set : threshold:%d, temperature:%d, cdev:%d(%s), curr_state:%d, max_state:%d\n", set_point, temperature, index, type_str.c_str(), get_curr_state(), max_state); thd_log_debug("<<thd_cdev_set_state %d\n", state); return THD_SUCCESS; }
bool cthd_rapl_power_meter::rapl_energy_loop() { csys_fs sys_fs; int status; unsigned long long counter; unsigned long long diff; time_t curr_time; if (!enable_measurement) return false; curr_time = time(NULL); if ((curr_time - last_time) <= 0) return true; for (unsigned int i = 0; i < domain_list.size(); ++i) { std::string buffer; std::string path; if (!domain_list[i].max_energy_range) { std::string _path; std::string _buffer; _path = domain_list[i].path + "/" + "max_energy_range_uj"; status = sys_fs.read(_path, _buffer); if (status >= 0) domain_list[i].max_energy_range = atoll(_buffer.c_str()) / 1000; domain_list[i].max_energy_range_threshold = domain_list[i].max_energy_range / 2; } path = domain_list[i].path + "/" + "energy_uj"; status = sys_fs.read(path, buffer); if (status >= 0) { counter = domain_list[i].energy_counter; domain_list[i].energy_counter = atoll(buffer.c_str()) / 1000; // To milli Js diff = 0; if (domain_list[i].half_way && domain_list[i].energy_counter < domain_list[i].max_energy_range_threshold) { // wrap around domain_list[i].energy_cumulative_counter += domain_list[i].max_energy_range; diff = domain_list[i].max_energy_range - counter; counter = 0; domain_list[i].half_way = 0; } else if (domain_list[i].energy_counter > domain_list[i].max_energy_range_threshold) domain_list[i].half_way = 1; if (counter) domain_list[i].power = (domain_list[i].energy_counter - counter + diff) / (curr_time - last_time); if (domain_list[i].power > domain_list[i].max_power) domain_list[i].max_power = domain_list[i].power; if (domain_list[i].min_power == 0) domain_list[i].min_power = domain_list[i].power; else if (domain_list[i].power < domain_list[i].min_power) domain_list[i].min_power = domain_list[i].power; thd_log_debug(" energy %d:%lld:%lld mj: %u mw \n", domain_list[i].type, domain_list[i].energy_cumulative_counter, domain_list[i].energy_counter + domain_list[i].energy_cumulative_counter, domain_list[i].power); } } last_time = curr_time; return true; }
cthd_zone::cthd_zone(int _index, std::string control_path, sensor_relate_t rel) : index(_index), zone_sysfs(control_path.c_str()), zone_temp(0), zone_active( false), zone_cdev_binded_status(false), type_str(), sensor_rel( rel), thd_model("") { thd_log_debug("Added zone index:%d \n", index); }
int cthd_cdev::thd_cdev_set_state(int set_point, int target_temp, int temperature, int state, int zone_id, int trip_id, int target_value) { time_t tm; int ret; time(&tm); thd_log_debug(">>thd_cdev_set_state index:%d state:%d :%d:%d:%d\n", index, state, zone_id, trip_id, target_value); if (last_state == state && (tm - last_action_time) <= debounce_interval) { thd_log_debug( "Ignore: delay < debounce interval : %d, %d, %d, %d, %d\n", set_point, temperature, index, get_curr_state(), max_state); return THD_SUCCESS; } last_state = state; if (state) { zone_mask |= (1 << zone_id); trip_mask |= (1 << trip_id); if (target_value != TRIP_PT_INVALID_TARGET_STATE) { zone_trip_limits_t limit; bool found = false; for (unsigned int i = 0; i < zone_trip_limits.size(); ++i) { if (zone_trip_limits[i].zone == zone_id && zone_trip_limits[i].trip == trip_id) { found = true; break; } } if (!found) { limit.zone = zone_id; limit.trip = trip_id; limit.target_value = target_value; thd_log_debug("Added zone %d trip %d clamp %d\n", limit.zone, limit.trip, limit.target_value); zone_trip_limits.push_back(limit); std::sort(zone_trip_limits.begin(), zone_trip_limits.end(), sort_clamp_values); } set_curr_state_raw(target_value, zone_id); curr_state = target_value; last_action_time = tm; thd_log_info( "Set : threshold:%d, temperature:%d, cdev:%d(%s), curr_state:%d, max_state:%d\n", set_point, temperature, index, type_str.c_str(), get_curr_state(), max_state); return THD_SUCCESS; } } else { if (zone_mask & (1 << zone_id)) { if (trip_mask & (1 << trip_id)) { trip_mask &= ~(1 << trip_id); zone_mask &= ~(1 << zone_id); } } if (zone_trip_limits.size() > 0) { int length = zone_trip_limits.size(); int i; // Just remove the current zone requesting to turn off for (i = 0; i < length; ++i) { if (zone_trip_limits[i].zone == zone_id && zone_trip_limits[i].trip == trip_id) { zone_trip_limits.erase(zone_trip_limits.begin() + i); thd_log_debug("Erased [%d: %d\n", zone_id, trip_id); break; } } zone_trip_limits_t limit; if (zone_trip_limits.size() == 0) { limit.target_value = get_min_state(); limit.zone = zone_id; limit.trip = trip_id; } else { limit = zone_trip_limits[zone_trip_limits.size() - 1]; } if (cmp_current_state(limit.target_value) < 0) { thd_log_info( "new active zone; next in line %d trip %d clamp %d\n", limit.zone, limit.trip, limit.target_value); set_curr_state_raw(limit.target_value, zone_id); thd_log_info( "Set : threshold:%d, temperature:%d, cdev:%d(%s), curr_state:%d, max_state:%d\n", set_point, temperature, index, type_str.c_str(), get_curr_state(), max_state); } return THD_SUCCESS; } else if (zone_mask != 0 || trip_mask != 0) { thd_log_debug( "skip to reduce current state as this is controlled by two zone or trip actions and one is still on %lx:%lx\n", zone_mask, trip_mask); return THD_SUCCESS; } } last_action_time = tm; curr_state = get_curr_state(); if (curr_state == get_min_state()) { control_begin(); } if (pid_enable) { pid_ctrl.set_target_temp(target_temp); ret = pid_ctrl.pid_output(temperature); ret += get_curr_state(); if (ret > get_max_state()) ret = get_max_state(); if (ret < get_min_state()) ret = get_min_state(); set_curr_state_raw(ret, zone_id); thd_log_debug("Set : %d, %d, %d, %d, %d\n", set_point, temperature, index, get_curr_state(), max_state); ret = THD_SUCCESS; } else { ret = thd_cdev_exponential_controller(set_point, target_temp, temperature, state, zone_id); } if (curr_state == get_max_state()) { control_end(); } return ret; }
void cthd_rapl_power_meter::rapl_read_domains(const char *dir_name) { int count = 0; csys_fs sys_fs; if (rapl_present) { DIR *dir; struct dirent *dir_entry; thd_log_debug("RAPL base path %s\n", dir_name); if ((dir = opendir(dir_name)) != NULL) { while ((dir_entry = readdir(dir)) != NULL) { std::string buffer; std::stringstream path; int status; rapl_domain_t domain; domain.half_way = 0; domain.energy_counter = 0; domain.energy_cumulative_counter = 0; domain.max_energy_range = 0; domain.max_energy_range_threshold = 0; domain.power = 0; domain.max_power = 0; domain.min_power = 0; domain.type = PACKAGE; if (!strcmp(dir_entry->d_name, ".") || !strcmp(dir_entry->d_name, "..")) continue; thd_log_debug("RAPL domain dir %s\n", dir_entry->d_name); path << dir_name << dir_entry->d_name << "/" << "name"; if (!sys_fs.exists(path.str())) { thd_log_debug(" %s doesn't exist\n", path.str().c_str()); continue; } status = sys_fs.read(path.str(), buffer); if (status < 0) continue; thd_log_debug("name %s\n", buffer.c_str()); if (fnmatch("package-*", buffer.c_str(), 0) == 0) { domain.type = PACKAGE; std::stringstream path; path << dir_name << dir_entry->d_name << "/"; rapl_read_domains(path.str().c_str()); } else if (buffer == "core") { domain.type = CORE; } else if (buffer == "uncore") { domain.type = UNCORE; } else if (buffer == "dram") { domain.type = DRAM; } if (measure_mask & domain.type) { domain.name = buffer; domain.path = std::string(dir_name) + std::string(dir_entry->d_name); domain_list.push_back(domain); ++count; } } closedir(dir); } else { thd_log_debug("opendir failed %s :%s\n", strerror(errno), rapl_sysfs.get_base_path()); } } thd_log_info("RAPL domain count %d\n", count); }