| package xdc.rta; |
| |
| import xdc.runtime.LoggerBufDecoder; |
| |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.Vector; |
| |
| /* |
| * ======== MixedDecoder ======== |
| * This class decodes and filters log entries from multiple logger types. |
| * It takes byte arrays of both xdc.runtime.Log records and |
| * xdc.runtime.LoggerBuf entries, properly decodes them based on the logger |
| * id, then filters the results to eliminate any redundant or out-of-order |
| * records. |
| */ |
| public class MixedDecoder { |
| |
| private MetaData meta; |
| private LoggerBufDecoder loggerBufDec; |
| private Decoder logDec; |
| |
| /* |
| * This hash map tracks the highest sequence number we have seen |
| * for a given logger. |
| */ |
| private HashMap<Integer, Long> highestSeen; |
| |
| /* |
| * Multiple logger Ids may map to the same log (due to run mode and |
| * stop mode, for example). This HashMap maps those logger ids to a |
| * common value to support filtering. |
| */ |
| private HashMap<Integer, Integer> filterIds; |
| |
| /* |
| * ======== Constructor ======== |
| */ |
| public MixedDecoder (MetaData meta, LoggerBufDecoder loggerBufDec, |
| Decoder logDec) |
| { |
| this.meta = meta; |
| this.loggerBufDec = loggerBufDec; |
| this.logDec = logDec; |
| |
| filterIds = new HashMap<Integer, Integer>(); |
| |
| highestSeen = new HashMap<Integer, Long>(); |
| } |
| |
| /* |
| * ======== addLog ======== |
| */ |
| public void addLog(int[] logIds) |
| { |
| /* Use the first log id in the list as the common log number. */ |
| int commonNum = logIds[0]; |
| |
| /* Map the common log id to itself. */ |
| filterIds.put(commonNum, commonNum); |
| |
| /* Map the rest of the logger Ids to the common one. */ |
| for (int i = 1; i < logIds.length; i++) { |
| filterIds.put(logIds[i], commonNum); |
| } |
| |
| /* Initialize the 'highestSeen' value for the common log id. */ |
| highestSeen.put(commonNum, -1l); |
| } |
| |
| /* |
| * ======== mapDecoder ======== |
| */ |
| // TODO - Make MixedDecoder generic. |
| //public void mapDecoder(int logId, IDecoder decoder) |
| |
| /* |
| * ======== decode ======== |
| * This API decodes the given byte array based on the logger id. It |
| * filters the decoded records to eleminate redundant and out-of-order |
| * records. |
| */ |
| public HostEvent[] decode(byte[] buffer, int offset, int length, int logId) |
| { |
| HostEvent[] evts; |
| |
| /* |
| * If these are stop mode entries (indicated by the log id) |
| * decode using the LoggerBufDecoder. |
| * TODO - To be generic, the MixedDecoder should have a general |
| * mapping of log id to decoder. This will require an IDecoder |
| * interface. |
| */ |
| if (logId >= meta.getLoggerNames().length) { |
| evts = loggerBufDec.decodeBuffer(buffer, offset, length); |
| |
| /* It's possible that there are no entries in the logger buf. */ |
| if (evts.length == 0) { |
| return (evts); |
| } |
| } |
| /* Otherwise, they are just Log records */ |
| else { |
| int recSize = meta.getTargetEventRecSize(); |
| int numRecs = length / recSize; |
| |
| evts = new HostEvent[numRecs]; |
| |
| /* Decode each of the records individually. */ |
| for (int i = 0; i < numRecs; i++) { |
| evts[i] = logDec.apply(buffer, offset + (i * recSize)); |
| } |
| |
| /* Sort the records in case they are out of order. */ |
| Arrays.sort(evts, evts[0].new CompareRecs()); |
| } |
| |
| /* Filter the events. */ |
| return (filterEvents(evts, logId)); |
| } |
| |
| /* |
| * ======== filterEvents ======== |
| * This API takes an array of HostEvents and filters out any records which |
| * are out of order or have already been seen. |
| * To accomplish this, it simply filters out any records whose sequence |
| * number is lower than the highest number which has been so far (per |
| * logger instance) |
| */ |
| private HostEvent[] filterEvents(HostEvent[] events, int loggerId) |
| { |
| Vector<HostEvent> results = new Vector<HostEvent>(); |
| |
| /* Get the common log id */ |
| int logId = filterIds.get(loggerId); |
| |
| /* Get the highest sequence number we've seen so far for this log. */ |
| long max = highestSeen.get(logId); |
| |
| /* For each of the records... */ |
| for (int i = 0; i < events.length; i++) { |
| /* |
| * If this record's sequence number is higher than any previously |
| * seen, update the 'max' and add the record to the results. |
| */ |
| if (events[i].sequenceNum > max) { |
| max = events[i].sequenceNum; |
| results.add(events[i]); |
| } |
| } |
| |
| /* Update the highest sequence number seen. */ |
| highestSeen.put(logId, max); |
| |
| return (results.toArray(new HostEvent[0])); |
| } |
| } |