1/*
2 * Copyright (c) 2003, 2012, 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.util.*;
31import java.util.regex.*;
32
33public class PerfInstrumentation {
34    private ByteBuffer buffer;
35    private Prologue prologue;
36    private long lastModificationTime;
37    private long lastUsed;
38    private int  nextEntry;
39    private SortedMap<String, Counter>  map;
40
41    public PerfInstrumentation(ByteBuffer b) {
42        prologue = new Prologue(b);
43        buffer = b;
44        buffer.order(prologue.getByteOrder());
45
46        // Check recognized versions
47        int major = getMajorVersion();
48        int minor = getMinorVersion();
49
50        // Support only 2.0 version
51        if (major < 2) {
52            throw new InstrumentationException("Unsupported version: " +
53                                               major + "." + minor);
54        }
55        rewind();
56    }
57
58    public int getMajorVersion() {
59        return prologue.getMajorVersion();
60    }
61
62    public int getMinorVersion() {
63        return prologue.getMinorVersion();
64    }
65
66    public long getModificationTimeStamp() {
67        return prologue.getModificationTimeStamp();
68    }
69
70    void rewind() {
71        // rewind to the first entry
72        buffer.rewind();
73        buffer.position(prologue.getEntryOffset());
74        nextEntry = buffer.position();
75        // rebuild all the counters
76        map = new TreeMap<>();
77    }
78
79    boolean hasNext() {
80        return (nextEntry < prologue.getUsed());
81    }
82
83    Counter getNextCounter() {
84        if (! hasNext()) {
85            return null;
86        }
87
88        if ((nextEntry % 4) != 0) {
89            // entries are always 4 byte aligned.
90            throw new InstrumentationException(
91                "Entry index not properly aligned: " + nextEntry);
92        }
93
94        if (nextEntry < 0  || nextEntry > buffer.limit()) {
95            // defensive check to protect against a corrupted shared memory region.
96            throw new InstrumentationException(
97                "Entry index out of bounds: nextEntry = " + nextEntry +
98                ", limit = " + buffer.limit());
99        }
100
101        buffer.position(nextEntry);
102        PerfDataEntry entry = new PerfDataEntry(buffer);
103        nextEntry = nextEntry + entry.size();
104
105        Counter counter = null;
106        PerfDataType type = entry.type();
107        if (type == PerfDataType.BYTE) {
108            if (entry.units() == Units.STRING && entry.vectorLength() > 0) {
109                counter = new PerfStringCounter(entry.name(),
110                                                entry.variability(),
111                                                entry.flags(),
112                                                entry.vectorLength(),
113                                                entry.byteData());
114            } else if (entry.vectorLength() > 0) {
115                counter = new PerfByteArrayCounter(entry.name(),
116                                                   entry.units(),
117                                                   entry.variability(),
118                                                   entry.flags(),
119                                                   entry.vectorLength(),
120                                                   entry.byteData());
121           } else {
122                // ByteArrayCounter must have vectorLength > 0
123                assert false;
124           }
125        }
126        else if (type == PerfDataType.LONG) {
127            if (entry.vectorLength() == 0) {
128                counter = new PerfLongCounter(entry.name(),
129                                              entry.units(),
130                                              entry.variability(),
131                                              entry.flags(),
132                                              entry.longData());
133            } else {
134                counter = new PerfLongArrayCounter(entry.name(),
135                                                   entry.units(),
136                                                   entry.variability(),
137                                                   entry.flags(),
138                                                   entry.vectorLength(),
139                                                   entry.longData());
140            }
141        }
142        else {
143            // FIXME: Should we throw an exception for unsupported type?
144            // Currently skip such entry
145            assert false;
146        }
147        return counter;
148    }
149
150    public synchronized List<Counter> getAllCounters() {
151        while (hasNext()) {
152            Counter c = getNextCounter();
153            if (c != null) {
154                map.put(c.getName(), c);
155            }
156        }
157        return new ArrayList<>(map.values());
158    }
159
160    public synchronized List<Counter> findByPattern(String patternString) {
161        while (hasNext()) {
162            Counter c = getNextCounter();
163            if (c != null) {
164                map.put(c.getName(), c);
165            }
166        }
167
168        Pattern pattern = Pattern.compile(patternString);
169        Matcher matcher = pattern.matcher("");
170        List<Counter> matches = new ArrayList<>();
171
172
173        for (Map.Entry<String,Counter> me: map.entrySet()) {
174            String name = me.getKey();
175
176            // apply pattern to counter name
177            matcher.reset(name);
178
179            // if the pattern matches, then add Counter to list
180            if (matcher.lookingAt()) {
181                matches.add(me.getValue());
182            }
183        }
184        return matches;
185    }
186}
187