Home | History | Annotate | Download | only in power-libperfmgr
      1 /*
      2  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  * *    * Redistributions of source code must retain the above copyright
      8  *       notice, this list of conditions and the following disclaimer.
      9  *     * Redistributions in binary form must reproduce the above
     10  *       copyright notice, this list of conditions and the following
     11  *       disclaimer in the documentation and/or other materials provided
     12  *       with the distribution.
     13  *     * Neither the name of The Linux Foundation nor the names of its
     14  *       contributors may be used to endorse or promote products derived
     15  *       from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #define LOG_NIDEBUG 0
     31 #define LOG_TAG "android.hardware.power (at) 1.2-service.wahoo-libperfmgr"
     32 
     33 #include <errno.h>
     34 #include <inttypes.h>
     35 #include <string.h>
     36 #include <sys/types.h>
     37 #include <sys/stat.h>
     38 #include <fcntl.h>
     39 #include <dlfcn.h>
     40 #include <stdlib.h>
     41 
     42 #include <log/log.h>
     43 
     44 #include "power-helper.h"
     45 
     46 #ifndef RPM_SYSTEM_STAT
     47 #define RPM_SYSTEM_STAT "/d/system_stats"
     48 #endif
     49 
     50 #ifndef WLAN_POWER_STAT
     51 #define WLAN_POWER_STAT "/d/wlan0/power_stats"
     52 #endif
     53 
     54 #ifndef EASEL_STATE_FILE
     55 #define EASEL_STATE_FILE "/sys/devices/virtual/misc/mnh_sm/state"
     56 #endif
     57 
     58 #define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
     59 #define LINE_SIZE 128
     60 
     61 const char *rpm_stat_params[MAX_RPM_PARAMS] = {
     62     "count",
     63     "actual last sleep(msec)",
     64 };
     65 
     66 const char *master_stat_params[MAX_RPM_PARAMS] = {
     67     "Accumulated XO duration",
     68     "XO Count",
     69 };
     70 
     71 struct stat_pair rpm_stat_map[] = {
     72     { RPM_MODE_XO,   "RPM Mode:vlow", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
     73     { RPM_MODE_VMIN, "RPM Mode:vmin", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
     74     { VOTER_APSS,    "APSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     75     { VOTER_MPSS,    "MPSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     76     { VOTER_ADSP,    "ADSP",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     77     { VOTER_SLPI,    "SLPI",    master_stat_params, ARRAY_SIZE(master_stat_params) },
     78 };
     79 
     80 
     81 const char *wlan_power_stat_params[] = {
     82     "cumulative_sleep_time_ms",
     83     "cumulative_total_on_time_ms",
     84     "deep_sleep_enter_counter",
     85     "last_deep_sleep_enter_tstamp_ms"
     86 };
     87 
     88 struct stat_pair wlan_stat_map[] = {
     89     { WLAN_POWER_DEBUG_STATS, "POWER DEBUG STATS", wlan_power_stat_params, ARRAY_SIZE(wlan_power_stat_params) },
     90 };
     91 
     92 static int parse_stats(const char **params, size_t params_size,
     93                        uint64_t *list, FILE *fp) {
     94     ssize_t nread;
     95     size_t len = LINE_SIZE;
     96     char *line;
     97     size_t params_read = 0;
     98     size_t i;
     99 
    100     line = malloc(len);
    101     if (!line) {
    102         ALOGE("%s: no memory to hold line", __func__);
    103         return -ENOMEM;
    104     }
    105 
    106     while ((params_read < params_size) &&
    107         (nread = getline(&line, &len, fp) > 0)) {
    108         char *key = line + strspn(line, " \t");
    109         char *value = strchr(key, ':');
    110         if (!value || (value > (line + len)))
    111             continue;
    112         *value++ = '\0';
    113 
    114         for (i = 0; i < params_size; i++) {
    115             if (!strcmp(key, params[i])) {
    116                 list[i] = strtoull(value, NULL, 0);
    117                 params_read++;
    118                 break;
    119             }
    120         }
    121     }
    122     free(line);
    123 
    124     return 0;
    125 }
    126 
    127 
    128 static int extract_stats(uint64_t *list, char *file,
    129                          struct stat_pair *map, size_t map_size) {
    130     FILE *fp;
    131     ssize_t read;
    132     size_t len = LINE_SIZE;
    133     char *line;
    134     size_t i, stats_read = 0;
    135     int ret = 0;
    136 
    137     fp = fopen(file, "re");
    138     if (fp == NULL) {
    139         ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
    140         return -errno;
    141     }
    142 
    143     line = malloc(len);
    144     if (!line) {
    145         ALOGE("%s: no memory to hold line", __func__);
    146         fclose(fp);
    147         return -ENOMEM;
    148     }
    149 
    150     while ((stats_read < map_size) && (read = getline(&line, &len, fp) != -1)) {
    151         size_t begin = strspn(line, " \t");
    152 
    153         for (i = 0; i < map_size; i++) {
    154             if (!strncmp(line + begin, map[i].label, strlen(map[i].label))) {
    155                 stats_read++;
    156                 break;
    157             }
    158         }
    159 
    160         if (i == map_size)
    161             continue;
    162 
    163         ret = parse_stats(map[i].parameters, map[i].num_parameters,
    164                           &list[map[i].stat * MAX_RPM_PARAMS], fp);
    165         if (ret < 0)
    166             break;
    167     }
    168     free(line);
    169     fclose(fp);
    170 
    171     return ret;
    172 }
    173 
    174 int extract_platform_stats(uint64_t *list) {
    175     return extract_stats(list, RPM_SYSTEM_STAT, rpm_stat_map, ARRAY_SIZE(rpm_stat_map));
    176 }
    177 
    178 int extract_wlan_stats(uint64_t *list) {
    179     return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map));
    180 }
    181 
    182 int get_easel_state(unsigned long *current_state) {
    183     FILE *fp = NULL;
    184     static const size_t EASEL_STATE_LINE_SIZE = 16;
    185     char buffer[EASEL_STATE_LINE_SIZE];
    186     char *parse_end = buffer;
    187     unsigned long state;
    188 
    189     if (current_state == NULL) {
    190         ALOGD("%s: null current_state pointer from caller", __func__);
    191         return -1;
    192     }
    193 
    194     fp = fopen(EASEL_STATE_FILE, "re");
    195     if (fp == NULL) {
    196         ALOGE("%s: failed to open: %s Error = %s", __func__, EASEL_STATE_FILE,
    197                 strerror(errno));
    198         return -errno;
    199     }
    200 
    201     if (fgets(buffer, EASEL_STATE_LINE_SIZE, fp) == NULL) {
    202         fclose(fp);
    203         ALOGE("%s: failed to read: %s", __func__, EASEL_STATE_FILE);
    204         return -1;
    205     }
    206 
    207     fclose(fp);
    208 
    209     parse_end = buffer;
    210     state = strtoul(buffer, &parse_end, 10);
    211     if ((parse_end == buffer) || (state > 2)) {
    212         ALOGE("%s: unrecognized format: %s '%s'", __func__, EASEL_STATE_FILE,
    213                 buffer);
    214         return -1;
    215     }
    216 
    217     *current_state = state;
    218 
    219     return 0;
    220 }
    221 
    222