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