diff options
author | joshualitt <joshualitt@chromium.org> | 2016-02-09 07:18:08 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-09 07:18:08 -0800 |
commit | 3ebd050be551e9d1364dbd115708e8f86397cd6f (patch) | |
tree | bc3faddef38752c2f22ce373d28e90cb48581020 /tools | |
parent | 4984b85037bf0733d848318dfaff03ab85204a6f (diff) |
Create a thermal manager class and wire it in to nanobench behind a flag
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1671573002
Review URL: https://codereview.chromium.org/1671573002
Diffstat (limited to 'tools')
-rw-r--r-- | tools/ThermalManager.cpp | 113 | ||||
-rw-r--r-- | tools/ThermalManager.h | 61 |
2 files changed, 174 insertions, 0 deletions
diff --git a/tools/ThermalManager.cpp b/tools/ThermalManager.cpp new file mode 100644 index 0000000000..24770ab08e --- /dev/null +++ b/tools/ThermalManager.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "ThermalManager.h" + +#include "SkOSFile.h" + +#include <stdio.h> + +#ifdef THERMAL_MANAGER_SUPPORTED + +/* + * ThermalManager is completely dependent on sysfs to monitor thermal temperatures. In sysfs + * thermal management is controlled by a number of thermal zones. They are laid out as follows: + * /sys/class/thermal/thermal_zoneN where N is the number of the thermal zone starting at 0. + * + * Inside each thermal_zone folder is a file called 'temp,' which has the current temperature + * reading from the sensor in that zone, as well as 0 or more files called 'trip_point_N_temp.' + * + * When the reading in temp is greater than one of the numbers in the trip_point files, then the + * kernel will take some kind of action. This is all documented online. + * + * In any case, the goal of this class is to sleep right before a trip point is about to be + * triggered, thus naturally cooling the system and preventing thermal throttling. + */ + +ThermalManager::ThermalManager(int32_t threshold, uint32_t sleepIntervalMs, uint32_t timeoutMs) + : fSleepIntervalMs(sleepIntervalMs) + , fTimeoutMs(timeoutMs) { + static const char* kThermalZonePath = "/sys/class/thermal/"; + SkOSFile::Iter it(kThermalZonePath); + SkString path; + while (it.next(&path, true)) { + if (!path.contains("thermal_zone")) { + continue; + } + + SkString fullPath(kThermalZonePath); + fullPath.append(path); + SkOSFile::Iter thermalZoneIt(fullPath.c_str()); + + SkString filename; + while (thermalZoneIt.next(&filename)) { + if (!(filename.contains("trip_point") && filename.contains("temp"))) { + continue; + } + + fTripPoints.push_back(TripPoint(fullPath, filename, threshold)); + } + } +} + +bool ThermalManager::coolOffIfNecessary() { + uint32_t i = 0, totalTimeSleptMs = 0; + while (i < (uint32_t)fTripPoints.count() && totalTimeSleptMs < fTimeoutMs) { + if (fTripPoints[i].willTrip()) { + sleep(fSleepIntervalMs); + totalTimeSleptMs += fSleepIntervalMs; + } else { + i++; + } + } + + return totalTimeSleptMs < fTimeoutMs; +} + +int32_t ThermalManager::OpenFileAndReadInt32(const char* path) { + FILE* tempFile = fopen(path, "r"); + SkASSERT(tempFile); + int32_t value; + int ret = fscanf(tempFile, "%d", &value); + if (!ret) { + SkDebugf("Could not read temperature\n"); + SkASSERT(false); + } + + fclose(tempFile); + return value; +} + +ThermalManager::TripPoint::TripPoint(SkString thermalZoneRoot, SkString pointName, + int32_t threshold) + : fThermalZoneRoot(thermalZoneRoot) + , fPointName(pointName) { + SkString fullPath(thermalZoneRoot); + fullPath.appendf("/%s", pointName.c_str()); + fPoint = OpenFileAndReadInt32(fullPath.c_str()); + fBase = GetTemp(fThermalZoneRoot); + fDisabled = fBase >= fPoint + fThreshold; // We disable any trip point which start off + // triggered + fThreshold = threshold; + if (!fDisabled) { + SkDebugf("Trip point %s base - %d trip point-%d\n", fullPath.c_str(), + fBase, fPoint); + } +} + +bool ThermalManager::TripPoint::willTrip() { + int32_t currentTemp = GetTemp(fThermalZoneRoot); + bool wouldTrip = !fDisabled && currentTemp + fThreshold >= fPoint; + + if (wouldTrip) { + SkDebugf("%s/%s would trip {%d,%d,%d,%d}\n", fThermalZoneRoot.c_str(), + fPointName.c_str(), fBase, currentTemp, fPoint, fThreshold); + } + return wouldTrip; +} + +#endif diff --git a/tools/ThermalManager.h b/tools/ThermalManager.h new file mode 100644 index 0000000000..74e9dd1eac --- /dev/null +++ b/tools/ThermalManager.h @@ -0,0 +1,61 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef ThermalManager_DEFINED +#define ThermalManager_DEFINED + +#include "SkString.h" +#include "SkTArray.h" + +#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) +# define THERMAL_MANAGER_SUPPORTED +#endif + +#ifdef THERMAL_MANAGER_SUPPORTED + +/* + * This simple class monitors the thermal part of sysfs to ensure we don't trigger thermal events + */ + +class ThermalManager { +public: + ThermalManager(int32_t threshold, uint32_t sleepIntervalMs, uint32_t timeoutMs); + + bool coolOffIfNecessary(); + +private: + static int32_t OpenFileAndReadInt32(const char* path); + + // current temperature can be read from /thermalZonePath/temp + static int32_t GetTemp(SkString thermalZonePath) { + SkString temperatureFilePath(thermalZonePath); + temperatureFilePath.appendf("/temp"); + return OpenFileAndReadInt32(temperatureFilePath.c_str()); + } + + struct TripPoint { + TripPoint(SkString thermalZoneRoot, SkString pointName, int32_t threshold); + + bool willTrip(); + + SkString fThermalZoneRoot; + SkString fPointName; + int32_t fBase; + int32_t fPoint; + int32_t fThreshold; + + // Certain trip points seem to start tripped. For example, I have seen trip points of 0 or + // negative numbers. + bool fDisabled; + }; + + SkTArray<TripPoint> fTripPoints; + uint32_t fSleepIntervalMs; + uint32_t fTimeoutMs; +}; +#endif +#endif |