diff --git a/energy_model/analyze.py b/energy_model/analyze.py new file mode 100644 index 0000000..0d03d93 --- /dev/null +++ b/energy_model/analyze.py @@ -0,0 +1,94 @@ +import sys +import os + +sys.path.append("modules") +try: + from model import * +except: + raise + + +def read_cpu_log(filepath, startT=None, endT=None, isDelta=True): + contents = [] + results = [] + deltas = [] + skipFirstTime = True + with open(filepath, 'rU') as f: + contents = f.readlines() + for line in contents: + tmp = line.rstrip().split(' ') + if len(tmp) < 3: + print "something is wrong at splitting the line for cpu_log" + sys.exit(-1) + timestamp = int(tmp[0]) # ms + if (startT is not None and timestamp < startT) \ + or (endT is not None and timestamp > endT): + continue + cpu_total_idle = int(tmp[1]) + cpu_total_used = int(tmp[2]) + cpu_per_core = [] + if isDelta and not skipFirstTime: + delta_t = timestamp - results[-1][0] + delta_total_idle = cpu_total_idle - results[-1][1] + delta_total_used = cpu_total_used - results[-1][2] + delta_per_core = [] + for i in xrange(3, len(tmp), 3): + cpu_i_idle = int(tmp[i]) + cpu_i_used = int(tmp[i + 1]) + cpu_i_freq = int(tmp[i + 2]) + cpu_per_core.append([cpu_i_idle, cpu_i_used, cpu_i_freq]) + if isDelta and len(results) != 0: + delta_per_core.append( + [cpu_i_idle - results[-1][3][i / 3 - 1][0], + cpu_i_used - results[-1][3][i / 3 - 1][1], + cpu_i_freq]) + if isDelta and not skipFirstTime: + deltas.append( + [delta_t, delta_total_idle, delta_total_used, delta_per_core]) + results.append( + [timestamp, cpu_total_idle, cpu_total_used, cpu_per_core]) + skipFirstTime = False + if isDelta: + return deltas, results + return results + + +def get_cpu_energy(results, model): + energy = 0 + if len(results) < 1: + return energy + num_of_cores = len(results[0][3]) + for result in results: + freqs = [0 for i in xrange(num_of_cores)] + utils = [0 for i in xrange(num_of_cores + 1)] + for i in xrange(num_of_cores): + if result[3][i][0] + result[3][i][1] > 0: + utils[i] = 1.0 * \ + result[3][i][1] / (result[3][i][0] + result[3][i][1]) + else: + utils[i] = 0 + freqs[i] = result[3][i][-1] + # calculate total + if result[1] + result[2] > 0: + utils[-1] = 1.0 * result[1] / (result[1] + result[2]) + else: + utils[-1] = 0 + energy += model.get_cpu_energy(result[0] / 1000.0, freqs, utils[:-1]) + + +if __name__ == "__main__": + # cpuFile = sys.argv[1] + cpuFile = "1485560673559.cpu" + if not os.path.isfile(cpuFile): + print ".....!" + sys.exit(-1) + deltas, results = read_cpu_log(cpuFile, isDelta=True) + myObj = Model(isDebuging=True, unit="mW") + # myObj.load(sys.argv[1]) + myObj.load("shamu") + get_cpu_energy(deltas, myObj) + # for i in xrange(1, len(myObj.freqs)): + # print myObj.freqs[i] - myObj.freqs[i-1] + # myObj.get_wifi_tail_energy(1) + # myObj.get_wifi_active_energy(1, -60, isTX=False) + # myObj.get_cpu_energy(1, [1036800, 422400], [0, 1]) \ No newline at end of file diff --git a/energy_model/modules/model.py b/energy_model/modules/model.py index 32f53d6..27dc340 100644 --- a/energy_model/modules/model.py +++ b/energy_model/modules/model.py @@ -15,7 +15,7 @@ class Model(): The energy model module ''' - def __init__(self, isDebuging=False, use_uAh=False): + def __init__(self, isDebuging=False, unit="mW"): self.freqs = [] self.cpu_single_core = {} self.cpu_multi_core = {} @@ -38,14 +38,12 @@ class Model(): ''' self.DEBUG = isDebuging self.logger = None + self.voltage = 1 + self.unit = unit if isDebuging: self.logger = EmptyLogger("Model", printout=True) - if use_uAh: - self._ratio_uAh_over_mAs = 5 / 18.0 - else: - self._ratio_uAh_over_mAs = 1.0 - def load(self, productname, dir="../models/"): + def load(self, productname, dir="./models/"): self.voltage = getVoltage(productname) filepath = "{0}/{1}.xml".format(dir, productname) if not os.path.isfile(filepath): @@ -142,10 +140,30 @@ class Model(): # if self.DEBUG: # self.logger.debug(self.freqs) + def get_final_energy(self, current, time): + ''' + @param current: mA + @param time: s + @return defined energy with unit conversion + ''' + if 'W' in self.unit: + tmp = current * self.voltage + elif 'J' in self.unit: + tmp = current * self.voltage * time + elif 'A' in self.unit: + tmp = current + if 'm' == self.unit[0]: + if 'h' == self.unit[-1]: + return tmp * time / 3600.0 + return tmp + else: + return tmp / 1000.0 + def get_cpu_energy(self, time_diff, freq, util): ''' @param freq: list of cpu frequencies @param util: list of cpu utilization + @return: energy in desired unit, default is mW ''' if len(freq) != len(util) or len(freq) < 1: self.logger.error("freq & util have different length!") @@ -153,29 +171,31 @@ class Model(): current = 0 if len(freq) > 1: db = self.cpu_multi_core - for i in xrange(len(freq)): - if freq[i] <= 0 or freq[i] not in db[i]: - self.logger.error("freq outlier: {0}".format(freq[i])) - self.logger.debug(db[i]) - continue - active_current = db[i][freq[i]][0] - idle_current = db[i][freq[i]][1] - current += util[i] * (active_current - idle_current) + \ - idle_current else: db = self.cpu_single_core - if freq[0] <= 0 or freq[0] not in db[0]: - self.logger.error("freq outlier: {0}".format(f)) - self.logger.debug(db[i]) - else: - active_current = db[0][freq[0]][0] - idle_current = db[0][freq[0]][1] - current = util[0] * (active_current - idle_current) + \ - idle_current + for i in xrange(len(freq)): + if freq[i] <= 0: + continue + if freq[i] not in db[i]: + minDiff = float("inf") + myJ = None + for j in xrange(len(self.freqs)): + tmp = abs(self.freqs[j] - freq[i]) + if tmp < minDiff: + minDiff = tmp + myJ = j + closestFreq = self.freqs[j] + self.logger.debug("Freq outlier: {0}. ".format(freq[i]) + + "Use {0} instead.".format(closestFreq)) + freq[i] = closestFreq + active_current = db[i][freq[i]][0] + idle_current = db[i][freq[i]][1] + current += util[i] * active_current + (1 - util[i]) * idle_current # derive energy - energy = current * time_diff * self._ratio_uAh_over_mAs + energy = self.get_final_energy(current, time_diff) if self.DEBUG: - self.logger.debug("cpu_energy: {0:.4f}".format(energy)) + self.logger.debug( + "cpu_energy: {0:.4f}{1}".format(energy, self.unit)) return energy def get_lte_prom_energy(self, time_diff, rssi, isTX=True): @@ -215,24 +235,19 @@ class Model(): self.logger.error("Current {0} is nothing!".format(current)) sys.exit(-1) # derive energy - energy = current * time_diff * self._ratio_uAh_over_mAs + energy = self.get_final_energy(current, time_diff) if self.DEBUG: - self.logger.debug("wifi_active_energy: {0:.4f}".format(energy)) + self.logger.debug( + "wifi_active_energy: {0:.4f}{1}".format(energy, self.unit)) return energy def get_wifi_tail_energy(self, time_diff): - energy = (time_diff * self.net_wifi['tail']['0'][1] * - self._ratio_uAh_over_mAs) + current = self.net_wifi['tail']['0'][1] + energy = self.get_final_energy(current, time_diff) if self.DEBUG: - self.logger.debug("wifi_tail_energy: {0:.4f}".format(energy)) + self.logger.debug( + "wifi_active_energy: {0:.4f}{1}".format(energy, self.unit)) return energy if __name__ == "__main__": print "Usage: from model import *" - # debugging.. - myObj = Model(isDebuging=True) - # myObj.load(sys.argv[1]) - myObj.load("shamu") - myObj.get_wifi_tail_energy(1) - myObj.get_wifi_active_energy(1, -60, isTX=False) - myObj.get_cpu_energy(1, [1036800, 422400], [0, 1])