1 #!/usr/sbin/dtrace -Zs
2 /*
3  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   - Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *
12  *   - Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  *
16  *   - Neither the name of Oracle nor the names of its
17  *     contributors may be used to endorse or promote products derived
18  *     from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34 */
35 
36 /*
37  * Usage:
38  *    1. method_invocation_stat.d -c "java ..."
39  *    2. method_invocation_stat.d -p JAVA_PID
40  *
41  * This script collects statistics about Java method invocations.
42  *
43  * Notes:
44  *  - These probes are disabled by default since it incurs performance
45  *    overhead to the application. To trace the method-entry and
46  *    method-exit probes, you need to turn on the ExtendedDTraceProbes VM
47  *    option.
48  *    You can either start the application with -XX:+ExtendedDTraceProbes
49  *    option or use the jinfo command to enable it at runtime as follows:
50  *
51  *       jinfo -flag +ExtendedDTraceProbes <java_pid>
52  *
53  */
54 
55 #pragma D option quiet
56 #pragma D option destructive
57 #pragma D option defaultargs
58 #pragma D option bufsize=16m
59 #pragma D option aggrate=100ms
60 
61 
62 self char *str_ptr;
63 self string class_name;
64 self string method_name;
65 self string signature;
66 self string package_name;
67 self string last_class_name;
68 
69 long long JAVA_CALLS;
70 long long JNI_CALLS;
71 long long SYS_CALLS;
72 
73 int SYS_DEEP;
74 long long LAST_SYS_TS;
75 
76 long long START_TIME;
77 long long JAVA_TIME;
78 long long RUN_TIME;
79 long long SYS_TIME;
80 
81 BEGIN
82 {
83     SAMPLE_NAME = "hotspot method invocation tracing";
84 
85     START_TIME = timestamp;
86     SYS_TIME = 0;
87 
88     printf("BEGIN %s\n\n", SAMPLE_NAME);
89 }
90 
91 /*
92  * hotspot:::method-entry, hotspot:::method-return probe arguments:
93  *  arg0: uintptr_t,    Java thread id
94  *  arg1: char*,        a pointer to mUTF-8 string containing the name of
95  *                          the class of the method being entered
96  *  arg2: uintptr_t,    the length of the class name (in bytes)
97  *  arg3: char*,        a pointer to mUTF-8 string data which contains the
98  *                          name of the method being entered
99  *  arg4: uintptr_t,    the length of the method name (in bytes)
100  *  arg5: char*,        a pointer to mUTF-8 string data which contains the
101  *                          signature of the method being entered
102  *  arg6: uintptr_t,    the length of the signature(in bytes)
103  */
104 hotspot$target:::method-entry
105 {
106     self->str_ptr = (char*) copyin(arg1, arg2+1);
107     self->str_ptr[arg2] = '\0';
108     self->class_name = (string) self->str_ptr;
109 
110     self->str_ptr = (char*) copyin(arg3, arg4+1);
111     self->str_ptr[arg4] = '\0';
112     self->method_name = (string) self->str_ptr;
113 
114     self->str_ptr = (char*) copyin(arg5, arg6+1);
115     self->str_ptr[arg6] = '\0';
116     self->signature = (string) self->str_ptr;
117 
118 
119     self->package_name = dirname(self->class_name);
120 
121     JAVA_CALLS ++;
122     @method_calls[self->class_name,
123                   self->method_name, self->signature] = count();
124     @class_calls[self->class_name] = count();
125     @package_calls[self->package_name] = count();
126 }
127 
128 
129 hotspot_jni$target:::*-entry
130 {
131     JNI_CALLS ++;
132 
133     @jni_calls[probename] = count();
134 }
135 
136 syscall:::entry
137 /pid == $target && SYS_DEEP == 0/
138 {
139     LAST_SYS_TS = timestamp;
140 }
141 
142 syscall:::entry
143 /pid == $target/
144 {
145     SYS_DEEP ++;
146     @sys_calls[probefunc] = count();
147     SYS_CALLS ++;
148 }
149 
150 syscall:::return
151 /pid == $target/
152 {
153     SYS_DEEP --;
154 }
155 
156 syscall:::return
157 /pid == $target && SYS_DEEP == 0/
158 {
159     SYS_TIME += (timestamp - LAST_SYS_TS);
160 }
161 
162 
163 :::END
164 {
165     RUN_TIME = (timestamp - START_TIME);
166     JAVA_TIME = (RUN_TIME - SYS_TIME);
167 
168     printf("System calls:\n");
169     printa("%10@d %s\n", @sys_calls);
170     printf("\n");
171 
172     printf("JNI calls:\n");
173     printa("%10@d %s\n", @jni_calls);
174     printf("\n");
175 
176     printf("Top packages calls:\n");
177     printa("%10@d %s\n", @package_calls);
178     printf("\n");
179 
180     printf("Top class calls:\n");
181     printa("%10@d %s\n", @class_calls);
182     printf("\n");
183 
184     printf("Top method calls:\n");
185     printa("%10@d %s:%s:%s\n", @method_calls);
186     printf("\n");
187 
188     printf("=======================================\n");
189     printf("JAVA_CALLS: %10d\n", JAVA_CALLS);
190     printf(" JNI_CALLS: %10d\n", JNI_CALLS);
191     printf(" SYS_CALLS: %10d\n", SYS_CALLS);
192     printf("\n");
193 
194     printf("Run time:       %15d\n", RUN_TIME);
195     printf("Syscall time:   %15d\n", SYS_TIME);
196     printf("Java+JNI time:  %15d\n", JAVA_TIME);
197     printf("\n");
198 }
199 
200 :::END
201 {
202     printf("\nEND %s\n", SAMPLE_NAME);
203 }
204 
205 syscall::rexit:entry,
206 syscall::exit:entry
207 /pid == $target/
208 {
209     exit(0);
210 }
211