001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 014package org.jikesrvm.tuningfork; 015 016import org.jikesrvm.VM; 017import org.jikesrvm.runtime.Time; 018import org.vmmagic.pragma.Inline; 019import org.vmmagic.pragma.NoInline; 020import org.vmmagic.pragma.Uninterruptible; 021import org.vmmagic.pragma.Untraced; 022 023import com.ibm.tuningfork.tracegen.chunk.EventChunk; 024import com.ibm.tuningfork.tracegen.types.EventType; 025 026/** 027 * <p>A Feedlet is a entity that is a unit of trace generation 028 * for TuningFork. In Jikes RVM, a Feedlet is typically 029 * associated with a VM_Thread.</p> 030 * 031 * <p>Note an important assumption that a Feedlet will only 032 * be used by a single thread at a time. All operations are 033 * unsynchronized. This invariant is usually met because only 034 * the VM_Thread to which it is attached is allowed to perform 035 * addEvent operations on the Feedlet. If a Feedlet is attached 036 * to something other than a VM_Thread, then this invariant must be 037 * established via external synchronization.</p> 038 */ 039@Uninterruptible 040public final class Feedlet { 041 private static final boolean CHECK_TYPES = VM.VerifyAssertions; 042 043 private final TraceEngine engine; 044 private final int feedletIndex; 045 private int sequenceNumber; 046 @Untraced /* NB: Assumes EventChunk is NonMoving and externally kept alive for GC */ 047 private EventChunk events; 048 049 /** 050 * Enabled is true when TF engine is enabled, false otherwise. 051 * This field is intentionally not made final to 052 * (1) allow us to disable the boot thread's feedlet during VM booting 053 * (2) allow us to dynamically enable/disable event generation (for eventual socket hookup) 054 * (3) allow us to turn off event generation during VM shutdown 055 */ 056 boolean enabled; 057 058 /** 059 * Create a new Feedlet. 060 * This method is only meant to be called from TraceEngine. 061 * @param engine the TraceEngine instance to which this feedlet is attached. 062 * @param feedletIndex the index to use for the Feedlet 063 */ 064 Feedlet(TraceEngine engine, int feedletIndex) { 065 this.engine = engine; 066 this.feedletIndex = feedletIndex; 067 this.sequenceNumber = 0; 068 this.events = null; /* defer actually acquiring an EventChunk until the feedlet emits its first event */ 069 this.enabled = true; /* If tracing is not enabled, then TraceEngine will set this field to false. */ 070 } 071 072 /** 073 * @return the feedlet's index 074 */ 075 int getFeedletIndex() { 076 return feedletIndex; 077 } 078 079 void shutdown() { 080 enabled = false; 081 flushEventChunk(); 082 } 083 084 /** 085 * Add an event to the feedlet's generated event stream 086 * @param et The type of event to add 087 */ 088 @Inline 089 public void addEvent(EventType et) { 090 if (!enabled) return; 091 addEventInternal(et); 092 } 093 @NoInline 094 private void addEventInternal(EventType et) { 095 if (CHECK_TYPES && !checkTypes(et, 0, 0, 0, 0)) return; 096 097 long timeStamp = getTimeStamp(); 098 while (true) { 099 if (events == null && !acquireEventChunk()) { 100 return; /* failure */ 101 } 102 if (events.addEvent(timeStamp, et)) { 103 return; /* success */ 104 } 105 flushEventChunk(); /* events is full or stale; flush and try again */ 106 } 107 } 108 109 /** 110 * Add an event to the feedlet's generated event stream 111 * @param et The type of event to add 112 * @param ival1 The first int data value 113 */ 114 @Inline 115 public void addEvent(EventType et, int ival1) { 116 if (!enabled) return; 117 addEventInternal(et, ival1); 118 } 119 @NoInline 120 private void addEventInternal(EventType et, int ival1) { 121 if (CHECK_TYPES && !checkTypes(et, 1, 0, 0, 0)) return; 122 123 long timeStamp = getTimeStamp(); 124 while (true) { 125 if (events == null && !acquireEventChunk()) { 126 return; /* failure */ 127 } 128 if (events.addEvent(timeStamp, et, ival1)) { 129 return; /* success */ 130 } 131 flushEventChunk(); /* events is full or stale; flush and try again */ 132 } 133 } 134 135 /** 136 * Add an event to the feedlet's generated event stream 137 * @param et The type of event to add 138 * @param ival1 The first int data value 139 * @param ival2 The second int data value 140 */ 141 @Inline 142 public void addEvent(EventType et, int ival1, int ival2) { 143 if (!enabled) return; 144 addEventInternal(et, ival1, ival2); 145 } 146 @NoInline 147 private void addEventInternal(EventType et, int ival1, int ival2) { 148 if (CHECK_TYPES && !checkTypes(et, 2, 0, 0, 0)) return; 149 150 long timeStamp = getTimeStamp(); 151 while (true) { 152 if (events == null && !acquireEventChunk()) { 153 return; /* failure */ 154 } 155 if (events.addEvent(timeStamp, et, ival1, ival2)) { 156 return; /* success */ 157 } 158 flushEventChunk(); /* events is full or stale; flush and try again */ 159 } 160 } 161 162 /** 163 * Add an event to the feedlet's generated event stream 164 * @param et The type of event to add 165 * @param ival1 The first int data value 166 * @param ival2 The second int data value 167 * @param ival3 The third int data value 168 */ 169 @Inline 170 public void addEvent(EventType et, int ival1, int ival2, int ival3) { 171 if (!enabled) return; 172 addEventInternal(et, ival1, ival2, ival3); 173 } 174 @NoInline 175 private void addEventInternal(EventType et, int ival1, int ival2, int ival3) { 176 if (CHECK_TYPES && !checkTypes(et, 3, 0, 0, 0)) return; 177 178 long timeStamp = getTimeStamp(); 179 while (true) { 180 if (events == null && !acquireEventChunk()) { 181 return; /* failure */ 182 } 183 if (events.addEvent(timeStamp, et, ival1, ival2, ival3)) { 184 return; /* success */ 185 } 186 flushEventChunk(); /* events is full or stale; flush and try again */ 187 } 188 } 189 190 /** 191 * Add an event to the feedlet's generated event stream 192 * @param et The type of event to add 193 * @param ival1 The first int data value 194 * @param ival2 The second int data value 195 * @param ival3 The third int data value 196 * @param ival4 The fourth int data value 197 */ 198 @Inline 199 public void addEvent(EventType et, int ival1, int ival2, int ival3, int ival4) { 200 if (!enabled) return; 201 addEventInternal(et, ival1, ival2, ival3, ival4); 202 } 203 @NoInline 204 private void addEventInternal(EventType et, int ival1, int ival2, int ival3, int ival4) { 205 if (CHECK_TYPES && !checkTypes(et, 4, 0, 0, 0)) return; 206 207 long timeStamp = getTimeStamp(); 208 while (true) { 209 if (events == null && !acquireEventChunk()) { 210 return; /* failure */ 211 } 212 if (events.addEvent(timeStamp, et, ival1, ival2, ival3, ival4)) { 213 return; /* success */ 214 } 215 flushEventChunk(); /* events is full or stale; flush and try again */ 216 } 217 } 218 219 /** 220 * Add an event to the feedlet's generated event stream 221 * @param et The type of event to add 222 * @param lval1 The first double data value 223 */ 224 @Inline 225 public void addEvent(EventType et, long lval1) { 226 if (!enabled) return; 227 addEventInternal(et, lval1); 228 } 229 @NoInline 230 private void addEventInternal(EventType et, long lval1) { 231 if (CHECK_TYPES && !checkTypes(et, 0, 1, 0, 0)) return; 232 233 long timeStamp = getTimeStamp(); 234 while (true) { 235 if (events == null && !acquireEventChunk()) { 236 return; /* failure */ 237 } 238 if (events.addEvent(timeStamp, et, lval1)) { 239 return; /* success */ 240 } 241 flushEventChunk(); /* events is full or stale; flush and try again */ 242 } 243 } 244 245 /** 246 * Add an event to the feedlet's generated event stream 247 * @param et The type of event to add 248 * @param dval1 The first double data value 249 */ 250 @Inline 251 public void addEvent(EventType et, double dval1) { 252 if (!enabled) return; 253 addEventInternal(et, dval1); 254 } 255 @NoInline 256 private void addEventInternal(EventType et, double dval1) { 257 if (CHECK_TYPES && !checkTypes(et, 0, 0, 1, 0)) return; 258 259 long timeStamp = getTimeStamp(); 260 while (true) { 261 if (events == null && !acquireEventChunk()) { 262 return; /* failure */ 263 } 264 if (events.addEvent(timeStamp, et, dval1)) { 265 return; /* success */ 266 } 267 flushEventChunk(); /* events is full or stale; flush and try again */ 268 } 269 } 270 271 /** 272 * Add an event to the feedlet's generated event stream 273 * @param et The type of event to add 274 * @param sval1 The first String data value 275 */ 276 @Inline 277 public void addEvent(EventType et, String sval1) { 278 if (!enabled) return; 279 addEventInternal(et, sval1); 280 } 281 @NoInline 282 private void addEventInternal(EventType et, String sval1) { 283 if (CHECK_TYPES && !checkTypes(et, 0, 0, 0, 1)) return; 284 285 long timeStamp = getTimeStamp(); 286 while (true) { 287 if (events == null && !acquireEventChunk()) { 288 return; /* failure */ 289 } 290 if (events.addEvent(timeStamp, et, sval1)) { 291 return; /* success */ 292 } 293 flushEventChunk(); /* events is full or stale; flush and try again */ 294 } 295 } 296 297 /** 298 * Add an event to the feedlet's generated event stream 299 * @param et The type of event to add 300 * @param ival1 The first int data value 301 * @param dval1 The first double data value 302 */ 303 @Inline 304 public void addEvent(EventType et, int ival1, double dval1) { 305 if (!enabled) return; 306 addEventInternal(et, ival1, dval1); 307 } 308 @NoInline 309 private void addEventInternal(EventType et, int ival1, double dval1) { 310 if (CHECK_TYPES && !checkTypes(et, 1, 0, 1, 0)) return; 311 312 long timeStamp = getTimeStamp(); 313 while (true) { 314 if (events == null && !acquireEventChunk()) { 315 return; /* failure */ 316 } 317 if (events.addEvent(timeStamp, et, ival1, dval1)) { 318 return; /* success */ 319 } 320 flushEventChunk(); /* events is full or stale; flush and try again */ 321 } 322 } 323 324 /** 325 * Add an event to the feedlet's generated event stream 326 * @param et The type of event to add 327 * @param ival1 The first int data value 328 * @param ival2 The second int data value 329 * @param dval1 The first double data value 330 */ 331 @Inline 332 public void addEvent(EventType et, int ival1, int ival2, double dval1) { 333 if (!enabled) return; 334 addEventInternal(et, ival1, ival2, dval1); 335 } 336 @NoInline 337 private void addEventInternal(EventType et, int ival1, int ival2, double dval1) { 338 if (CHECK_TYPES && !checkTypes(et, 2, 0, 1, 0)) return; 339 340 long timeStamp = getTimeStamp(); 341 while (true) { 342 if (events == null && !acquireEventChunk()) { 343 return; /* failure */ 344 } 345 if (events.addEvent(timeStamp, et, ival1, ival2, dval1)) { 346 return; /* success */ 347 } 348 flushEventChunk(); /* events is full or stale; flush and try again */ 349 } 350 } 351 352 /** 353 * Add an event to the feedlet's generated event stream 354 * @param et The type of event to add 355 * @param dval1 The first double data value 356 * @param sval1 The first String data value 357 */ 358 @Inline 359 public void addEvent(EventType et, double dval1, String sval1) { 360 if (!enabled) return; 361 addEventInternal(et, dval1, sval1); 362 } 363 @NoInline 364 private void addEventInternal(EventType et, double dval1, String sval1) { 365 if (CHECK_TYPES && !checkTypes(et, 0, 0, 1, 1)) return; 366 367 long timeStamp = getTimeStamp(); 368 while (true) { 369 if (events == null && !acquireEventChunk()) { 370 return; /* failure */ 371 } 372 if (events.addEvent(timeStamp, et, dval1, sval1)) { 373 return; /* success */ 374 } 375 flushEventChunk(); /* events is full or stale; flush and try again */ 376 } 377 } 378 379 /** 380 * Add an event to the feedlet's generated event stream 381 * @param et the event's type 382 * @param idata an array of int data values (may be null if no such values for this event) 383 * @param ldata an array of long data values (may be null if no such values for this event) 384 * @param ddata an array of double data values (may be null if no such values for this event) 385 * @param sdata an array of String data values (may be null if no such values for this event) 386 */ 387 @Inline 388 public void addEvent(EventType et, int[] idata, long[] ldata, double[] ddata, String[] sdata) { 389 if (!enabled) return; 390 addEventInternal(et, idata, ldata, ddata, sdata); 391 } 392 @NoInline 393 private void addEventInternal(EventType et, int[] idata, long[] ldata, double[] ddata, String[] sdata) { 394 if (CHECK_TYPES) { 395 int ilen = idata == null ? 0 : idata.length; 396 int llen = ldata == null ? 0 : ldata.length; 397 int dlen = ddata == null ? 0 : ddata.length; 398 int slen = sdata == null ? 0 : sdata.length; 399 if (!checkTypes(et, ilen, llen, dlen, slen)) return; 400 } 401 402 long timeStamp = getTimeStamp(); 403 while (true) { 404 if (events == null && !acquireEventChunk()) { 405 return; /* failure */ 406 } 407 if (events.addEvent(timeStamp, et, idata, ldata, ddata, sdata)) { 408 return; /* success */ 409 } 410 flushEventChunk(); /* events is full or stale; flush and try again */ 411 } 412 } 413 414 private boolean checkTypes(EventType et, int numInts, int numLongs, int numDoubles, int numStrings) { 415 if (et.getNumberOfInts() != numInts || 416 et.getNumberOfLongs() != numLongs || 417 et.getNumberOfDoubles() != numDoubles || 418 et.getNumberOfStrings() != numStrings) { 419 VM.sysWriteln("Feedlet: Dropping addEvent of ill-typed event ", et.getName()); 420 return false; 421 } else { 422 return true; 423 } 424 } 425 426 private long getTimeStamp() { 427 return Time.nanoTime(); 428 } 429 430 @NoInline 431 private boolean acquireEventChunk() { 432 if (VM.VerifyAssertions) VM._assert(events == null); 433 events = engine.getEventChunk(); 434 if (events == null) { 435 // TODO: here is where we would need to record in the Feedlet's 436 // state that we had to drop an event. We would then later 437 // (when we got an event chunk back again) emit an event 438 // to indicate the number of events that were dropped due to 439 // an inability to obtain an event chunk. 440 return false; 441 } 442 events.reset(feedletIndex, sequenceNumber++); 443 return true; 444 } 445 446 @NoInline 447 private void flushEventChunk() { 448 if (events != null) { 449 events.close(); 450 engine.returnFullEventChunk(events); 451 events = null; 452 } 453 } 454}