1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import unittest
6
7from telemetry.core.platform.power_monitor import cros_power_monitor
8
9
10class CrosPowerMonitorMonitorTest(unittest.TestCase):
11  initial_power = ('''Device: Line Power
12  path:                    /sys/class/power_supply/AC
13  online:                  no
14  type:                    Mains
15  enum type:               Disconnected
16  model name:
17  voltage (V):             0
18  current (A):             0
19Device: Battery
20  path:                    /sys/class/power_supply/BAT0
21  vendor:                  SANYO
22  model name:              AP13J3K
23  serial number:           0061
24  state:                   Discharging
25  voltage (V):             11.816
26  energy (Wh):             31.8262
27  energy rate (W):         12.7849
28  current (A):             1.082
29  charge (Ah):             2.829
30  full charge (Ah):        4.03
31  full charge design (Ah): 4.03
32  percentage:              70.1985
33  display percentage:      73.9874
34  technology:              Li-ion''')
35  final_power = ('''Device: Line Power
36  path:                    /sys/class/power_supply/AC
37  online:                  yes
38  type:                    Mains
39  enum type:               Disconnected
40  model name:
41  voltage (V):             0
42  current (A):             0
43Device: Battery
44  path:                    /sys/class/power_supply/BAT0
45  vendor:                  SANYO
46  model name:              AP13J3K
47  serial number:           0061
48  state:                   Discharging
49  voltage (V):             12.238
50  energy (Wh):             31.8262
51  energy rate (W):         12.7993
52  current (A):             1.082
53  charge (Ah):             2.827
54  full charge (Ah):        4.03
55  full charge design (Ah): 4.03
56  percentage:              70.1985
57  display percentage:      73.9874
58  technology:              Li-ion''')
59  expected_parsing_power = {
60    'Line Power': {
61      'path': '/sys/class/power_supply/AC',
62      'online': 'no',
63      'type': 'Mains',
64      'enum type': 'Disconnected',
65      'voltage': '0',
66      'current': '0'
67    },
68    'Battery': {
69      'path': '/sys/class/power_supply/BAT0',
70      'vendor': 'SANYO',
71      'model name': 'AP13J3K',
72      'serial number': '0061',
73      'state': 'Discharging',
74      'voltage': '11.816',
75      'energy': '31.8262',
76      'energy rate': '12.7849',
77      'current': '1.082',
78      'charge': '2.829',
79      'full charge': '4.03',
80      'full charge design': '4.03',
81      'percentage': '70.1985',
82      'display percentage': '73.9874',
83      'technology': 'Li-ion'
84    }
85  }
86  expected_power = {
87    'energy_consumption_mwh': 2558.42,
88    'power_samples_mw': [12784.9, 12799.3],
89    'component_utilization': {
90      'battery': {
91        'charge_full': 4.03,
92        'charge_full_design': 4.03,
93        'charge_now': 2.827,
94        'current_now': 1.082,
95        'energy': 31.8262,
96        'energy_rate': 12.7993,
97        'voltage_now': 12.238
98      }
99    }
100  }
101  expected_cpu = {
102    'whole_package': {
103      'frequency_percent': {
104        1700000000: 3.29254111574526,
105        1600000000: 0.0,
106        1500000000: 0.0,
107        1400000000: 0.15926805099535601,
108        1300000000: 0.47124116307273645,
109        1200000000: 0.818756100807525,
110        1100000000: 1.099381692400982,
111        1000000000: 2.5942528544384302,
112        900000000: 5.68661122326737,
113        800000000: 3.850545467654628,
114        700000000: 2.409691872245393,
115        600000000: 1.4693702487650486,
116        500000000: 2.4623575553879373,
117        400000000: 2.672038150383057,
118        300000000: 3.415770495015825,
119        200000000: 69.59817400982045
120      },
121      'cstate_residency_percent': {
122        'C0': 83.67623835616438535,
123        'C1': 0.2698609589041096,
124        'C2': 0.2780191780821918,
125        'C3': 15.77588150684931505
126      }
127    },
128    'cpu0': {
129      'frequency_percent': {
130        1700000000: 4.113700564971752,
131        1600000000: 0.0,
132        1500000000: 0.0,
133        1400000000: 0.1765536723163842,
134        1300000000: 0.4943502824858757,
135        1200000000: 0.7944915254237288,
136        1100000000: 1.2226341807909604,
137        1000000000: 3.0632062146892656,
138        900000000: 5.680614406779661,
139        800000000: 3.6679025423728815,
140        700000000: 2.379060734463277,
141        600000000: 1.4124293785310735,
142        500000000: 2.599752824858757,
143        400000000: 3.0102401129943503,
144        300000000: 3.650247175141243,
145        200000000: 67.73481638418079
146      },
147      'cstate_residency_percent': {
148        'C0': 76.76226164383562,
149        'C1': 0.3189164383561644,
150        'C2': 0.4544301369863014,
151        'C3': 22.4643917808219178
152      }
153    },
154    'cpu1': {
155      'frequency_percent': {
156        1700000000: 2.4713816665187682,
157        1600000000: 0.0,
158        1500000000: 0.0,
159        1400000000: 0.1419824296743278,
160        1300000000: 0.44813204365959713,
161        1200000000: 0.8430206761913214,
162        1100000000: 0.9761292040110037,
163        1000000000: 2.1252994941875945,
164        900000000: 5.69260803975508,
165        800000000: 4.033188392936374,
166        700000000: 2.4403230100275093,
167        600000000: 1.526311118999024,
168        500000000: 2.3249622859171177,
169        400000000: 2.3338361877717633,
170        300000000: 3.1812938148904073,
171        200000000: 71.46153163546012
172      },
173      'cstate_residency_percent': {
174        'C0': 90.5902150684931507,
175        'C1': 0.2208054794520548,
176        'C2': 0.1016082191780822,
177        'C3': 9.0873712328767123
178      }
179    }
180  }
181  def testParsePowerSupplyInfo(self):
182    result = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
183        self.initial_power)
184    self.assertDictEqual(result, self.expected_parsing_power)
185
186  def testParsePower(self):
187    results = cros_power_monitor.CrosPowerMonitor.ParsePower(
188        self.initial_power, self.final_power, 0.2)
189    for value in results['component_utilization']['battery']:
190      self.assertAlmostEqual(
191          results['component_utilization']['battery'][value],
192          self.expected_power['component_utilization']['battery'][value])
193    self.assertAlmostEqual(results['energy_consumption_mwh'],
194                           self.expected_power['energy_consumption_mwh'])
195    self.assertAlmostEqual(results['power_samples_mw'][0],
196                           self.expected_power['power_samples_mw'][0])
197    self.assertAlmostEqual(results['power_samples_mw'][1],
198                           self.expected_power['power_samples_mw'][1])
199
200  def testSplitSample(self):
201    sample = self.initial_power + '\n1408739546\n'
202    power, time = cros_power_monitor.CrosPowerMonitor.SplitSample(sample)
203    self.assertEqual(power, self.initial_power)
204    self.assertEqual(time, 1408739546)
205
206  def testCombineResults(self):
207    result = cros_power_monitor.CrosPowerMonitor.CombineResults(
208        self.expected_cpu, self.expected_power)
209    comp_util = result['component_utilization']
210    # Test power values.
211    self.assertEqual(result['energy_consumption_mwh'],
212                     self.expected_power['energy_consumption_mwh'])
213    self.assertEqual(result['power_samples_mw'],
214                     self.expected_power['power_samples_mw'])
215    self.assertEqual(comp_util['battery'],
216                     self.expected_power['component_utilization']['battery'])
217    # Test frequency values.
218    self.assertDictEqual(
219        comp_util['whole_package']['frequency_percent'],
220        self.expected_cpu['whole_package']['frequency_percent'])
221    self.assertDictEqual(
222        comp_util['cpu0']['frequency_percent'],
223        self.expected_cpu['cpu0']['frequency_percent'])
224    self.assertDictEqual(
225        comp_util['cpu1']['frequency_percent'],
226        self.expected_cpu['cpu1']['frequency_percent'])
227    # Test c-state residency values.
228    self.assertDictEqual(
229        comp_util['whole_package']['cstate_residency_percent'],
230        self.expected_cpu['whole_package']['cstate_residency_percent'])
231    self.assertDictEqual(
232        comp_util['cpu0']['cstate_residency_percent'],
233        self.expected_cpu['cpu0']['cstate_residency_percent'])
234    self.assertDictEqual(
235        comp_util['cpu1']['cstate_residency_percent'],
236        self.expected_cpu['cpu1']['cstate_residency_percent'])
237
238  def testCanMonitorPower(self):
239    # TODO(tmandel): Add a test here where the device cannot monitor power.
240    initial_status = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
241        self.initial_power)
242    final_status = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
243        self.final_power)
244    self.assertTrue(cros_power_monitor.CrosPowerMonitor.IsOnBatteryPower(
245        initial_status, 'peppy'))
246    self.assertTrue(cros_power_monitor.CrosPowerMonitor.IsOnBatteryPower(
247        final_status, 'butterfly'))
248