Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "ThermalManager.h"
      9 
     10 #include "SkOSFile.h"
     11 
     12 #include <stdio.h>
     13 
     14 #ifndef SK_BUILD_FOR_WIN32
     15     #include <unistd.h>
     16 #endif
     17 
     18 #ifdef THERMAL_MANAGER_SUPPORTED
     19 
     20 /*
     21  * ThermalManager is completely dependent on sysfs to monitor thermal temperatures.  In sysfs
     22  * thermal management is controlled by a number of thermal zones.  They are laid out as follows:
     23  * /sys/class/thermal/thermal_zoneN where N is the number of the thermal zone starting at 0.
     24  *
     25  * Inside each thermal_zone folder is a file called 'temp,' which has the current temperature
     26  * reading from the sensor in that zone, as well as 0 or more files called 'trip_point_N_temp.'
     27  *
     28  * When the reading in temp is greater than one of the numbers in the trip_point files, then the
     29  * kernel will take some kind of action.  This is all documented online.
     30  *
     31  * In any case, the goal of this class is to sleep right before a trip point is about to be
     32  * triggered, thus naturally cooling the system and preventing thermal throttling.
     33  */
     34 
     35 ThermalManager::ThermalManager(int32_t threshold, uint32_t sleepIntervalMs, uint32_t timeoutMs)
     36     : fSleepIntervalMs(sleepIntervalMs)
     37     , fTimeoutMs(timeoutMs) {
     38     static const char* kThermalZonePath = "/sys/class/thermal/";
     39     SkOSFile::Iter it(kThermalZonePath);
     40     SkString path;
     41     while (it.next(&path, true)) {
     42         if (!path.contains("thermal_zone")) {
     43             continue;
     44         }
     45 
     46         SkString fullPath(kThermalZonePath);
     47         fullPath.append(path);
     48         SkOSFile::Iter thermalZoneIt(fullPath.c_str());
     49 
     50         SkString filename;
     51         while (thermalZoneIt.next(&filename)) {
     52             if (!(filename.contains("trip_point") && filename.contains("temp"))) {
     53                 continue;
     54             }
     55 
     56             fTripPoints.push_back(TripPoint(fullPath, filename, threshold));
     57         }
     58     }
     59 }
     60 
     61 bool ThermalManager::coolOffIfNecessary() {
     62     uint32_t i = 0, totalTimeSleptMs = 0;
     63     while (i < (uint32_t)fTripPoints.count() && totalTimeSleptMs < fTimeoutMs) {
     64         if (fTripPoints[i].willTrip()) {
     65             sleep(fSleepIntervalMs);
     66             totalTimeSleptMs += fSleepIntervalMs;
     67         } else {
     68             i++;
     69         }
     70     }
     71 
     72     return totalTimeSleptMs < fTimeoutMs;
     73 }
     74 
     75 int32_t ThermalManager::OpenFileAndReadInt32(const char* path) {
     76     FILE* tempFile = fopen(path, "r");
     77     SkASSERT(tempFile);
     78     int32_t value;
     79     int ret = fscanf(tempFile, "%d", &value);
     80     if (!ret) {
     81         SkDebugf("Could not read temperature\n");
     82         SkASSERT(false);
     83     }
     84 
     85     fclose(tempFile);
     86     return value;
     87 }
     88 
     89 ThermalManager::TripPoint::TripPoint(SkString thermalZoneRoot, SkString pointName,
     90                                      int32_t threshold)
     91     : fThermalZoneRoot(thermalZoneRoot)
     92     , fPointName(pointName) {
     93     SkString fullPath(thermalZoneRoot);
     94     fullPath.appendf("/%s", pointName.c_str());
     95     fPoint = OpenFileAndReadInt32(fullPath.c_str());
     96     fBase = GetTemp(fThermalZoneRoot);
     97     fThreshold = threshold;
     98     fDisabled = fBase + fThreshold >= fPoint;  // We disable any trip point which start off
     99                                                // triggered
    100 }
    101 
    102 bool ThermalManager::TripPoint::willTrip() {
    103     int32_t currentTemp = GetTemp(fThermalZoneRoot);
    104     bool wouldTrip = !fDisabled && currentTemp + fThreshold >= fPoint;
    105 
    106     if (wouldTrip) {
    107         SkDebugf("%s/%s would trip {%d,%d,%d,%d}\n", fThermalZoneRoot.c_str(),
    108                  fPointName.c_str(), fBase, currentTemp, fPoint, fThreshold);
    109     }
    110     return wouldTrip;
    111 }
    112 
    113 #endif
    114