1 /*
  2  * Copyright (c) 2012, 2020, 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 
 25 #ifndef SHARE_JFR_RECORDER_SERVICE_JFREVENT_HPP
 26 #define SHARE_JFR_RECORDER_SERVICE_JFREVENT_HPP
 27 
 28 #include "jfr/recorder/jfrEventSetting.inline.hpp"
 29 #include "jfr/recorder/service/jfrEventThrottler.hpp"
 30 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
 31 #include "jfr/utilities/jfrTime.hpp"
 32 #include "jfr/utilities/jfrTypes.hpp"
 33 #include "jfr/writers/jfrNativeEventWriter.hpp"
 34 #include "runtime/thread.hpp"
 35 #include "utilities/exceptions.hpp"
 36 #include "utilities/ticks.hpp"
 37 #ifdef ASSERT
 38 #include "utilities/bitMap.hpp"
 39 #endif
 40 
 41 #ifdef ASSERT
 42 class JfrEventVerifier {
 43   template <typename>
 44   friend class JfrEvent;
 45  private:
 46   // verification of event fields
 47   BitMap::bm_word_t _verification_storage[1];
 48   BitMapView _verification_bit_map;
 49   bool _committed;
 50 
 51   JfrEventVerifier();
 52   void check(BitMap::idx_t field_idx) const;
 53   void set_field_bit(size_t field_idx);
 54   bool verify_field_bit(size_t field_idx) const;
 55   void set_committed();
 56   void clear_committed();
 57   bool committed() const;
 58 };
 59 #endif // ASSERT
 60 
 61 template <typename T>
 62 class JfrEvent {
 63  private:
 64   jlong _start_time;
 65   jlong _end_time;
 66   bool _started;
 67   bool _untimed;
 68   bool _should_commit;
 69   bool _evaluated;
 70 
 71  protected:
 72   JfrEvent(EventStartTime timing=TIMED) : _start_time(0), _end_time(0),
 73                                           _started(false), _untimed(timing == UNTIMED),
 74                                           _should_commit(false), _evaluated(false)
 75 #ifdef ASSERT
 76   , _verifier()
 77 #endif
 78   {
 79     if (T::is_enabled()) {
 80       _started = true;
 81       if (TIMED == timing && !T::isInstant) {
 82         set_starttime(JfrTicks::now());
 83       }
 84     }
 85   }
 86 
 87   void commit() {
 88     assert(!_verifier.committed(), "event already committed");
 89     if (!should_write()) {
 90       return;
 91     }
 92     write_event();
 93     DEBUG_ONLY(_verifier.set_committed();)
 94   }
 95 
 96  public:
 97   void set_starttime(const JfrTicks& time) {
 98     _start_time = time.value();
 99   }
100 
101   void set_endtime(const JfrTicks& time) {
102     _end_time = time.value();
103   }
104 
105   void set_starttime(const Ticks& time) {
106     _start_time = JfrTime::is_ft_enabled() ? time.ft_value() : time.value();
107   }
108 
109   void set_endtime(const Ticks& time) {
110     _end_time = JfrTime::is_ft_enabled() ? time.ft_value() : time.value();
111   }
112 
113   static bool is_enabled() {
114     return JfrEventSetting::is_enabled(T::eventId);
115   }
116 
117   static bool is_stacktrace_enabled() {
118     return JfrEventSetting::has_stacktrace(T::eventId);
119   }
120 
121   static bool is_large() {
122     return JfrEventSetting::is_large(T::eventId);
123   }
124 
125   static void set_large() {
126     JfrEventSetting::set_large(T::eventId);
127   }
128 
129   static JfrEventId id() {
130     return T::eventId;
131   }
132 
133   static bool is_instant() {
134     return T::isInstant;
135   }
136 
137   static bool is_requestable() {
138     return T::isRequestable;
139   }
140 
141   static bool has_thread() {
142     return T::hasThread;
143   }
144 
145   static bool has_stacktrace() {
146     return T::hasStackTrace;
147   }
148 
149   bool is_started() const {
150     return _started;
151   }
152 
153   bool should_commit() {
154     if (!_started) {
155       return false;
156     }
157     if (_untimed) {
158       return true;
159     }
160     if (_evaluated) {
161       return _should_commit;
162     }
163     _should_commit = evaluate();
164     _evaluated = true;
165     return _should_commit;
166   }
167 
168  private:
169   bool should_write() {
170     return _started && (_evaluated ? _should_commit : evaluate());
171   }
172 
173   bool evaluate() {
174     assert(_started, "invariant");
175     if (_start_time == 0) {
176       set_starttime(JfrTicks::now());
177     } else if (_end_time == 0) {
178       set_endtime(JfrTicks::now());
179     }
180     if (T::isInstant || T::isRequestable) {
181       return T::hasThrottle ? JfrEventThrottler::accept(T::eventId, _untimed ? 0 : _start_time) : true;
182     }
183     if (_end_time - _start_time < JfrEventSetting::threshold(T::eventId)) {
184       return false;
185     }
186     return T::hasThrottle ? JfrEventThrottler::accept(T::eventId, _untimed ? 0 : _end_time) : true;
187   }
188 
189   void write_event() {
190     DEBUG_ONLY(assert_precondition();)
191     Thread* const event_thread = Thread::current();
192     JfrThreadLocal* const tl = event_thread->jfr_thread_local();
193     JfrBuffer* const buffer = tl->native_buffer();
194     if (buffer == NULL) {
195       // most likely a pending OOM
196       return;
197     }
198     bool large = is_large();
199     if (write_sized_event(buffer, event_thread, tl, large)) {
200       // Event written succesfully
201       return;
202     }
203     if (!large) {
204       // Try large size
205       if (write_sized_event(buffer, event_thread, tl, true)) {
206         // Event written succesfully, use large size from now on
207         set_large();
208       }
209     }
210   }
211 
212   bool write_sized_event(JfrBuffer* const buffer, Thread* const event_thread, JfrThreadLocal* const tl, bool large_size) {
213     JfrNativeEventWriter writer(buffer, event_thread);
214     writer.begin_event_write(large_size);
215     writer.write<u8>(T::eventId);
216     assert(_start_time != 0, "invariant");
217     writer.write(_start_time);
218     if (!(T::isInstant || T::isRequestable) || T::hasCutoff) {
219       assert(_end_time != 0, "invariant");
220       writer.write(_end_time - _start_time);
221     }
222     if (T::hasThread) {
223       writer.write(JfrThreadLocal::thread_id(event_thread));
224     }
225     if (T::hasStackTrace) {
226       if (is_stacktrace_enabled()) {
227         if (tl->has_cached_stack_trace()) {
228           writer.write(tl->cached_stack_trace_id());
229         } else {
230           writer.write(JfrStackTraceRepository::record(event_thread));
231         }
232       } else {
233         writer.write<traceid>(0);
234       }
235     }
236     // payload
237     static_cast<T*>(this)->writeData(writer);
238     return writer.end_event_write(large_size) > 0;
239   }
240 
241 #ifdef ASSERT
242  private:
243   // verification of event fields
244   JfrEventVerifier _verifier;
245 
246   void assert_precondition() {
247     assert(T::eventId >= FIRST_EVENT_ID, "event id underflow invariant");
248     assert(T::eventId <= LAST_EVENT_ID, "event id overflow invariant");
249     DEBUG_ONLY(static_cast<T*>(this)->verify());
250   }
251 
252  protected:
253   void set_field_bit(size_t field_idx) {
254     _verifier.set_field_bit(field_idx);
255     // it is ok to reuse an already committed event
256     // granted you provide new informational content
257     _verifier.clear_committed();
258   }
259 
260   bool verify_field_bit(size_t field_idx) const {
261     return _verifier.verify_field_bit(field_idx);
262   }
263 #endif // ASSERT
264 };
265 
266 #endif // SHARE_JFR_RECORDER_SERVICE_JFREVENT_HPP