summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Schwartz <bsschwar@google.com>2019-08-21 16:30:55 -0700
committerBenjamin Schwartz <bsschwar@google.com>2019-09-13 15:59:29 -0700
commit37e62a1637370d1a1ed5d50d3fc897aae0e2a766 (patch)
tree3707b8b5ad953f413b63fce902a4f4182b84db0c
parentb54dffd29e72e9973ede8ce890a36bb3b44b0638 (diff)
downloadpixel-37e62a1637370d1a1ed5d50d3fc897aae0e2a766.tar.gz
pwrstats_util: Generate statistics using protobuf
Bug: 138745474 Test: adb shell pwrstats_util Change-Id: I2845d9b77c07d2df39017b983b370481a714d08d
-rw-r--r--pwrstats_util/Android.bp10
-rw-r--r--pwrstats_util/PowerStatsAggregator.cpp41
-rw-r--r--pwrstats_util/PowerStatsAggregator.h49
-rw-r--r--pwrstats_util/PowerStatsCollector.cpp131
-rw-r--r--pwrstats_util/PowerStatsCollector.h64
-rw-r--r--pwrstats_util/dataproviders/DataProviderHelper.cpp50
-rw-r--r--pwrstats_util/dataproviders/DataProviderHelper.h28
-rw-r--r--pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.cpp61
-rw-r--r--pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.h10
-rw-r--r--pwrstats_util/dataproviders/RailEnergyDataProvider.cpp75
-rw-r--r--pwrstats_util/dataproviders/RailEnergyDataProvider.h10
-rw-r--r--pwrstats_util/pwrstats_util.cpp97
-rw-r--r--pwrstats_util/pwrstatsutil.proto50
13 files changed, 515 insertions, 161 deletions
diff --git a/pwrstats_util/Android.bp b/pwrstats_util/Android.bp
index 1186b98b..ee9f824c 100644
--- a/pwrstats_util/Android.bp
+++ b/pwrstats_util/Android.bp
@@ -18,10 +18,16 @@ cc_library_static {
export_include_dirs: ["."],
srcs: [
"pwrstats_util.cpp",
- "PowerStatsAggregator.cpp",
+ "PowerStatsCollector.cpp",
"dataproviders/PowerEntityResidencyDataProvider.cpp",
"dataproviders/RailEnergyDataProvider.cpp",
+ "dataproviders/DataProviderHelper.cpp",
+ "pwrstatsutil.proto",
],
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
shared_libs: [
"libhidlbase",
"android.hardware.power.stats@1.0",
@@ -40,6 +46,7 @@ cc_defaults {
"-Werror=int-to-pointer-cast",
"-Werror=type-limits",
"-Werror",
+ "-Wno-unused-parameter",
],
tidy: true,
tidy_checks: [
@@ -63,5 +70,6 @@ cc_defaults {
"libbase",
"libutils",
"liblog",
+ "libprotobuf-cpp-full"
],
}
diff --git a/pwrstats_util/PowerStatsAggregator.cpp b/pwrstats_util/PowerStatsAggregator.cpp
deleted file mode 100644
index c3205050..00000000
--- a/pwrstats_util/PowerStatsAggregator.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "pwrstats_util"
-
-#include "PowerStatsAggregator.h"
-
-#include <android-base/logging.h>
-#include <android-base/parsedouble.h>
-
-#include <iostream>
-#include <memory>
-#include <unordered_map>
-
-void PowerStatsAggregator::addDataProvider(std::unique_ptr<IPowerStatsDataProvider> p) {
- mDataProviders.emplace_back(std::move(p));
-}
-
-int PowerStatsAggregator::getData(std::unordered_map<std::string, uint64_t>* data) const {
- data->clear();
- for (auto&& provider : mDataProviders) {
- int ret = provider->get(data);
- if (ret != 0) {
- data->clear();
- return ret;
- }
- }
- return 0;
-}
diff --git a/pwrstats_util/PowerStatsAggregator.h b/pwrstats_util/PowerStatsAggregator.h
deleted file mode 100644
index 70ff70f5..00000000
--- a/pwrstats_util/PowerStatsAggregator.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef POWERSTATSAGGREGATOR_H
-#define POWERSTATSAGGREGATOR_H
-
-#include <memory>
-#include <unordered_map>
-#include <vector>
-
-/**
- * Classes that implement this interface can be used to provide stats in the form of key/value
- * pairs to PwrStatsUtil.
- **/
-class IPowerStatsDataProvider {
- public:
- virtual ~IPowerStatsDataProvider() = default;
- virtual int get(std::unordered_map<std::string, uint64_t>* data) = 0;
-};
-
-/**
- * This class is used to return stats in the form of key/value pairs for all registered classes
- * that implement IPwrStatsUtilDataProvider.
- **/
-class PowerStatsAggregator {
- public:
- PowerStatsAggregator() = default;
- int getData(std::unordered_map<std::string, uint64_t>* data) const;
- void addDataProvider(std::unique_ptr<IPowerStatsDataProvider> dataProvider);
-
- private:
- std::vector<std::unique_ptr<IPowerStatsDataProvider>> mDataProviders;
-};
-
-int run(int argc, char** argv, const PowerStatsAggregator& agg);
-
-#endif // POWERSTATSAGGREGATOR_H
diff --git a/pwrstats_util/PowerStatsCollector.cpp b/pwrstats_util/PowerStatsCollector.cpp
new file mode 100644
index 00000000..d2b1c6d6
--- /dev/null
+++ b/pwrstats_util/PowerStatsCollector.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "pwrstats_util"
+
+#include "PowerStatsCollector.h"
+
+#include <android-base/logging.h>
+
+void PowerStatsCollector::addDataProvider(std::unique_ptr<IPowerStatProvider> p) {
+ mStatProviders.emplace(p->typeOf(), std::move(p));
+}
+
+int PowerStatsCollector::get(std::vector<PowerStatistic>* stats) const {
+ if (!stats) {
+ LOG(ERROR) << __func__ << ": bad args; stat is null";
+ return 1;
+ }
+
+ stats->clear();
+ for (auto&& provider : mStatProviders) {
+ PowerStatistic stat;
+ if (provider.second->get(&stat) != 0) {
+ LOG(ERROR) << __func__ << ": a data provider failed";
+ stats->clear();
+ return 1;
+ }
+
+ stats->emplace_back(stat);
+ }
+ return 0;
+}
+
+int PowerStatsCollector::get(const std::vector<PowerStatistic>& start,
+ std::vector<PowerStatistic>* interval) const {
+ if (!interval) {
+ LOG(ERROR) << __func__ << ": bad args; interval is null";
+ return 1;
+ }
+
+ interval->clear();
+ for (auto const& curStat : start) {
+ auto provider = mStatProviders.find(curStat.power_stat_case());
+ if (provider == mStatProviders.end()) {
+ LOG(ERROR) << __func__ << ": a provider is missing";
+ interval->clear();
+ return 1;
+ }
+
+ PowerStatistic curInterval;
+ if (provider->second->get(curStat, &curInterval) != 0) {
+ LOG(ERROR) << __func__ << ": a data provider failed";
+ interval->clear();
+ return 1;
+ }
+ interval->emplace_back(curInterval);
+ }
+ return 0;
+}
+
+void PowerStatsCollector::dump(const std::vector<PowerStatistic>& stats,
+ std::ostream* output) const {
+ if (!output) {
+ LOG(ERROR) << __func__ << ": bad args; output is null";
+ return;
+ }
+
+ for (auto const& stat : stats) {
+ auto provider = mStatProviders.find(stat.power_stat_case());
+ if (provider == mStatProviders.end()) {
+ LOG(ERROR) << __func__ << ": a provider is missing";
+ return;
+ }
+
+ provider->second->dump(stat, output);
+ }
+}
+
+int IPowerStatProvider::get(PowerStatistic* stat) const {
+ if (!stat) {
+ LOG(ERROR) << __func__ << ": bad args; stat is null";
+ return 1;
+ }
+
+ return getImpl(stat);
+}
+
+int IPowerStatProvider::get(const PowerStatistic& start, PowerStatistic* interval) const {
+ if (!interval) {
+ LOG(ERROR) << __func__ << ": bad args; interval is null";
+ return 1;
+ }
+
+ if (typeOf() != start.power_stat_case()) {
+ LOG(ERROR) << __func__ << ": bad args; start is incorrect type";
+ return 1;
+ }
+
+ if (0 != getImpl(interval)) {
+ LOG(ERROR) << __func__ << ": unable to retrieve stats";
+ return 1;
+ }
+
+ return getImpl(start, interval);
+}
+
+void IPowerStatProvider::dump(const PowerStatistic& stat, std::ostream* output) const {
+ if (!output) {
+ LOG(ERROR) << __func__ << ": bad args; output is null";
+ return;
+ }
+
+ if (typeOf() != stat.power_stat_case()) {
+ LOG(ERROR) << __func__ << ": bad args; stat is incorrect type";
+ return;
+ }
+
+ dumpImpl(stat, output);
+}
diff --git a/pwrstats_util/PowerStatsCollector.h b/pwrstats_util/PowerStatsCollector.h
new file mode 100644
index 00000000..cf7c991a
--- /dev/null
+++ b/pwrstats_util/PowerStatsCollector.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef POWERSTATSCOLLECTOR_H
+#define POWERSTATSCOLLECTOR_H
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include <pwrstatsutil.pb.h>
+
+using com::google::android::pwrstatsutil::PowerStatistic;
+using PowerStatCase = com::google::android::pwrstatsutil::PowerStatistic::PowerStatCase;
+
+/**
+ * Classes that inherit from this can be used to provide stats in the form of key/value
+ * pairs to PwrStatsUtil.
+ **/
+class IPowerStatProvider {
+ public:
+ virtual ~IPowerStatProvider() = default;
+ int get(PowerStatistic* stat) const;
+ int get(const PowerStatistic& start, PowerStatistic* interval) const;
+ void dump(const PowerStatistic& stat, std::ostream* output) const;
+ virtual PowerStatCase typeOf() const = 0;
+
+ private:
+ virtual int getImpl(PowerStatistic* stat) const = 0;
+ virtual int getImpl(const PowerStatistic& start, PowerStatistic* interval) const = 0;
+ virtual void dumpImpl(const PowerStatistic& stat, std::ostream* output) const = 0;
+};
+
+/**
+ * This class is used to return stats in the form of key/value pairs for all registered classes
+ * that implement IPowerStatProvider.
+ **/
+class PowerStatsCollector {
+ public:
+ PowerStatsCollector() = default;
+ int get(std::vector<PowerStatistic>* stats) const;
+ int get(const std::vector<PowerStatistic>& start, std::vector<PowerStatistic>* interval) const;
+ void dump(const std::vector<PowerStatistic>& stats, std::ostream* output) const;
+ void addDataProvider(std::unique_ptr<IPowerStatProvider> statProvider);
+
+ private:
+ std::unordered_map<PowerStatCase, std::unique_ptr<IPowerStatProvider>> mStatProviders;
+};
+
+int run(int argc, char** argv, const PowerStatsCollector& collector);
+
+#endif // POWERSTATSCOLLECTOR_H
diff --git a/pwrstats_util/dataproviders/DataProviderHelper.cpp b/pwrstats_util/dataproviders/DataProviderHelper.cpp
new file mode 100644
index 00000000..1494c54a
--- /dev/null
+++ b/pwrstats_util/dataproviders/DataProviderHelper.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "pwrstats_util"
+
+#include "DataProviderHelper.h"
+#include <android-base/logging.h>
+
+int StateResidencyInterval(const StateResidency_Residency& startResidency,
+ StateResidency_Residency* intervalResidency) {
+ // If start and interval are not the same size then they cannot have matching data
+ if (startResidency.size() != intervalResidency->size()) {
+ LOG(ERROR) << __func__ << ": mismatched data";
+ return 1;
+ }
+
+ for (int i = 0; i < startResidency.size(); ++i) {
+ // Check and make sure each entry matches. Data are in sorted order so if there is a
+ // mismatch then we will bail.
+ if (startResidency.Get(i).entity_name() != intervalResidency->Get(i).entity_name() ||
+ startResidency.Get(i).state_name() != intervalResidency->Get(i).state_name()) {
+ LOG(ERROR) << __func__ << ": mismatched data";
+ return 1;
+ }
+
+ auto delta = intervalResidency->Get(i).time_ms() - startResidency.Get(i).time_ms();
+ intervalResidency->Mutable(i)->set_time_ms(delta);
+ }
+ return 0;
+}
+
+void StateResidencyDump(const StateResidency_Residency& stateResidency, std::ostream* output) {
+ for (auto const& residency : stateResidency) {
+ *output << residency.entity_name() << ":" << residency.state_name() << "="
+ << residency.time_ms() << std::endl;
+ }
+ *output << std::endl;
+}
diff --git a/pwrstats_util/dataproviders/DataProviderHelper.h b/pwrstats_util/dataproviders/DataProviderHelper.h
new file mode 100644
index 00000000..7f931ffc
--- /dev/null
+++ b/pwrstats_util/dataproviders/DataProviderHelper.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef DATAPROVIDERHELPER_H
+#define DATAPROVIDERHELPER_H
+
+#include <pwrstatsutil.pb.h>
+
+using StateResidency_Residency = ::google::protobuf::RepeatedPtrField<
+ ::com::google::android::pwrstatsutil::StateResidency_Residency>;
+int StateResidencyInterval(const StateResidency_Residency& start,
+ StateResidency_Residency* interval);
+
+void StateResidencyDump(const StateResidency_Residency& stateResidency, std::ostream* output);
+
+#endif // DATAPROVIDERHELPER_H
diff --git a/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.cpp b/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.cpp
index ae5eff4f..fc5d66a0 100644
--- a/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.cpp
+++ b/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.cpp
@@ -16,8 +16,11 @@
#define LOG_TAG "pwrstats_util"
#include "PowerEntityResidencyDataProvider.h"
+#include "DataProviderHelper.h"
+
#include <android-base/logging.h>
#include <android/hardware/power/stats/1.0/IPowerStats.h>
+
using android::sp;
using android::hardware::Return;
@@ -26,17 +29,18 @@ using android::hardware::Return;
* Provides data monitored by Power Stats HAL 1.0
**/
-int PowerEntityResidencyDataProvider::get(std::unordered_map<std::string, uint64_t>* data) {
+int PowerEntityResidencyDataProvider::getImpl(PowerStatistic* stat) const {
sp<android::hardware::power::stats::V1_0::IPowerStats> powerStatsService =
android::hardware::power::stats::V1_0::IPowerStats::getService();
if (powerStatsService == nullptr) {
- LOG(ERROR) << "Unable to get power.stats HAL service.";
+ LOG(ERROR) << "unable to get power.stats HAL service";
return 1;
}
std::unordered_map<uint32_t, std::string> entityNames;
std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> stateNames;
+ // Create map of entity names based on entity id
Return<void> ret;
ret = powerStatsService->getPowerEntityInfo([&entityNames](auto infos, auto /* status */) {
for (auto const& info : infos) {
@@ -44,9 +48,11 @@ int PowerEntityResidencyDataProvider::get(std::unordered_map<std::string, uint64
}
});
if (!ret.isOk()) {
+ LOG(ERROR) << __func__ << ": unable to get entity info";
return 1;
}
+ // Create map of each entity's states based on entity and state id
ret = powerStatsService->getPowerEntityStateInfo({}, [&stateNames](auto stateSpaces,
auto /* status */) {
for (auto const& stateSpace : stateSpaces) {
@@ -59,24 +65,63 @@ int PowerEntityResidencyDataProvider::get(std::unordered_map<std::string, uint64
}
});
if (!ret.isOk()) {
+ LOG(ERROR) << __func__ << ": unable to get state info";
return 1;
}
+ // Retrieve residency data and create the PowerStatistic::PowerEntityStateResidency
ret = powerStatsService->getPowerEntityStateResidencyData({}, [&entityNames, &stateNames,
- &data](auto results,
+ &stat](auto results,
auto /* status */) {
+ auto residencies = stat->mutable_power_entity_state_residency();
for (auto const& result : results) {
- for (auto stateResidency : result.stateResidencyData) {
- std::ostringstream key;
- key << entityNames.at(result.powerEntityId) << "__"
- << stateNames.at(result.powerEntityId).at(stateResidency.powerEntityStateId);
- data->emplace(key.str(), static_cast<uint64_t>(stateResidency.totalTimeInStateMs));
+ for (auto const& curStateResidency : result.stateResidencyData) {
+ auto residency = residencies->add_residency();
+ residency->set_entity_name(entityNames.at(result.powerEntityId));
+ residency->set_state_name(stateNames.at(result.powerEntityId)
+ .at(curStateResidency.powerEntityStateId));
+ residency->set_time_ms(static_cast<uint64_t>(curStateResidency.totalTimeInStateMs));
}
}
+
+ // Sort entries first by entity_name, then by state_name.
+ // Sorting is needed to make interval processing efficient.
+ std::sort(residencies->mutable_residency()->begin(),
+ residencies->mutable_residency()->end(), [](const auto& a, const auto& b) {
+ if (a.entity_name() != b.entity_name()) {
+ return a.entity_name() < b.entity_name();
+ }
+
+ return a.state_name() < b.state_name();
+ });
});
if (!ret.isOk()) {
+ LOG(ERROR) << __func__ << ": Unable to get residency info";
return 1;
}
return 0;
}
+
+int PowerEntityResidencyDataProvider::getImpl(const PowerStatistic& start,
+ PowerStatistic* interval) const {
+ auto startResidency = start.power_entity_state_residency().residency();
+ auto intervalResidency = interval->mutable_power_entity_state_residency()->mutable_residency();
+
+ if (0 != StateResidencyInterval(startResidency, intervalResidency)) {
+ interval->clear_power_entity_state_residency();
+ return 1;
+ }
+
+ return 0;
+}
+
+void PowerEntityResidencyDataProvider::dumpImpl(const PowerStatistic& stat,
+ std::ostream* output) const {
+ *output << "Power Entity State Residencies:" << std::endl;
+ StateResidencyDump(stat.power_entity_state_residency().residency(), output);
+}
+
+PowerStatCase PowerEntityResidencyDataProvider::typeOf() const {
+ return PowerStatCase::kPowerEntityStateResidency;
+}
diff --git a/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.h b/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.h
index 73bb4532..b7264bb3 100644
--- a/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.h
+++ b/pwrstats_util/dataproviders/PowerEntityResidencyDataProvider.h
@@ -16,13 +16,17 @@
#ifndef POWERENTITYRESIDENCYDATAPROVIDER_H
#define POWERENTITYRESIDENCYDATAPROVIDER_H
-#include "PowerStatsAggregator.h"
+#include "PowerStatsCollector.h"
-class PowerEntityResidencyDataProvider : public IPowerStatsDataProvider {
+class PowerEntityResidencyDataProvider : public IPowerStatProvider {
public:
PowerEntityResidencyDataProvider() = default;
+ PowerStatCase typeOf() const override;
- int get(std::unordered_map<std::string, uint64_t>* data) override;
+ private:
+ int getImpl(PowerStatistic* stat) const override;
+ int getImpl(const PowerStatistic& start, PowerStatistic* interval) const override;
+ void dumpImpl(const PowerStatistic& stat, std::ostream* output) const override;
};
#endif // POWERENTITYRESIDENCYDATAPROVIDER_H
diff --git a/pwrstats_util/dataproviders/RailEnergyDataProvider.cpp b/pwrstats_util/dataproviders/RailEnergyDataProvider.cpp
index 5de6530a..7a2213ef 100644
--- a/pwrstats_util/dataproviders/RailEnergyDataProvider.cpp
+++ b/pwrstats_util/dataproviders/RailEnergyDataProvider.cpp
@@ -24,12 +24,11 @@ using android::hardware::Return;
using android::hardware::power::stats::V1_0::IPowerStats;
using android::hardware::power::stats::V1_0::Status;
-int RailEnergyDataProvider::get(std::unordered_map<std::string, uint64_t>* data) {
- // example using the power stats HAL
- sp<IPowerStats> powerStatsService =
+int RailEnergyDataProvider::getImpl(PowerStatistic* stat) const {
+ sp<android::hardware::power::stats::V1_0::IPowerStats> powerStatsService =
android::hardware::power::stats::V1_0::IPowerStats::getService();
if (powerStatsService == nullptr) {
- LOG(ERROR) << "Unable to get power.stats HAL service.";
+ LOG(ERROR) << "unable to get power.stats HAL service";
return 1;
}
@@ -44,41 +43,81 @@ int RailEnergyDataProvider::get(std::unordered_map<std::string, uint64_t>* data)
}
for (auto const& info : railInfos) {
- railNames.emplace(info.index,
- std::string(info.subsysName) + "__" + std::string(info.railName));
+ railNames.emplace(info.index, info.railName);
}
});
if (retStatus == Status::NOT_SUPPORTED) {
- LOG(WARNING) << "rail energy stats not supported";
+ LOG(WARNING) << __func__ << ": rail energy stats not supported";
return 0;
}
if (!ret.isOk() || retStatus != Status::SUCCESS) {
- LOG(ERROR) << "no rail information available";
+ LOG(ERROR) << __func__ << ": no rail information available";
return 1;
}
+ auto railEntries = stat->mutable_rail_energy();
bool resultSuccess = true;
ret = powerStatsService->getEnergyData(
- {}, [&data, &railNames, &resultSuccess](auto energyData, auto status) {
+ {}, [&railEntries, &railNames, &resultSuccess](auto energyData, auto status) {
if (status != Status::SUCCESS) {
- LOG(ERROR) << "Error getting rail energy";
+ LOG(ERROR) << __func__ << ": unable to get rail energy";
resultSuccess = false;
return;
}
+
for (auto const& energyDatum : energyData) {
- auto railName = railNames.find(energyDatum.index);
- if (railName == railNames.end()) {
- LOG(ERROR) << "Missing one or more rail names";
- resultSuccess = false;
- return;
- }
- data->emplace(railName->second, energyDatum.energy);
+ auto entry = railEntries->add_entry();
+ entry->set_rail_name(railNames.at(energyDatum.index));
+ entry->set_energy_uws(energyDatum.energy);
}
});
if (!ret.isOk() || !resultSuccess) {
- LOG(ERROR) << "Failed to get rail energy stats";
+ stat->clear_rail_energy();
+ LOG(ERROR) << __func__ << ": failed to get rail energy stats";
return 1;
}
+ // Sort entries by name. Sorting is needed to make interval processing efficient.
+ std::sort(railEntries->mutable_entry()->begin(), railEntries->mutable_entry()->end(),
+ [](const auto& a, const auto& b) { return a.rail_name() < b.rail_name(); });
+
return 0;
}
+
+int RailEnergyDataProvider::getImpl(const PowerStatistic& start, PowerStatistic* interval) const {
+ auto startEnergy = start.rail_energy().entry();
+ auto intervalEnergy = interval->mutable_rail_energy()->mutable_entry();
+
+ // If start and interval are not the same size then they cannot have matching data
+ if (startEnergy.size() != intervalEnergy->size()) {
+ LOG(ERROR) << __func__ << ": mismatched data";
+ interval->clear_rail_energy();
+ return 1;
+ }
+
+ for (int i = 0; i < startEnergy.size(); ++i) {
+ // Check and make sure each entry matches. Data are in sorted order so if there is a
+ // mismatch then we will bail.
+ if (startEnergy.Get(i).rail_name() != intervalEnergy->Get(i).rail_name()) {
+ LOG(ERROR) << __func__ << ": mismatched data";
+ interval->clear_rail_energy();
+ return 1;
+ }
+
+ auto delta = intervalEnergy->Get(i).energy_uws() - startEnergy.Get(i).energy_uws();
+ intervalEnergy->Mutable(i)->set_energy_uws(delta);
+ }
+ return 0;
+}
+
+void RailEnergyDataProvider::dumpImpl(const PowerStatistic& stat, std::ostream* output) const {
+ *output << "Rail Energy:" << std::endl;
+ for (auto const& rail : stat.rail_energy().entry()) {
+ *output << rail.rail_name() << "=" << rail.energy_uws() << std::endl;
+ }
+ *output << std::endl;
+}
+
+PowerStatCase RailEnergyDataProvider::typeOf() const {
+ return PowerStatCase::kRailEnergy;
+}
diff --git a/pwrstats_util/dataproviders/RailEnergyDataProvider.h b/pwrstats_util/dataproviders/RailEnergyDataProvider.h
index 919eacbb..abdaa6dc 100644
--- a/pwrstats_util/dataproviders/RailEnergyDataProvider.h
+++ b/pwrstats_util/dataproviders/RailEnergyDataProvider.h
@@ -16,18 +16,22 @@
#ifndef RAILENERGYDATAPROVIDER_H
#define RAILENERGYDATAPROVIDER_H
-#include "PowerStatsAggregator.h"
+#include "PowerStatsCollector.h"
/**
* Rail Energy data provider:
* Provides data via Power Stats HAL 1.0
* data is in units of microwatt-seconds (uWs)
**/
-class RailEnergyDataProvider : public IPowerStatsDataProvider {
+class RailEnergyDataProvider : public IPowerStatProvider {
public:
RailEnergyDataProvider() = default;
+ PowerStatCase typeOf() const override;
- int get(std::unordered_map<std::string, uint64_t>* data) override;
+ private:
+ int getImpl(PowerStatistic* stat) const override;
+ int getImpl(const PowerStatistic& start, PowerStatistic* interval) const override;
+ void dumpImpl(const PowerStatistic& stat, std::ostream* output) const override;
};
#endif // RAILENERGYDATAPROVIDER_H
diff --git a/pwrstats_util/pwrstats_util.cpp b/pwrstats_util/pwrstats_util.cpp
index b28b4b0f..55ef0717 100644
--- a/pwrstats_util/pwrstats_util.cpp
+++ b/pwrstats_util/pwrstats_util.cpp
@@ -17,76 +17,93 @@
#include <android-base/logging.h>
#include <fcntl.h>
+#include <getopt.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <algorithm>
#include <chrono>
#include <csignal>
#include <fstream>
#include <iostream>
-#include <unordered_map>
-#include "PowerStatsAggregator.h"
+#include <pwrstatsutil.pb.h>
+#include "PowerStatsCollector.h"
namespace {
volatile std::sig_atomic_t gSignalStatus;
}
+static void signalHandler(int signal) {
+ gSignalStatus = signal;
+}
+
class Options {
public:
+ bool humanReadable;
bool daemonMode;
std::string filePath;
};
-static void signalHandler(int signal) {
- gSignalStatus = signal;
-}
-
-static void printHelp() {
- std::cout << "pwrstats_util: Prints out device power stats in the form of key/value pairs."
- << std::endl
- << "-d </path/to/file> : daemon mode. Spawns a daemon process and prints out"
- << " its <pid>. kill -INT <pid> will trigger a write to specified file." << std::endl;
-}
-
static Options parseArgs(int argc, char** argv) {
Options opt = {
+ .humanReadable = false,
.daemonMode = false,
};
+ static struct option long_options[] = {/* These options set a flag. */
+ {"human-readable", no_argument, 0, 0},
+ {"daemon", required_argument, 0, 'd'},
+ {0, 0, 0, 0}};
+
+ // getopt_long stores the option index here
+ int option_index = 0;
+
int c;
- while ((c = getopt(argc, argv, "d:h")) != -1) {
+ while ((c = getopt_long(argc, argv, "d:", long_options, &option_index)) != -1) {
switch (c) {
+ case 0:
+ if ("human-readable" == std::string(long_options[option_index].name)) {
+ opt.humanReadable = true;
+ }
+ break;
case 'd':
opt.daemonMode = true;
opt.filePath = std::string(optarg);
break;
- case 'h':
- printHelp();
- exit(EXIT_SUCCESS);
- default:
+ default: /* '?' */
+ std::cerr << "pwrstats_util: Prints out device power stats." << std::endl
+ << "--human-readable: human-readable format" << std::endl
+ << "--daemon <path/to/file>, -d <path/to/file>: daemon mode. Spawns a "
+ "daemon process and prints out its <pid>. kill -INT <pid> will "
+ "trigger a write to specified file."
+ << std::endl;
exit(EXIT_FAILURE);
}
}
return opt;
}
-static void snapshot(const PowerStatsAggregator& agg) {
- std::unordered_map<std::string, uint64_t> data;
- int ret = agg.getData(&data);
+static void snapshot(const Options& opt, const PowerStatsCollector& collector) {
+ std::vector<PowerStatistic> stats;
+ int ret = collector.get(&stats);
if (ret) {
exit(EXIT_FAILURE);
}
- for (auto const& datum : data) {
- std::cout << datum.first << "=" << datum.second << std::endl;
+ if (opt.humanReadable) {
+ collector.dump(stats, &std::cout);
+ } else {
+ for (const auto& stat : stats) {
+ stat.SerializeToOstream(&std::cout);
+ }
}
exit(EXIT_SUCCESS);
}
-static void daemon(const std::string& filePath, const PowerStatsAggregator& agg) {
+static void daemon(const Options& opt, const PowerStatsCollector& collector) {
// Following a subset of steps outlined in http://man7.org/linux/man-pages/man7/daemon.7.html
// Call fork to create child process
@@ -144,10 +161,10 @@ static void daemon(const std::string& filePath, const PowerStatsAggregator& agg)
// get the start_data
auto start_time = std::chrono::system_clock::now();
- std::unordered_map<std::string, uint64_t> start_data;
- int ret = agg.getData(&start_data);
+ std::vector<PowerStatistic> start_stats;
+ int ret = collector.get(&start_stats);
if (ret) {
- LOG(ERROR) << "failed to get start data";
+ LOG(ERROR) << "failed to get start stats";
exit(EXIT_FAILURE);
}
@@ -157,10 +174,10 @@ static void daemon(const std::string& filePath, const PowerStatsAggregator& agg)
}
// get the end data
- std::unordered_map<std::string, uint64_t> end_data;
- ret = agg.getData(&end_data);
+ std::vector<PowerStatistic> interval_stats;
+ ret = collector.get(start_stats, &interval_stats);
if (ret) {
- LOG(ERROR) << "failed to get end data";
+ LOG(ERROR) << "failed to get interval stats";
exit(EXIT_FAILURE);
}
auto end_time = std::chrono::system_clock::now();
@@ -168,14 +185,18 @@ static void daemon(const std::string& filePath, const PowerStatsAggregator& agg)
std::chrono::duration<double> elapsed_seconds = end_time - start_time;
// Write data to file
- std::ofstream myfile(filePath);
+ std::ofstream myfile(opt.filePath, std::ios::out | std::ios::binary);
if (!myfile.is_open()) {
LOG(ERROR) << "failed to open file";
exit(EXIT_FAILURE);
}
myfile << "elapsed time: " << elapsed_seconds.count() << "s" << std::endl;
- for (auto const& datum : end_data) {
- myfile << datum.first << "=" << datum.second - start_data[datum.first] << std::endl;
+ if (opt.humanReadable) {
+ collector.dump(interval_stats, &myfile);
+ } else {
+ for (const auto& stat : interval_stats) {
+ stat.SerializeToOstream(&myfile);
+ }
}
myfile.close();
@@ -183,18 +204,18 @@ static void daemon(const std::string& filePath, const PowerStatsAggregator& agg)
exit(EXIT_SUCCESS);
}
-static void runWithOptions(const Options& opt, const PowerStatsAggregator& agg) {
+static void runWithOptions(const Options& opt, const PowerStatsCollector& collector) {
if (opt.daemonMode) {
- daemon(opt.filePath, agg);
+ daemon(opt, collector);
} else {
- snapshot(agg);
+ snapshot(opt, collector);
}
}
-int run(int argc, char** argv, const PowerStatsAggregator& agg) {
+int run(int argc, char** argv, const PowerStatsCollector& collector) {
Options opt = parseArgs(argc, argv);
- runWithOptions(opt, agg);
+ runWithOptions(opt, collector);
return 0;
}
diff --git a/pwrstats_util/pwrstatsutil.proto b/pwrstats_util/pwrstatsutil.proto
new file mode 100644
index 00000000..ee708a61
--- /dev/null
+++ b/pwrstats_util/pwrstatsutil.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+syntax = "proto3";
+
+option java_package = "com.google.android.pwrstatsutil";
+package com.google.android.pwrstatsutil;
+
+
+message PowerStatistic {
+ oneof power_stat {
+ StateResidency power_entity_state_residency = 1;
+ RailEnergy rail_energy = 2;
+ StateResidency c_state_residency = 3;
+ // add new power_stats here
+ }
+}
+
+// Utility message for items that provide a state residency in milliseconds
+message StateResidency {
+ message Residency {
+ string entity_name = 1;
+ string state_name = 2;
+ uint64 time_ms = 3;
+ }
+
+ repeated Residency residency = 1;
+}
+
+// Rail energy data in uWs
+message RailEnergy {
+ message RailEntry {
+ string rail_name = 1;
+ uint64 energy_uws = 2;
+ }
+
+ repeated RailEntry entry = 1;
+}