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    package org.mmtk.utility.deque;
014    
015    import org.mmtk.utility.Log;
016    import org.mmtk.utility.TracingConstants;
017    import org.mmtk.vm.VM;
018    import org.mmtk.utility.Constants;
019    
020    import org.vmmagic.pragma.*;
021    import org.vmmagic.unboxed.*;
022    
023    /**
024     * This supports <i>unsynchronized</i> enqueuing and dequeuing of tracing data
025     * and bulk processing of the buffer.
026     */
027    @Uninterruptible public class TraceBuffer extends LocalQueue
028      implements Constants, TracingConstants {
029    
030      /***********************************************************************
031       *
032       * Class based constants
033       */
034    
035      /**
036       *
037       */
038      private static final Word TRACE_NEW_RECORD = Word.fromIntSignExtend(3);
039      private static final Word TRACE_ALLOC_SIZE = Word.fromIntSignExtend(5);
040    //  private static final Word TRACE_ALLOC_NAME = Word.fromIntSignExtend(6);
041      private static final Word TRACE_ALLOC_FP = Word.fromIntSignExtend(7);
042      private static final Word TRACE_ALLOC_THREAD = Word.fromIntSignExtend(9);
043      private static final Word TRACE_TIB_VALUE = Word.fromIntSignExtend(10);
044      private static final Word TRACE_DEATH_TIME = Word.fromIntSignExtend(11);
045      private static final Word TRACE_FIELD_TARGET = Word.fromIntSignExtend(12);
046      private static final Word TRACE_ARRAY_TARGET = Word.fromIntSignExtend(13);
047      private static final Word TRACE_FIELD_SLOT = Word.fromIntSignExtend(14);
048      private static final Word TRACE_ARRAY_ELEMENT = Word.fromIntSignExtend(15);
049      private static final Word TRACE_STATIC_TARGET = Word.fromIntSignExtend(17);
050      private static final Word TRACE_BOOT_ALLOC_SIZE = Word.fromIntSignExtend(18);
051    
052      /*
053       * Debugging and trace reducing constants
054       */
055      public static final boolean OMIT_ALLOCS=false;
056      public static final boolean OMIT_UPDATES=false;
057      public static final boolean OMIT_BOOTALLOCS=false;
058      public static final boolean OMIT_UNREACHABLES=false;
059      public static final boolean OMIT_OTHERS=false;
060      public static final boolean OMIT_OUTPUT=OMIT_ALLOCS && OMIT_UPDATES &&
061                                              OMIT_OTHERS;
062    
063    
064      /***********************************************************************
065       *
066       * Public methods
067       */
068    
069      /**
070       * Constructor
071       *
072       * @param pool The shared queue to which this queue will append its
073       * buffers (when full or flushed) and from which it will aquire new
074       * buffers when it has exhausted its own.
075       */
076      public TraceBuffer(SharedDeque pool) {
077        super(pool);
078      }
079    
080      /**
081       * Push word onto the tracing queue.
082       *
083       * @param i The data to be pushed onto the tracing queue
084       */
085      @Inline
086      public final void push(Word i) {
087        checkTailInsert(1);
088        uncheckedTailInsert(i.toAddress());
089      }
090    
091      /**
092       * Process the data in the tracing buffer, output information as needed.
093       */
094      public final void process() {
095        Word traceState = TRACE_NEW_RECORD;
096        int entriesNotFlushed = 0;
097        boolean loggedRecord = false;
098        /* First we must flush any remaining data */
099        if (!OMIT_OUTPUT) Log.writeln();
100    
101        /* Process through the entire buffer. */
102        while (checkDequeue(1)) {
103          /* For speed and efficiency, we will actually process the data buffer by
104             buffer and not by dequeue-ing each entry. */
105          while (!bufferOffset(head).isZero()) {
106            head = head.minus(BYTES_IN_ADDRESS);
107            Word val = head.loadWord();
108            if (traceState.EQ(TRACE_NEW_RECORD)) {
109              loggedRecord = false;
110              if (val.EQ(TRACE_GCSTART)) {
111                if (!OMIT_OTHERS) {
112                  Log.write('G');
113                  Log.write('C');
114                  Log.writeln('B', true);
115                }
116              } else if (val.EQ(TRACE_GCEND)) {
117                if (!OMIT_OTHERS) {
118                  Log.write('G');
119                  Log.write('C');
120                  Log.writeln('E', true);
121                }
122              } else {
123                traceState = val;
124              }
125            } else {
126              if (traceState.EQ(TRACE_EXACT_ALLOC) ||
127                  traceState.EQ(TRACE_ALLOC)) {
128                if (!OMIT_ALLOCS) {
129                  Log.write((traceState.EQ(TRACE_EXACT_ALLOC)) ? 'A' : 'a');
130                  Log.write(' ');
131                  Log.write(val);
132                  loggedRecord = true;
133                }
134                traceState = TRACE_ALLOC_SIZE;
135              } else if (traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC) ||
136                         traceState.EQ(TRACE_IMMORTAL_ALLOC)) {
137                if (!OMIT_ALLOCS) {
138                  Log.write((traceState.EQ(TRACE_EXACT_IMMORTAL_ALLOC)) ? 'I' : 'i');
139                  Log.write(' ');
140                  Log.write(val);
141                  loggedRecord = true;
142                }
143                traceState = TRACE_ALLOC_SIZE;
144              } else if (traceState.EQ(TRACE_BOOT_ALLOC)) {
145                if (!OMIT_BOOTALLOCS) {
146                  Log.write('B');
147                  Log.write(' ');
148                  Log.write(val);
149                  loggedRecord = true;
150                }
151                traceState = TRACE_BOOT_ALLOC_SIZE;
152              } else if (traceState.EQ(TRACE_DEATH)) {
153                if (!OMIT_UNREACHABLES) {
154                  Log.write('D');
155                  Log.write(' ');
156                  Log.write(val);
157                  loggedRecord = true;
158                }
159                traceState = TRACE_DEATH_TIME;
160              } else if (traceState.EQ(TRACE_BOOT_ALLOC_SIZE)) {
161                if (!OMIT_BOOTALLOCS)
162                  Log.write(val);
163                traceState = TRACE_NEW_RECORD;
164              } else if (traceState.EQ(TRACE_ALLOC_SIZE)) {
165                if (!OMIT_ALLOCS)
166                  Log.write(val);
167                traceState = TRACE_ALLOC_FP;
168              } else if (traceState.EQ(TRACE_ALLOC_FP)) {
169                if (!OMIT_ALLOCS)
170                  Log.write(val);
171                traceState = TRACE_ALLOC_THREAD;
172              } else if (traceState.EQ(TRACE_ALLOC_THREAD)) {
173                if (!OMIT_ALLOCS)
174                  Log.write(val);
175                traceState = TRACE_NEW_RECORD;
176              } else if (traceState.EQ(TRACE_TIB_SET)) {
177                if (!OMIT_UPDATES) {
178                  Log.write('T');
179                  Log.write(' ');
180                  Log.write(val);
181                  loggedRecord = true;
182                }
183                traceState = TRACE_TIB_VALUE;
184              } else if (traceState.EQ(TRACE_STATIC_SET)) {
185                if (!OMIT_UPDATES) {
186                  Log.write('S');
187                  Log.write(' ');
188                  Log.write(val);
189                  loggedRecord = true;
190                }
191                traceState = TRACE_STATIC_TARGET;
192              } else if (traceState.EQ(TRACE_TIB_VALUE) ||
193                         traceState.EQ(TRACE_STATIC_TARGET)) {
194                if (!OMIT_UPDATES)
195                  Log.write(val);
196                traceState = TRACE_NEW_RECORD;
197              } else if (traceState.EQ(TRACE_DEATH_TIME)) {
198                if (!OMIT_UNREACHABLES)
199                  Log.write(val);
200                traceState = TRACE_NEW_RECORD;
201              } else if (traceState.EQ(TRACE_FIELD_SET) ||
202                         traceState.EQ(TRACE_ARRAY_SET)) {
203                if (!OMIT_UPDATES) {
204                  Log.write('U');
205                  Log.write(' ');
206                  Log.write(val);
207                  loggedRecord = true;
208                }
209                traceState = TRACE_FIELD_SLOT;
210              } else if (traceState.EQ(TRACE_FIELD_TARGET) ||
211                         traceState.EQ(TRACE_ARRAY_TARGET)) {
212                if (!OMIT_UPDATES)
213                  Log.write(val);
214                traceState = TRACE_NEW_RECORD;
215              } else if (traceState.EQ(TRACE_FIELD_SLOT) ||
216                         traceState.EQ(TRACE_ARRAY_ELEMENT)) {
217                if (!OMIT_UPDATES)
218                  Log.write(val);
219                traceState = TRACE_FIELD_TARGET;
220              } else {
221                VM.assertions.fail("Cannot understand directive!\n");
222              }
223              if (traceState.EQ(TRACE_NEW_RECORD) && loggedRecord) {
224                entriesNotFlushed++;
225                Log.writeln();
226              } else if (loggedRecord) {
227                  Log.write(' ');
228              }
229            }
230            if (entriesNotFlushed == 10) {
231              if (!OMIT_OUTPUT)
232                Log.flush();
233              entriesNotFlushed = 0;
234            }
235          }
236        }
237        resetLocal();
238      }
239    }