1/*
2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.management.counter.perf;
27
28import sun.management.counter.*;
29import java.nio.*;
30import java.io.UnsupportedEncodingException;
31
32class PerfDataEntry {
33    private class EntryFieldOffset {
34        private final static int SIZEOF_BYTE = 1;
35        private final static int SIZEOF_INT  = 4;
36        private final static int SIZEOF_LONG = 8;
37
38        private final static int ENTRY_LENGTH_SIZE    = SIZEOF_INT;
39        private final static int NAME_OFFSET_SIZE     = SIZEOF_INT;
40        private final static int VECTOR_LENGTH_SIZE   = SIZEOF_INT;
41        private final static int DATA_TYPE_SIZE       = SIZEOF_BYTE;
42        private final static int FLAGS_SIZE           = SIZEOF_BYTE;
43        private final static int DATA_UNIT_SIZE       = SIZEOF_BYTE;
44        private final static int DATA_VAR_SIZE        = SIZEOF_BYTE;
45        private final static int DATA_OFFSET_SIZE     = SIZEOF_INT;
46
47        final static int ENTRY_LENGTH  = 0;
48        final static int NAME_OFFSET   = ENTRY_LENGTH + ENTRY_LENGTH_SIZE;
49        final static int VECTOR_LENGTH = NAME_OFFSET + NAME_OFFSET_SIZE;;
50        final static int DATA_TYPE     = VECTOR_LENGTH + VECTOR_LENGTH_SIZE;
51        final static int FLAGS         = DATA_TYPE + DATA_TYPE_SIZE;
52        final static int DATA_UNIT     = FLAGS + FLAGS_SIZE;
53        final static int DATA_VAR      = DATA_UNIT + DATA_UNIT_SIZE;
54        final static int DATA_OFFSET   = DATA_VAR + DATA_VAR_SIZE;
55    }
56
57    private String       name;
58    private int          entryStart;
59    private int          entryLength;
60    private int          vectorLength;
61    private PerfDataType dataType;
62    private int          flags;
63    private Units        unit;
64    private Variability  variability;
65    private int          dataOffset;
66    private int          dataSize;
67    private ByteBuffer   data;
68
69    PerfDataEntry(ByteBuffer b) {
70        entryStart = b.position();
71        entryLength = b.getInt();
72
73        // check for valid entry length
74        if (entryLength <= 0 || entryLength > b.limit()) {
75            throw new InstrumentationException("Invalid entry length: " +
76                                               " entryLength = " + entryLength);
77        }
78        // check if last entry occurs before the eof.
79        if ((entryStart + entryLength) > b.limit()) {
80            throw new InstrumentationException("Entry extends beyond end of buffer: " +
81                                               " entryStart = " + entryStart +
82                                               " entryLength = " + entryLength +
83                                               " buffer limit = " + b.limit());
84        }
85
86        b.position(entryStart + EntryFieldOffset.NAME_OFFSET);
87        int nameOffset = b.getInt();
88
89        if ((entryStart + nameOffset) > b.limit()) {
90            throw new InstrumentationException("Invalid name offset: " +
91                                               " entryStart = " + entryStart +
92                                               " nameOffset = " + nameOffset +
93                                               " buffer limit = " + b.limit());
94        }
95
96
97        b.position(entryStart + EntryFieldOffset.VECTOR_LENGTH);
98        vectorLength = b.getInt();
99
100        b.position(entryStart + EntryFieldOffset.DATA_TYPE);
101        dataType = PerfDataType.toPerfDataType(b.get());
102
103        b.position(entryStart + EntryFieldOffset.FLAGS);
104        flags = b.get();
105
106        b.position(entryStart + EntryFieldOffset.DATA_UNIT);
107        unit = Units.toUnits(b.get());
108
109        b.position(entryStart + EntryFieldOffset.DATA_VAR);
110        variability = Variability.toVariability(b.get());
111
112        b.position(entryStart + EntryFieldOffset.DATA_OFFSET);
113        dataOffset = b.getInt();
114
115        // read in the perfData item name, casting bytes to chars. skip the
116        // null terminator
117        b.position(entryStart + nameOffset);
118        // calculate the length of the name
119        int nameLength = 0;
120        byte c;
121        for (; (c = b.get()) != (byte)0; nameLength++);
122
123        byte[] symbolBytes = new byte[nameLength];
124        b.position(entryStart + nameOffset);
125        for (int i = 0; i < nameLength; i++) {
126            symbolBytes[i] = b.get();
127        }
128
129        // convert name into a String
130        try {
131            name = new String(symbolBytes, "UTF-8");
132        }
133        catch (UnsupportedEncodingException e) {
134            // should not reach here
135            // "UTF-8" is always a known encoding
136            throw new InternalError(e.getMessage(), e);
137        }
138
139        if (variability == Variability.INVALID) {
140            throw new InstrumentationException("Invalid variability attribute:" +
141                                               " name = " + name);
142        }
143        if (unit == Units.INVALID) {
144            throw new InstrumentationException("Invalid units attribute: " +
145                                               " name = " + name);
146        }
147
148        if (vectorLength > 0) {
149            dataSize = vectorLength * dataType.size();
150        } else {
151            dataSize = dataType.size();
152        }
153
154        // check if data beyond the eof.
155        if ((entryStart + dataOffset + dataSize) > b.limit()) {
156            throw new InstrumentationException("Data extends beyond end of buffer: " +
157                                               " entryStart = " + entryStart +
158                                               " dataOffset = " + dataOffset+
159                                               " dataSize = " + dataSize +
160                                               " buffer limit = " + b.limit());
161        }
162        // Construct a ByteBuffer for the data
163        b.position(entryStart + dataOffset);
164        data = b.slice();
165        data.order(b.order());
166        data.limit(dataSize);
167    }
168
169
170    public int size() {
171        return entryLength;
172    }
173
174    public String name() {
175        return name;
176    }
177
178    public PerfDataType type() {
179        return dataType;
180    }
181
182    public Units units() {
183        return unit;
184    }
185
186    public int flags() {
187        return flags;
188    }
189
190    /**
191     * Returns the number of elements in the data.
192     */
193    public int vectorLength() {
194        return vectorLength;
195    }
196
197    public Variability variability() {
198        return variability;
199    }
200
201    public ByteBuffer byteData() {
202        data.position(0);
203        assert data.remaining() == vectorLength();
204        return data.duplicate();
205    }
206
207    public LongBuffer longData() {
208        LongBuffer lb = data.asLongBuffer();
209        return lb;
210    }
211}
212