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