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 
26 package sun.management.counter.perf;
27 
28 import sun.management.counter.*;
29 import java.nio.*;
30 import java.util.*;
31 import java.util.regex.*;
32 
33 public 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 
PerfInstrumentation(ByteBuffer b)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 
getMajorVersion()58     public int getMajorVersion() {
59         return prologue.getMajorVersion();
60     }
61 
getMinorVersion()62     public int getMinorVersion() {
63         return prologue.getMinorVersion();
64     }
65 
getModificationTimeStamp()66     public long getModificationTimeStamp() {
67         return prologue.getModificationTimeStamp();
68     }
69 
rewind()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 
hasNext()79     boolean hasNext() {
80         return (nextEntry < prologue.getUsed());
81     }
82 
getNextCounter()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 
getAllCounters()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 
findByPattern(String patternString)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