1 /*
2 * Copyright (c) 2020, 2025, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24 #include "ci/ciMethod.hpp"
25 #include "compiler/compilerEvent.hpp"
26 #include "jfr/jfr.hpp"
27 #include "jfr/jfrEvents.hpp"
28 #include "jfr/metadata/jfrSerializer.hpp"
29 #include "runtime/interfaceSupport.inline.hpp"
30 #include "runtime/javaThread.hpp"
31 #include "runtime/os.hpp"
32 #include "runtime/semaphore.inline.hpp"
33 #include "utilities/growableArray.hpp"
34
35 // Synchronizes access to phases_names.
36 class PhaseTypeGuard : public StackObj {
37 private:
38 static Semaphore _mutex_semaphore;
39 bool _enabled;
40 public:
41 PhaseTypeGuard(bool enabled=true) {
42 if (enabled) {
43 _mutex_semaphore.wait();
44 _enabled = true;
45 } else {
46 _enabled = false;
47 }
48 }
49 ~PhaseTypeGuard() {
50 if (_enabled) {
51 _mutex_semaphore.signal();
52 }
53 }
54 };
55
56 Semaphore PhaseTypeGuard::_mutex_semaphore(1);
57
58 // Table for mapping compiler phases names to int identifiers.
59 static GrowableArray<const char*>* _phase_names = nullptr;
60
61 class CompilerPhaseTypeConstant : public JfrSerializer {
62 public:
63 void serialize(JfrCheckpointWriter& writer) {
64 PhaseTypeGuard guard;
65 assert(_phase_names != nullptr, "invariant");
66 assert(_phase_names->is_nonempty(), "invariant");
67 const u4 nof_entries = _phase_names->length();
68 writer.write_count(nof_entries);
69 for (u4 i = 0; i < nof_entries; i++) {
70 writer.write_key(i);
71 writer.write(_phase_names->at(i));
72 }
73 }
74 };
75
76 static int lookup_phase(const char* phase_name) {
77 for (int i = 0; i < _phase_names->length(); i++) {
78 const char* name = _phase_names->at(i);
79 if (strcmp(name, phase_name) == 0) {
80 return i;
81 }
82 }
83 return -1;
84 }
85
86 int CompilerEvent::PhaseEvent::get_phase_id(const char* phase_name, bool may_exist, bool use_strdup, bool sync) {
87 int index;
88 bool register_jfr_serializer = false;
89 {
90 PhaseTypeGuard guard(sync);
91 if (_phase_names == nullptr) {
92 _phase_names = new (mtInternal) GrowableArray<const char*>(100, mtCompiler);
93 register_jfr_serializer = true;
94 } else if (may_exist) {
95 index = lookup_phase(phase_name);
96 if (index != -1) {
97 return index;
98 }
99 } else {
100 assert((index = lookup_phase(phase_name)) == -1, "phase name \"%s\" already registered: %d", phase_name, index);
101 }
102
103 index = _phase_names->length();
104 _phase_names->append(use_strdup ? os::strdup(phase_name) : phase_name);
105 }
106 if (register_jfr_serializer) {
107 JfrSerializer::register_serializer(TYPE_COMPILERPHASETYPE, false, new CompilerPhaseTypeConstant());
108 } else if (Jfr::is_recording()) {
109 // serialize new phase.
110 JfrCheckpointWriter writer;
111 writer.write_type(TYPE_COMPILERPHASETYPE);
112 writer.write_count(1);
113 writer.write_key(index);
114 writer.write(phase_name);
115 }
116 return index;
117 }
118
119 // As part of event commit, a Method* is tagged as a function of an epoch.
120 // Epochs evolve during safepoints. To ensure the event is tagged in the correct epoch,
121 // that is, to avoid a race, the thread will participate in the safepoint protocol
122 // by doing the commit while the thread is _thread_in_vm.
123 template <typename EventType>
124 static inline void commit(EventType& event) {
125 JavaThread* thread = JavaThread::current();
126 JavaThreadState state = thread->thread_state();
127 if (state == _thread_in_native) {
128 ThreadInVMfromNative transition(thread);
129 event.commit();
130 } else {
131 assert(state == _thread_in_vm, "coming from wrong thread state %d", state);
132 event.commit();
133 }
134 }
135
136 void CompilerEvent::CompilationEvent::post(EventCompilation& event, int compile_id, CompilerType compiler_type, Method* method,
137 int compile_level, bool success, bool is_osr, int code_size,
138 int inlined_bytecodes, size_t arenaBytes) {
139 event.set_compileId(compile_id);
140 event.set_compiler(compiler_type);
141 event.set_method(method);
142 event.set_compileLevel((short)compile_level);
143 event.set_succeded(success);
144 event.set_isOsr(is_osr);
145 event.set_codeSize(code_size);
146 event.set_inlinedBytes(inlined_bytecodes);
147 event.set_arenaBytes(arenaBytes);
148 commit(event);
149 }
150
151 void CompilerEvent::CompilationFailureEvent::post(EventCompilationFailure& event, int compile_id, const char* reason) {
152 event.set_compileId(compile_id);
153 event.set_failureMessage(reason);
154 event.commit();
155 }
156
157 void CompilerEvent::PhaseEvent::post(EventCompilerPhase& event, const Ticks& start_time, int phase, int compile_id, int level) {
158 event.set_starttime(start_time);
159 event.set_phase((u1) phase);
160 event.set_compileId(compile_id);
161 event.set_phaseLevel((short)level);
162 event.commit();
163 }
164
165 void CompilerEvent::InlineEvent::post(EventCompilerInlining& event, int compile_id, Method* caller, const JfrStructCalleeMethod& callee, bool success, const char* msg, int bci) {
166 event.set_compileId(compile_id);
167 event.set_caller(caller);
168 event.set_callee(callee);
169 event.set_succeeded(success);
170 event.set_message(msg);
171 event.set_bci(bci);
172 commit(event);
173 }
174
175 void CompilerEvent::InlineEvent::post(EventCompilerInlining& event, int compile_id, Method* caller, Method* callee, bool success, const char* msg, int bci) {
176 JfrStructCalleeMethod callee_struct;
177 callee_struct.set_type(callee->klass_name()->as_utf8());
178 callee_struct.set_name(callee->name()->as_utf8());
179 callee_struct.set_descriptor(callee->signature()->as_utf8());
180 post(event, compile_id, caller, callee_struct, success, msg, bci);
181 }
182
183 void CompilerEvent::InlineEvent::post(EventCompilerInlining& event, int compile_id, Method* caller, ciMethod* callee, bool success, const char* msg, int bci) {
184 JfrStructCalleeMethod callee_struct;
185 callee_struct.set_type(callee->holder()->name()->as_utf8());
186 callee_struct.set_name(callee->name()->as_utf8());
187 callee_struct.set_descriptor(callee->signature()->as_symbol()->as_utf8());
188 post(event, compile_id, caller, callee_struct, success, msg, bci);
189 }