1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ddmlib.log; 18 19 import com.android.ddmlib.log.EventValueDescription.ValueType; 20 import com.android.ddmlib.log.LogReceiver.LogEntry; 21 22 /** 23 * Custom Event Container for the Gc event since this event doesn't simply output data in 24 * int or long format, but encodes several values on 4 longs. 25 * <p/> 26 * The array of {@link EventValueDescription}s parsed from the "event-log-tags" file must 27 * be ignored, and instead, the array returned from {@link #getValueDescriptions()} must be used. 28 */ 29 final class GcEventContainer extends EventContainer { 30 31 public final static int GC_EVENT_TAG = 20001; 32 33 private String processId; 34 private long gcTime; 35 private long bytesFreed; 36 private long objectsFreed; 37 private long actualSize; 38 private long allowedSize; 39 private long softLimit; 40 private long objectsAllocated; 41 private long bytesAllocated; 42 private long zActualSize; 43 private long zAllowedSize; 44 private long zObjectsAllocated; 45 private long zBytesAllocated; 46 private long dlmallocFootprint; 47 private long mallinfoTotalAllocatedSpace; 48 private long externalLimit; 49 private long externalBytesAllocated; 50 GcEventContainer(LogEntry entry, int tag, Object data)51 GcEventContainer(LogEntry entry, int tag, Object data) { 52 super(entry, tag, data); 53 init(data); 54 } 55 GcEventContainer(int tag, int pid, int tid, int sec, int nsec, Object data)56 GcEventContainer(int tag, int pid, int tid, int sec, int nsec, Object data) { 57 super(tag, pid, tid, sec, nsec, data); 58 init(data); 59 } 60 61 /** 62 * @param data 63 */ init(Object data)64 private void init(Object data) { 65 if (data instanceof Object[]) { 66 Object[] values = (Object[])data; 67 for (int i = 0; i < values.length; i++) { 68 if (values[i] instanceof Long) { 69 parseDvmHeapInfo((Long)values[i], i); 70 } 71 } 72 } 73 } 74 75 @Override getType()76 public EventValueType getType() { 77 return EventValueType.LIST; 78 } 79 80 @Override testValue(int index, Object value, CompareMethod compareMethod)81 public boolean testValue(int index, Object value, CompareMethod compareMethod) 82 throws InvalidTypeException { 83 // do a quick easy check on the type. 84 if (index == 0) { 85 if ((value instanceof String) == false) { 86 throw new InvalidTypeException(); 87 } 88 } else if ((value instanceof Long) == false) { 89 throw new InvalidTypeException(); 90 } 91 92 switch (compareMethod) { 93 case EQUAL_TO: 94 if (index == 0) { 95 return processId.equals(value); 96 } else { 97 return getValueAsLong(index) == ((Long)value).longValue(); 98 } 99 case LESSER_THAN: 100 return getValueAsLong(index) <= ((Long)value).longValue(); 101 case LESSER_THAN_STRICT: 102 return getValueAsLong(index) < ((Long)value).longValue(); 103 case GREATER_THAN: 104 return getValueAsLong(index) >= ((Long)value).longValue(); 105 case GREATER_THAN_STRICT: 106 return getValueAsLong(index) > ((Long)value).longValue(); 107 case BIT_CHECK: 108 return (getValueAsLong(index) & ((Long)value).longValue()) != 0; 109 } 110 111 throw new ArrayIndexOutOfBoundsException(); 112 } 113 114 @Override getValue(int valueIndex)115 public Object getValue(int valueIndex) { 116 if (valueIndex == 0) { 117 return processId; 118 } 119 120 try { 121 return new Long(getValueAsLong(valueIndex)); 122 } catch (InvalidTypeException e) { 123 // this would only happened if valueIndex was 0, which we test above. 124 } 125 126 return null; 127 } 128 129 @Override getValueAsDouble(int valueIndex)130 public double getValueAsDouble(int valueIndex) throws InvalidTypeException { 131 return (double)getValueAsLong(valueIndex); 132 } 133 134 @Override getValueAsString(int valueIndex)135 public String getValueAsString(int valueIndex) { 136 switch (valueIndex) { 137 case 0: 138 return processId; 139 default: 140 try { 141 return Long.toString(getValueAsLong(valueIndex)); 142 } catch (InvalidTypeException e) { 143 // we shouldn't stop there since we test, in this method first. 144 } 145 } 146 147 throw new ArrayIndexOutOfBoundsException(); 148 } 149 150 /** 151 * Returns a custom array of {@link EventValueDescription} since the actual content of this 152 * event (list of (long, long) does not match the values encoded into those longs. 153 */ getValueDescriptions()154 static EventValueDescription[] getValueDescriptions() { 155 try { 156 return new EventValueDescription[] { 157 new EventValueDescription("Process Name", EventValueType.STRING), 158 new EventValueDescription("GC Time", EventValueType.LONG, 159 ValueType.MILLISECONDS), 160 new EventValueDescription("Freed Objects", EventValueType.LONG, 161 ValueType.OBJECTS), 162 new EventValueDescription("Freed Bytes", EventValueType.LONG, ValueType.BYTES), 163 new EventValueDescription("Soft Limit", EventValueType.LONG, ValueType.BYTES), 164 new EventValueDescription("Actual Size (aggregate)", EventValueType.LONG, 165 ValueType.BYTES), 166 new EventValueDescription("Allowed Size (aggregate)", EventValueType.LONG, 167 ValueType.BYTES), 168 new EventValueDescription("Allocated Objects (aggregate)", 169 EventValueType.LONG, ValueType.OBJECTS), 170 new EventValueDescription("Allocated Bytes (aggregate)", EventValueType.LONG, 171 ValueType.BYTES), 172 new EventValueDescription("Actual Size", EventValueType.LONG, ValueType.BYTES), 173 new EventValueDescription("Allowed Size", EventValueType.LONG, ValueType.BYTES), 174 new EventValueDescription("Allocated Objects", EventValueType.LONG, 175 ValueType.OBJECTS), 176 new EventValueDescription("Allocated Bytes", EventValueType.LONG, 177 ValueType.BYTES), 178 new EventValueDescription("Actual Size (zygote)", EventValueType.LONG, 179 ValueType.BYTES), 180 new EventValueDescription("Allowed Size (zygote)", EventValueType.LONG, 181 ValueType.BYTES), 182 new EventValueDescription("Allocated Objects (zygote)", EventValueType.LONG, 183 ValueType.OBJECTS), 184 new EventValueDescription("Allocated Bytes (zygote)", EventValueType.LONG, 185 ValueType.BYTES), 186 new EventValueDescription("External Allocation Limit", EventValueType.LONG, 187 ValueType.BYTES), 188 new EventValueDescription("External Bytes Allocated", EventValueType.LONG, 189 ValueType.BYTES), 190 new EventValueDescription("dlmalloc Footprint", EventValueType.LONG, 191 ValueType.BYTES), 192 new EventValueDescription("Malloc Info: Total Allocated Space", 193 EventValueType.LONG, ValueType.BYTES), 194 }; 195 } catch (InvalidValueTypeException e) { 196 // this shouldn't happen since we control manual the EventValueType and the ValueType 197 // values. For development purpose, we assert if this happens. 198 assert false; 199 } 200 201 // this shouldn't happen, but the compiler complains otherwise. 202 return null; 203 } 204 parseDvmHeapInfo(long data, int index)205 private void parseDvmHeapInfo(long data, int index) { 206 switch (index) { 207 case 0: 208 // [63 ] Must be zero 209 // [62-24] ASCII process identifier 210 // [23-12] GC time in ms 211 // [11- 0] Bytes freed 212 213 gcTime = float12ToInt((int)((data >> 12) & 0xFFFL)); 214 bytesFreed = float12ToInt((int)(data & 0xFFFL)); 215 216 // convert the long into an array, in the proper order so that we can convert the 217 // first 5 char into a string. 218 byte[] dataArray = new byte[8]; 219 put64bitsToArray(data, dataArray, 0); 220 221 // get the name from the string 222 processId = new String(dataArray, 0, 5); 223 break; 224 case 1: 225 // [63-62] 10 226 // [61-60] Reserved; must be zero 227 // [59-48] Objects freed 228 // [47-36] Actual size (current footprint) 229 // [35-24] Allowed size (current hard max) 230 // [23-12] Objects allocated 231 // [11- 0] Bytes allocated 232 objectsFreed = float12ToInt((int)((data >> 48) & 0xFFFL)); 233 actualSize = float12ToInt((int)((data >> 36) & 0xFFFL)); 234 allowedSize = float12ToInt((int)((data >> 24) & 0xFFFL)); 235 objectsAllocated = float12ToInt((int)((data >> 12) & 0xFFFL)); 236 bytesAllocated = float12ToInt((int)(data & 0xFFFL)); 237 break; 238 case 2: 239 // [63-62] 11 240 // [61-60] Reserved; must be zero 241 // [59-48] Soft limit (current soft max) 242 // [47-36] Actual size (current footprint) 243 // [35-24] Allowed size (current hard max) 244 // [23-12] Objects allocated 245 // [11- 0] Bytes allocated 246 softLimit = float12ToInt((int)((data >> 48) & 0xFFFL)); 247 zActualSize = float12ToInt((int)((data >> 36) & 0xFFFL)); 248 zAllowedSize = float12ToInt((int)((data >> 24) & 0xFFFL)); 249 zObjectsAllocated = float12ToInt((int)((data >> 12) & 0xFFFL)); 250 zBytesAllocated = float12ToInt((int)(data & 0xFFFL)); 251 break; 252 case 3: 253 // [63-48] Reserved; must be zero 254 // [47-36] dlmallocFootprint 255 // [35-24] mallinfo: total allocated space 256 // [23-12] External byte limit 257 // [11- 0] External bytes allocated 258 dlmallocFootprint = float12ToInt((int)((data >> 36) & 0xFFFL)); 259 mallinfoTotalAllocatedSpace = float12ToInt((int)((data >> 24) & 0xFFFL)); 260 externalLimit = float12ToInt((int)((data >> 12) & 0xFFFL)); 261 externalBytesAllocated = float12ToInt((int)(data & 0xFFFL)); 262 break; 263 default: 264 break; 265 } 266 } 267 268 /** 269 * Converts a 12 bit float representation into an unsigned int (returned as a long) 270 * @param f12 271 */ float12ToInt(int f12)272 private static long float12ToInt(int f12) { 273 return (f12 & 0x1FF) << ((f12 >>> 9) * 4); 274 } 275 276 /** 277 * puts an unsigned value in an array. 278 * @param value The value to put. 279 * @param dest the destination array 280 * @param offset the offset in the array where to put the value. 281 * Array length must be at least offset + 8 282 */ put64bitsToArray(long value, byte[] dest, int offset)283 private static void put64bitsToArray(long value, byte[] dest, int offset) { 284 dest[offset + 7] = (byte)(value & 0x00000000000000FFL); 285 dest[offset + 6] = (byte)((value & 0x000000000000FF00L) >> 8); 286 dest[offset + 5] = (byte)((value & 0x0000000000FF0000L) >> 16); 287 dest[offset + 4] = (byte)((value & 0x00000000FF000000L) >> 24); 288 dest[offset + 3] = (byte)((value & 0x000000FF00000000L) >> 32); 289 dest[offset + 2] = (byte)((value & 0x0000FF0000000000L) >> 40); 290 dest[offset + 1] = (byte)((value & 0x00FF000000000000L) >> 48); 291 dest[offset + 0] = (byte)((value & 0xFF00000000000000L) >> 56); 292 } 293 294 /** 295 * Returns the long value of the <code>valueIndex</code>-th value. 296 * @param valueIndex the index of the value. 297 * @throws InvalidTypeException if index is 0 as it is a string value. 298 */ getValueAsLong(int valueIndex)299 private final long getValueAsLong(int valueIndex) throws InvalidTypeException { 300 switch (valueIndex) { 301 case 0: 302 throw new InvalidTypeException(); 303 case 1: 304 return gcTime; 305 case 2: 306 return objectsFreed; 307 case 3: 308 return bytesFreed; 309 case 4: 310 return softLimit; 311 case 5: 312 return actualSize; 313 case 6: 314 return allowedSize; 315 case 7: 316 return objectsAllocated; 317 case 8: 318 return bytesAllocated; 319 case 9: 320 return actualSize - zActualSize; 321 case 10: 322 return allowedSize - zAllowedSize; 323 case 11: 324 return objectsAllocated - zObjectsAllocated; 325 case 12: 326 return bytesAllocated - zBytesAllocated; 327 case 13: 328 return zActualSize; 329 case 14: 330 return zAllowedSize; 331 case 15: 332 return zObjectsAllocated; 333 case 16: 334 return zBytesAllocated; 335 case 17: 336 return externalLimit; 337 case 18: 338 return externalBytesAllocated; 339 case 19: 340 return dlmallocFootprint; 341 case 20: 342 return mallinfoTotalAllocatedSpace; 343 } 344 345 throw new ArrayIndexOutOfBoundsException(); 346 } 347 } 348