1 /* Copyright (c) 2018 Daniel Widdis, All Rights Reserved
2  *
3  * The contents of this file is dual-licensed under 2
4  * alternative Open Source/Free licenses: LGPL 2.1 or later and
5  * Apache License 2.0. (starting with JNA version 4.0.0).
6  *
7  * You can freely decide which license you want to apply to
8  * the project.
9  *
10  * You may obtain a copy of the LGPL License at:
11  *
12  * http://www.gnu.org/licenses/licenses.html
13  *
14  * A copy is also included in the downloadable source code package
15  * containing JNA, in file "LGPL2.1".
16  *
17  * You may obtain a copy of the Apache License at:
18  *
19  * http://www.apache.org/licenses/
20  *
21  * A copy is also included in the downloadable source code package
22  * containing JNA, in file "AL2.0".
23  */
24 // package com.sun.jna.platform.win32;
25 package com.sun.jna.platform.win32;
26 
27 import java.util.HashSet;
28 import java.util.Set;
29 
30 import org.junit.Test;
31 
32 import com.sun.jna.Memory;
33 import com.sun.jna.Native;
34 import com.sun.jna.Pointer;
35 import com.sun.jna.platform.win32.WinDef.DWORDByReference;
36 import com.sun.jna.platform.win32.WinPerf.PERF_COUNTER_BLOCK;
37 import com.sun.jna.platform.win32.WinPerf.PERF_COUNTER_DEFINITION;
38 import com.sun.jna.platform.win32.WinPerf.PERF_DATA_BLOCK;
39 import com.sun.jna.platform.win32.WinPerf.PERF_INSTANCE_DEFINITION;
40 import com.sun.jna.platform.win32.WinPerf.PERF_OBJECT_TYPE;
41 import com.sun.jna.ptr.IntByReference;
42 
43 /**
44  * Tests structures in WinPerf
45  *
46  * @author dbwiddis
47  */
48 public class WinPerfTest extends AbstractWin32TestSupport {
49     @Test
testPerfDataBLock()50     public void testPerfDataBLock() {
51         // This method tests:
52         // PERF_DATA_BLOCK,
53         // PERF_OBJECT_TYPE,
54         // PERF_COUNTER_DEFINITION,
55         // PERF_INSTANCE_DEFINITION,
56         // PERF_COUNTER_BLOCK
57         //
58         // See Performance Data format at
59         // https://msdn.microsoft.com/en-us/library/windows/desktop/aa373105(v=vs.85).aspx
60         // [ ] Perf_Data_block
61         // Then one or more objects repeating everything below:
62         // [ ] Object Type
63         // [ ][ ][ ] Multiple counter definitions
64         // Then multiple instances repeating:
65         // [ ] Instance Definition
66         // [ ] Instance name
67         // [ ] Counter Block
68         // [ ][ ][ ] Counter data for each definition above
69 
70         if (AbstractWin32TestSupport.isEnglishLocale) {
71             // To test the structures we'll get the data block for Process
72             // performance data
73             DWORDByReference index = new DWORDByReference();
74             Pdh.INSTANCE.PdhLookupPerfIndexByName(null, "Process", index);
75             int processIndex = index.getValue().intValue();
76             String processIndexStr = Integer.toString(processIndex);
77             // And one of the counters, for PID:
78             Pdh.INSTANCE.PdhLookupPerfIndexByName(null, "ID Process", index);
79             int idProcessIndex = index.getValue().intValue();
80 
81             // now load the Process registry entry
82             // Sequentially increase the buffer until everything fits.
83             int perfDataBufferSize = 4096;
84             IntByReference lpcbData = new IntByReference(perfDataBufferSize);
85             Pointer pPerfData = new Memory(perfDataBufferSize);
86             while (WinError.ERROR_MORE_DATA == Advapi32.INSTANCE.RegQueryValueEx(WinReg.HKEY_PERFORMANCE_DATA,
87                     processIndexStr, 0, null, pPerfData, lpcbData)) {
88                 perfDataBufferSize += 4096;
89                 lpcbData.setValue(perfDataBufferSize);
90                 pPerfData = new Memory(perfDataBufferSize);
91             }
92             // When this loop exits, pPerfData points to the PERF_DATA_BLOCK.
93 
94             // PERF_DATA_BLOCK test
95             // Test the signature, a char[] containing [P, E, R, F]
96             PERF_DATA_BLOCK perfData = new PERF_DATA_BLOCK(pPerfData);
97             assertEquals("PERF", Native.toString(perfData.Signature));
98 
99             // PERF_OBJECT_TYPE test
100             // Process object title index should match process object
101             // Object type begins after header offset
102             long perfObjectOffset = perfData.HeaderLength;
103             PERF_OBJECT_TYPE perfObject = new PERF_OBJECT_TYPE(pPerfData.share(perfObjectOffset));
104             assertEquals(processIndex, perfObject.ObjectNameTitleIndex);
105 
106             // PERF_COUNTER_DEFINITION test
107             // Counter offsets will be at least 4, and a multiple of 4
108             // Identify where counter definitions start
109             long perfCounterOffset = perfObjectOffset + perfObject.HeaderLength;
110             // Iterate through counter definitions to get the offset for the PID
111             int idProcessOffset = 0;
112             for (int counter = 0; counter < perfObject.NumCounters; counter++) {
113                 PERF_COUNTER_DEFINITION perfCounter = new PERF_COUNTER_DEFINITION(pPerfData.share(perfCounterOffset));
114                 assertTrue(perfCounter.CounterOffset >= 4);
115                 assertEquals(0, perfCounter.CounterOffset % 4);
116                 if (perfCounter.CounterNameTitleIndex == idProcessIndex) {
117                     idProcessOffset = perfCounter.CounterOffset;
118                 }
119                 // Increment for next Counter
120                 perfCounterOffset += perfCounter.ByteLength;
121             }
122 
123             // PERF_INSTANCE_DEFINITION test
124             long perfInstanceOffset = perfObjectOffset + perfObject.DefinitionLength;
125             Set<Integer> pidSet = new HashSet<Integer>();
126             for (int inst = 0; inst < perfObject.NumInstances; inst++) {
127                 PERF_INSTANCE_DEFINITION perfInstance = new PERF_INSTANCE_DEFINITION(
128                         pPerfData.share(perfInstanceOffset));
129                 // Definitions align to 8 byte boundaries
130                 assertEquals(0, perfInstance.ByteLength % 8);
131 
132                 // PERF_COUNTER_BLOCK test
133                 // ByteLength should be at least pid offset + 4,
134                 // and a multiple of 4
135                 long perfCounterBlockOffset = perfInstanceOffset + perfInstance.ByteLength;
136                 PERF_COUNTER_BLOCK perfCounterBlock = new PERF_COUNTER_BLOCK(pPerfData.share(perfCounterBlockOffset));
137                 assertTrue(perfCounterBlock.ByteLength >= 4 + idProcessOffset);
138                 assertEquals(0, perfCounterBlock.ByteLength % 4);
139                 int pid = pPerfData.getInt(perfCounterBlockOffset + idProcessOffset);
140                 // PID 0 exists as idle process and will repeat for the _Total
141                 // instance. All other PIDs should be unique
142                 assertTrue(pid >= 0);
143                 if (pid > 0) {
144                     assertFalse(pidSet.contains(pid));
145                     pidSet.add(pid);
146                 }
147             }
148         }
149     }
150 }
151