harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 1 | # Copyright (c) 2017 The Chromium OS 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 | |
harpreet | 16ebb4b | 2017-01-26 13:41:25 -0800 | [diff] [blame] | 5 | import json |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 6 | |
| 7 | from autotest_lib.server.cros import cfm_jmidata_helper_base |
| 8 | |
| 9 | # Start index in the JSON object that contains Audio/Video streams related info. |
| 10 | AV_INDEX = 4 |
| 11 | |
| 12 | SSRC = u'ssrc' |
| 13 | GLOBAL = u'global' |
| 14 | |
| 15 | AUDIO_INPUT = u'audioInputLevel' |
| 16 | AUDIO_OUTPUT = u'audioOutputLevel' |
| 17 | BYTES_RECEIVED = u'bytesReceived' |
| 18 | BYTES_SENT = u'bytesSent' |
| 19 | ADAPTATION_CHANGES = u'googAdaptationChanges' |
| 20 | AVERAGE_ENCODE_TIME = u'googAvgEncodeMs' |
| 21 | BANDWIDTH_LIMITED_RESOLUTION = u'googBandwidthLimitedResolution' |
| 22 | CPU_LIMITED_RESOLUTION = u'googCpuLimitedResolution' |
| 23 | VIDEO_ENCODE_CPU_USAGE = u'googEncodeUsagePercent' |
| 24 | VIDEO_RECEIVED_FRAME_HEIGHT = u'googFrameHeightReceived' |
| 25 | VIDEO_RECEIVED_FRAME_WIDTH = u'googFrameWidthReceived' |
| 26 | FRAMERATE_OUTGOING = u'googFrameRateInput' |
| 27 | FRAMERATE_RECEIVED = u'googFrameRateReceived' |
| 28 | FRAMERATE_SENT = u'googFrameRateSent' |
| 29 | FRAMERATE_DECODED = u'googFrameRateDecoded' |
| 30 | FRAMERATE_OUTPUT = u'googFrameRateOutput' |
| 31 | FRAME_WIDTH_SENT = u'googFrameWidthSent' |
| 32 | FRAME_HEIGHT_SENT = u'googFrameHeightSent' |
| 33 | FRAMES_DECODED = u'framesDecoded' |
| 34 | FRAMES_ENCODED = u'framesEncoded' |
| 35 | VIDEO_PACKETS_LOST = u'packetsLost' |
| 36 | VIDEO_PACKETS_SENT = u'packetsSent' |
| 37 | |
harpreet | 16ebb4b | 2017-01-26 13:41:25 -0800 | [diff] [blame] | 38 | BROWSER_CPU = u'browserCpuUsage' |
| 39 | GPU_CPU = u'gpuCpuUsage' |
| 40 | NUM_PROCESSORS = u'numOfProcessors' |
| 41 | NACL_EFFECTS_CPU = u'pluginCpuUsage' |
| 42 | RENDERER_CPU = u'tabCpuUsage' |
| 43 | TOTAL_CPU = u'totalCpuUsage' |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 44 | |
| 45 | |
| 46 | class JMIDataV3Helper(cfm_jmidata_helper_base.JMIDataHelperBase): |
| 47 | """Helper class for JMI data v3 parsing. This class helps in extracting |
| 48 | relevant JMI data from javascript log. |
| 49 | |
| 50 | The class takes javascript file as input and extracts jmidata elements from |
| 51 | the file that is internally stored as a list. Whenever we need to extract |
| 52 | data i.e. audio received bytes we call a method such as |
| 53 | getAudioReceivedDataList. This method converts each string element in the |
| 54 | internal list to a json object and retrieves the relevant info from it which |
| 55 | is then stored and returned as a list. |
| 56 | """ |
| 57 | |
| 58 | def __init__(self, log_file_content): |
| 59 | super(JMIDataV3Helper, self).__init__(log_file_content, 'jmidatav3') |
| 60 | |
| 61 | def _ExtractAllJMIDataPointsWithKey(self, jmi_type, is_audio, key): |
| 62 | """Extracts all values from the data points with the given key.""" |
| 63 | data_list = [] |
| 64 | for jmi_data_point in self._jmi_list: |
| 65 | json_arr = json.loads(jmi_data_point) |
| 66 | for i in range(AV_INDEX, len(json_arr)): |
| 67 | if json_arr[i] and jmi_type in json_arr[i]: |
| 68 | jmi_obj = json_arr[i][jmi_type] |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 69 | this_is_audio = (AUDIO_INPUT in jmi_obj or |
| 70 | AUDIO_OUTPUT in jmi_obj) |
| 71 | if this_is_audio == is_audio and key in jmi_obj: |
| 72 | if (not isinstance(jmi_obj[key], int) and |
| 73 | (jmi_obj[key] == 'false' or |
| 74 | jmi_obj[key] == 'true')): |
| 75 | jmi_obj[key] = 1 if jmi_obj[key] == 'true' else 0 |
| 76 | data_list.append(jmi_obj[key]) |
harpreet | eb36ffd | 2017-08-07 15:23:06 -0700 | [diff] [blame] | 77 | if not data_list: |
| 78 | data_list = [0] |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 79 | return data_list |
| 80 | |
| 81 | def GetAudioReceivedBytesList(self): |
| 82 | return self._ExtractAllJMIDataPointsWithKey( |
| 83 | jmi_type=SSRC, is_audio=True, key=BYTES_RECEIVED) |
| 84 | |
| 85 | def GetAudioSentBytesList(self): |
| 86 | return self._ExtractAllJMIDataPointsWithKey( |
| 87 | jmi_type=SSRC, is_audio=True, key=BYTES_SENT) |
| 88 | |
| 89 | def GetAudioReceivedEnergyList(self): |
| 90 | return self._ExtractAllJMIDataPointsWithKey( |
| 91 | jmi_type=SSRC, is_audio=True, key=AUDIO_OUTPUT) |
| 92 | |
| 93 | def GetAudioSentEnergyList(self): |
| 94 | return self._ExtractAllJMIDataPointsWithKey( |
| 95 | jmi_type=SSRC, is_audio=True, key=AUDIO_INPUT) |
| 96 | |
| 97 | def GetVideoSentBytesList(self): |
| 98 | return self._ExtractAllJMIDataPointsWithKey( |
| 99 | jmi_type=SSRC, is_audio=False, key=BYTES_SENT) |
| 100 | |
| 101 | def GetVideoReceivedBytesList(self): |
| 102 | return self._ExtractAllJMIDataPointsWithKey( |
| 103 | jmi_type=SSRC, is_audio=False, key=BYTES_RECEIVED) |
| 104 | |
| 105 | def GetVideoIncomingFramerateReceivedList(self): |
| 106 | return self._ExtractAllJMIDataPointsWithKey( |
| 107 | jmi_type=SSRC, is_audio=False, key=FRAMERATE_RECEIVED) |
| 108 | |
| 109 | def GetVideoOutgoingFramerateSentList(self): |
| 110 | return self._ExtractAllJMIDataPointsWithKey( |
| 111 | jmi_type=SSRC, is_audio=False, key=FRAMERATE_SENT) |
| 112 | |
| 113 | def GetVideoIncomingFramerateDecodedList(self): |
| 114 | return self._ExtractAllJMIDataPointsWithKey( |
| 115 | jmi_type=SSRC, is_audio=False, key=FRAMERATE_DECODED) |
| 116 | |
| 117 | def GetVideoIncomingFramerateList(self): |
| 118 | return self._ExtractAllJMIDataPointsWithKey( |
| 119 | jmi_type=SSRC, is_audio=False, key=FRAMERATE_OUTPUT) |
| 120 | |
| 121 | def GetVideoSentFrameWidthList(self): |
| 122 | return self._ExtractAllJMIDataPointsWithKey( |
| 123 | jmi_type=SSRC, is_audio=False, key=FRAME_WIDTH_SENT) |
| 124 | |
| 125 | def GetVideoSentFrameHeightList(self): |
| 126 | return self._ExtractAllJMIDataPointsWithKey( |
| 127 | jmi_type=SSRC, is_audio=False, key=FRAME_HEIGHT_SENT) |
| 128 | |
| 129 | def GetCPULimitedResolutionList(self): |
| 130 | return self._ExtractAllJMIDataPointsWithKey( |
| 131 | jmi_type=SSRC, is_audio=False, key=CPU_LIMITED_RESOLUTION) |
| 132 | |
| 133 | def GetVideoPacketsSentList(self): |
| 134 | return self._ExtractAllJMIDataPointsWithKey( |
| 135 | jmi_type=SSRC, is_audio=False, key=VIDEO_PACKETS_SENT) |
| 136 | |
| 137 | def GetVideoPacketsLostList(self): |
| 138 | return self._ExtractAllJMIDataPointsWithKey( |
| 139 | jmi_type=SSRC, is_audio=False, key=VIDEO_PACKETS_LOST) |
| 140 | |
| 141 | def GetVideoIncomingFramesDecodedList(self): |
| 142 | return self._ExtractAllJMIDataPointsWithKey( |
| 143 | jmi_type=SSRC, is_audio=False, key=FRAMES_DECODED) |
| 144 | |
| 145 | def GetVideoOutgoingFramesEncodedList(self): |
| 146 | return self._ExtractAllJMIDataPointsWithKey( |
| 147 | jmi_type=SSRC, is_audio=False, key=FRAMES_ENCODED) |
| 148 | |
| 149 | def GetVideoAdaptationChangeList(self): |
| 150 | return self._ExtractAllJMIDataPointsWithKey( |
| 151 | jmi_type=SSRC, is_audio=False, key=ADAPTATION_CHANGES) |
| 152 | |
| 153 | def GetVideoEncodeTimeList(self): |
| 154 | return self._ExtractAllJMIDataPointsWithKey( |
| 155 | jmi_type=SSRC, is_audio=False, key=AVERAGE_ENCODE_TIME) |
| 156 | |
| 157 | def GetBandwidthLimitedResolutionList(self): |
| 158 | return self._ExtractAllJMIDataPointsWithKey( |
| 159 | jmi_type=SSRC, is_audio=False, key=BANDWIDTH_LIMITED_RESOLUTION) |
| 160 | |
| 161 | def GetVideoReceivedFrameHeightList(self): |
| 162 | return self._ExtractAllJMIDataPointsWithKey( |
| 163 | jmi_type=SSRC, is_audio=False, key=VIDEO_RECEIVED_FRAME_HEIGHT) |
| 164 | |
| 165 | def GetVideoOutgoingFramerateInputList(self): |
| 166 | return self._ExtractAllJMIDataPointsWithKey( |
| 167 | jmi_type=SSRC, is_audio=False, key=FRAMERATE_OUTGOING) |
| 168 | |
| 169 | def GetVideoReceivedFrameWidthList(self): |
| 170 | return self._ExtractAllJMIDataPointsWithKey( |
| 171 | jmi_type=SSRC, is_audio=False, key=VIDEO_RECEIVED_FRAME_WIDTH) |
| 172 | |
| 173 | def GetVideoEncodeCpuUsagePercentList(self): |
| 174 | return self._ExtractAllJMIDataPointsWithKey( |
| 175 | jmi_type=SSRC, is_audio=False, key=VIDEO_ENCODE_CPU_USAGE) |
| 176 | |
| 177 | def GetNumberOfActiveIncomingVideoStreams(self): |
| 178 | """Retrieve number of active incoming video streams.""" |
| 179 | if not self._jmi_list: |
| 180 | # JMI data hasn't started populating yet. |
| 181 | return 0 |
| 182 | |
| 183 | num_video_streams = [] |
| 184 | |
| 185 | # If JMI data has started getting populated and has video stream data. |
| 186 | for jmi_data_point in self._jmi_list: |
| 187 | json_arr = json.loads(jmi_data_point) |
| 188 | video_streams = 0 |
| 189 | for i in range(AV_INDEX, len(json_arr)): |
| 190 | if json_arr[i] and SSRC in json_arr[i]: |
| 191 | ssrc_obj = json_arr[i][SSRC] |
| 192 | is_audio = ('audioInputLevel' in ssrc_obj or |
| 193 | 'audioOutputLevel' in ssrc_obj) |
| 194 | is_incoming = 'bytesReceived' in ssrc_obj |
| 195 | frame_rate_received = 'googFrameRateReceived' in ssrc_obj |
| 196 | if ssrc_obj['mediaType'] == 'video' and \ |
| 197 | frame_rate_received: |
| 198 | frame_rate = ssrc_obj['googFrameRateReceived'] |
| 199 | if (is_incoming and not is_audio) and \ |
| 200 | frame_rate != 0: |
| 201 | video_streams += 1 |
| 202 | num_video_streams.append(video_streams) |
harpreet | eb36ffd | 2017-08-07 15:23:06 -0700 | [diff] [blame] | 203 | if not num_video_streams: |
| 204 | num_video_streams = [0] |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 205 | return num_video_streams |
| 206 | |
| 207 | def GetCpuUsageList(self, cpu_type): |
| 208 | """Retrieves cpu usage data from JMI data. |
| 209 | |
harpreet | 16ebb4b | 2017-01-26 13:41:25 -0800 | [diff] [blame] | 210 | @param cpu_type: Cpu usage type. |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 211 | @returns List containing CPU usage data. |
| 212 | """ |
| 213 | data_list = [] |
| 214 | for jmi_data_point in self._jmi_list: |
| 215 | json_arr = json.loads(jmi_data_point) |
| 216 | for i in range(AV_INDEX, len(json_arr)): |
| 217 | if json_arr[i] and GLOBAL in json_arr[i]: |
| 218 | global_obj = json_arr[i][GLOBAL] |
| 219 | # Some values in JMIDataV3 are set to 'null'. |
harpreet | 16ebb4b | 2017-01-26 13:41:25 -0800 | [diff] [blame] | 220 | if cpu_type == u'numOfProcessors': |
| 221 | return global_obj[cpu_type] |
| 222 | elif (cpu_type in global_obj and |
| 223 | self.IsFloat(global_obj[cpu_type])): |
| 224 | data_list.append(float(global_obj[cpu_type])) |
harpreet | b527a0f | 2017-07-14 15:24:44 -0700 | [diff] [blame] | 225 | if not data_list: |
| 226 | data_list = [0] |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 227 | return data_list |
| 228 | |
harpreet | 16ebb4b | 2017-01-26 13:41:25 -0800 | [diff] [blame] | 229 | def GetNumOfProcessors(self): |
| 230 | return self.GetCpuUsageList(NUM_PROCESSORS) |
| 231 | |
| 232 | def GetTotalCpuPercentage(self): |
| 233 | return self.GetCpuUsageList(TOTAL_CPU) |
| 234 | |
| 235 | def GetBrowserCpuPercentage(self): |
| 236 | return self.GetCpuUsageList(BROWSER_CPU) |
| 237 | |
| 238 | def GetGpuCpuPercentage(self): |
| 239 | return self.GetCpuUsageList(GPU_CPU) |
| 240 | |
| 241 | def GetNaclEffectsCpuPercentage(self): |
| 242 | return self.GetCpuUsageList(NACL_EFFECTS_CPU) |
| 243 | |
| 244 | def GetRendererCpuPercentage(self): |
| 245 | return self.GetCpuUsageList(RENDERER_CPU) |
harpreet | 6ffd1e4 | 2017-01-24 18:24:36 -0800 | [diff] [blame] | 246 | |
| 247 | def IsFloat(self, value): |
| 248 | try: |
| 249 | float(value) |
| 250 | return True |
| 251 | except TypeError: |
| 252 | return False |