1 /* 2 * Copyright 2019 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.perfmark.java6; 18 19 import io.perfmark.impl.Generator; 20 import io.perfmark.impl.Mark; 21 import io.perfmark.impl.MarkHolder; 22 import java.util.AbstractCollection; 23 import java.util.ArrayDeque; 24 import java.util.ArrayList; 25 import java.util.Arrays; 26 import java.util.Collections; 27 import java.util.Deque; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Queue; 31 32 final class SynchronizedMarkHolder extends MarkHolder { 33 private static final long GEN_MASK = (1 << Generator.GEN_OFFSET) - 1; 34 35 private static final long START_N1S1_OP = Mark.Operation.TASK_START_N1S1.ordinal(); 36 private static final long START_N1S2_OP = Mark.Operation.TASK_START_N1S2.ordinal(); 37 private static final long STOP_N1S0_OP = Mark.Operation.TASK_END_N1S0.ordinal(); 38 private static final long STOP_N1S1_OP = Mark.Operation.TASK_END_N1S1.ordinal(); 39 private static final long STOP_N1S2_OP = Mark.Operation.TASK_END_N1S2.ordinal(); 40 private static final long EVENT_N1S1_OP = Mark.Operation.EVENT_N1S1.ordinal(); 41 private static final long EVENT_N1S2_OP = Mark.Operation.EVENT_N1S2.ordinal(); 42 private static final long EVENT_N2S2_OP = Mark.Operation.EVENT_N2S2.ordinal(); 43 private static final long LINK_OP = Mark.Operation.LINK.ordinal(); 44 private static final long TAG_N1S1_OP = Mark.Operation.TAG_N1S1.ordinal(); 45 private static final long TAG_KEYED_N0S2_OP = Mark.Operation.TAG_KEYED_N0S2.ordinal(); 46 private static final long TAG_KEYED_N1S1_OP = Mark.Operation.TAG_KEYED_N1S1.ordinal(); 47 private static final long TAG_KEYED_N2S1_OP = Mark.Operation.TAG_KEYED_N2S1.ordinal(); 48 49 private final int maxEvents; 50 private final long maxEventsMask; 51 52 // where to write to next 53 private long nIdx; 54 private long sIdx; 55 56 private final long[] nums; 57 private final String[] strings; 58 SynchronizedMarkHolder()59 SynchronizedMarkHolder() { 60 this(32768); 61 } 62 SynchronizedMarkHolder(int maxEvents)63 SynchronizedMarkHolder(int maxEvents) { 64 if (((maxEvents - 1) & maxEvents) != 0) { 65 throw new IllegalArgumentException(maxEvents + " is not a power of two"); 66 } 67 if (maxEvents <= 0) { 68 throw new IllegalArgumentException(maxEvents + " is not positive"); 69 } 70 this.maxEvents = maxEvents; 71 this.maxEventsMask = maxEvents - 1L; 72 this.nums = new long[maxEvents]; 73 this.strings = new String[maxEvents]; 74 } 75 writeNnss(long genOp, long n0, long n1, String s0, String s1)76 private void writeNnss(long genOp, long n0, long n1, String s0, String s1) { 77 nums[(int) (nIdx++ & maxEventsMask)] = n0; 78 nums[(int) (nIdx++ & maxEventsMask)] = n1; 79 strings[(int) (sIdx++ & maxEventsMask)] = s0; 80 strings[(int) (sIdx++ & maxEventsMask)] = s1; 81 nums[(int) (nIdx++ & maxEventsMask)] = genOp; 82 } 83 writeNss(long genOp, long n0, String s0, String s1)84 private void writeNss(long genOp, long n0, String s0, String s1) { 85 nums[(int) (nIdx++ & maxEventsMask)] = n0; 86 strings[(int) (sIdx++ & maxEventsMask)] = s0; 87 strings[(int) (sIdx++ & maxEventsMask)] = s1; 88 nums[(int) (nIdx++ & maxEventsMask)] = genOp; 89 } 90 writeNs(long genOp, long n0, String s0)91 private void writeNs(long genOp, long n0, String s0) { 92 nums[(int) (nIdx++ & maxEventsMask)] = n0; 93 strings[(int) (sIdx++ & maxEventsMask)] = s0; 94 nums[(int) (nIdx++ & maxEventsMask)] = genOp; 95 } 96 writeN(long genOp, long n0)97 private void writeN(long genOp, long n0) { 98 nums[(int) (nIdx++ & maxEventsMask)] = n0; 99 nums[(int) (nIdx++ & maxEventsMask)] = genOp; 100 } 101 writeNns(long genOp, long n0, long n1, String s0)102 private void writeNns(long genOp, long n0, long n1, String s0) { 103 nums[(int) (nIdx++ & maxEventsMask)] = n0; 104 nums[(int) (nIdx++ & maxEventsMask)] = n1; 105 strings[(int) (sIdx++ & maxEventsMask)] = s0; 106 nums[(int) (nIdx++ & maxEventsMask)] = genOp; 107 } 108 writeSs(long genOp, String s0, String s1)109 private void writeSs(long genOp, String s0, String s1) { 110 strings[(int) (sIdx++ & maxEventsMask)] = s0; 111 strings[(int) (sIdx++ & maxEventsMask)] = s1; 112 nums[(int) (nIdx++ & maxEventsMask)] = genOp; 113 } 114 115 @Override start( long gen, String taskName, String tagName, long tagId, long nanoTime)116 public synchronized void start( 117 long gen, String taskName, String tagName, long tagId, long nanoTime) { 118 writeNs(gen + START_N1S1_OP, nanoTime, taskName); 119 writeNs(gen + TAG_N1S1_OP, tagId, tagName); 120 } 121 122 @Override start(long gen, String taskName, long nanoTime)123 public synchronized void start(long gen, String taskName, long nanoTime) { 124 writeNs(gen + START_N1S1_OP, nanoTime, taskName); 125 } 126 127 @Override start(long gen, String taskName, String subTaskName, long nanoTime)128 public synchronized void start(long gen, String taskName, String subTaskName, long nanoTime) { 129 writeNss(gen + START_N1S2_OP, nanoTime, taskName, subTaskName); 130 } 131 132 @Override link(long gen, long linkId)133 public synchronized void link(long gen, long linkId) { 134 writeN(gen + LINK_OP, linkId); 135 } 136 137 @Override stop(long gen, long nanoTime)138 public synchronized void stop(long gen, long nanoTime) { 139 writeN(gen + STOP_N1S0_OP, nanoTime); 140 } 141 142 @Override stop( long gen, String taskName, String tagName, long tagId, long nanoTime)143 public synchronized void stop( 144 long gen, String taskName, String tagName, long tagId, long nanoTime) { 145 writeNs(gen + TAG_N1S1_OP, tagId, tagName); 146 writeNs(gen + STOP_N1S1_OP, nanoTime, taskName); 147 } 148 149 @Override stop(long gen, String taskName, long nanoTime)150 public synchronized void stop(long gen, String taskName, long nanoTime) { 151 writeNs(gen + STOP_N1S1_OP, nanoTime, taskName); 152 } 153 154 @Override stop(long gen, String taskName, String subTaskName, long nanoTime)155 public synchronized void stop(long gen, String taskName, String subTaskName, long nanoTime) { 156 writeNss(gen + STOP_N1S2_OP, nanoTime, taskName, subTaskName); 157 } 158 159 @Override event( long gen, String eventName, String tagName, long tagId, long nanoTime)160 public synchronized void event( 161 long gen, String eventName, String tagName, long tagId, long nanoTime) { 162 writeNnss(gen + EVENT_N2S2_OP, nanoTime, tagId, eventName, tagName); 163 } 164 165 @Override event(long gen, String eventName, long nanoTime)166 public synchronized void event(long gen, String eventName, long nanoTime) { 167 writeNs(gen + EVENT_N1S1_OP, nanoTime, eventName); 168 } 169 170 @Override event(long gen, String eventName, String subEventName, long nanoTime)171 public synchronized void event(long gen, String eventName, String subEventName, long nanoTime) { 172 writeNss(gen + EVENT_N1S2_OP, nanoTime, eventName, subEventName); 173 } 174 175 @Override attachTag(long gen, String tagName, long tagId)176 public synchronized void attachTag(long gen, String tagName, long tagId) { 177 writeNs(gen + TAG_N1S1_OP, tagId, tagName); 178 } 179 180 @Override attachKeyedTag(long gen, String name, long value0)181 public synchronized void attachKeyedTag(long gen, String name, long value0) { 182 writeNs(gen + TAG_KEYED_N1S1_OP, value0, name); 183 } 184 185 @Override attachKeyedTag(long gen, String name, String value)186 public synchronized void attachKeyedTag(long gen, String name, String value) { 187 writeSs(gen + TAG_KEYED_N0S2_OP, name, value); 188 } 189 190 @Override attachKeyedTag(long gen, String name, long value0, long value1)191 public synchronized void attachKeyedTag(long gen, String name, long value0, long value1) { 192 writeNns(gen + TAG_KEYED_N2S1_OP, value0, value1, name); 193 } 194 195 @Override resetForTest()196 public synchronized void resetForTest() { 197 Arrays.fill(nums, 0); 198 Arrays.fill(strings, null); 199 nIdx = 0; 200 sIdx = 0; 201 } 202 203 @Override read(boolean concurrentWrites)204 public List<Mark> read(boolean concurrentWrites) { 205 Kyoo<Long> numQ; 206 Kyoo<String> stringQ; 207 { 208 final long[] nums = new long[maxEvents]; 209 final String[] strings = new String[maxEvents]; 210 final long nIdx; 211 final long sIdx; 212 213 synchronized (this) { 214 System.arraycopy(this.nums, 0, nums, 0, maxEvents); 215 System.arraycopy(this.strings, 0, strings, 0, maxEvents); 216 nIdx = this.nIdx; 217 sIdx = this.sIdx; 218 } 219 Long[] numsBoxed = new Long[nums.length]; 220 for (int i = 0; i < nums.length; i++) { 221 numsBoxed[i] = nums[i]; 222 } 223 numQ = new Kyoo<Long>(numsBoxed, nIdx, (int) Math.min(nIdx, maxEvents)); 224 stringQ = new Kyoo<String>(strings, sIdx, (int) Math.min(sIdx, maxEvents)); 225 } 226 227 Deque<Mark> marks = new ArrayDeque<Mark>(maxEvents); 228 229 while (true) { 230 if (numQ.isEmpty()) { 231 break; 232 } 233 long genOp = numQ.remove(); 234 long gen = genOp & ~GEN_MASK; 235 Mark.Operation op = Mark.Operation.valueOf((int) (genOp & GEN_MASK)); 236 237 if (op.getNumbers() > numQ.size() 238 || op.getStrings() > stringQ.size()) { 239 break; 240 } 241 long n1; 242 String s1; 243 long n2; 244 String s2; 245 switch (op) { 246 case TASK_START_N1S1: 247 n1 = numQ.remove(); 248 s1 = stringQ.remove(); 249 marks.addFirst(Mark.taskStart(gen, n1, s1)); 250 break; 251 case TASK_START_N1S2: 252 n1 = numQ.remove(); 253 s2 = stringQ.remove(); 254 s1 = stringQ.remove(); 255 marks.addFirst(Mark.taskStart(gen, n1, s1, s2)); 256 break; 257 case TASK_END_N1S0: 258 n1 = numQ.remove(); 259 marks.addFirst(Mark.taskEnd(gen, n1)); 260 break; 261 case TASK_END_N1S1: 262 n1 = numQ.remove(); 263 s1 = stringQ.remove(); 264 marks.addFirst(Mark.taskEnd(gen, n1, s1)); 265 break; 266 case TASK_END_N1S2: 267 n1 = numQ.remove(); 268 s2 = stringQ.remove(); 269 s1 = stringQ.remove(); 270 marks.addFirst(Mark.taskEnd(gen, n1, s1, s2)); 271 break; 272 case EVENT_N1S1: 273 n1 = numQ.remove(); 274 s1 = stringQ.remove(); 275 marks.addFirst(Mark.event(gen, n1, s1)); 276 break; 277 case EVENT_N1S2: 278 n1 = numQ.remove(); 279 s2 = stringQ.remove(); 280 s1 = stringQ.remove(); 281 marks.addFirst(Mark.event(gen, n1, s1, s2)); 282 break; 283 case EVENT_N2S2: 284 n2 = numQ.remove(); 285 s2 = stringQ.remove(); 286 n1 = numQ.remove(); 287 s1 = stringQ.remove(); 288 marks.addFirst(Mark.event(gen, n1, s1, s2, n2)); 289 break; 290 case EVENT_N2S3: 291 throw new UnsupportedOperationException(); 292 case LINK: 293 n1 = numQ.remove(); 294 marks.addFirst(Mark.link(gen, n1)); 295 break; 296 case TAG_N0S1: 297 throw new UnsupportedOperationException(); 298 case TAG_N1S0: 299 throw new UnsupportedOperationException(); 300 case TAG_N1S1: 301 n1 = numQ.remove(); 302 s1 = stringQ.remove(); 303 marks.addFirst(Mark.tag(gen, s1, n1)); 304 break; 305 case TAG_KEYED_N0S2: 306 s2 = stringQ.remove(); 307 s1 = stringQ.remove(); 308 marks.addFirst(Mark.keyedTag(gen, s1, s2)); 309 break; 310 case TAG_KEYED_N1S1: 311 n1 = numQ.remove(); 312 s1 = stringQ.remove(); 313 marks.addFirst(Mark.keyedTag(gen, s1, n1)); 314 break; 315 case TAG_KEYED_N2S1: 316 n2 = numQ.remove(); 317 n1 = numQ.remove(); 318 s1 = stringQ.remove(); 319 marks.addFirst(Mark.keyedTag(gen, s1, n1, n2)); 320 break; 321 case NONE: 322 throw new UnsupportedOperationException(); 323 } 324 } 325 326 return Collections.unmodifiableList(new ArrayList<Mark>(marks)); 327 } 328 329 @Override maxMarks()330 public int maxMarks() { 331 return maxEvents; 332 } 333 334 private final class Kyoo<T> extends AbstractCollection<T> implements Queue<T> { 335 336 private final T[] elements; 337 private final long wIdx; 338 private final int size; 339 340 private int ri; 341 Kyoo(T[] elements, long wIdx, int size)342 Kyoo(T[] elements, long wIdx, int size) { 343 this.elements = elements; 344 this.wIdx = wIdx; 345 this.size = size; 346 } 347 348 @Override iterator()349 public Iterator<T> iterator() { 350 throw new UnsupportedOperationException(); 351 } 352 353 @Override size()354 public int size() { 355 return size - ri; 356 } 357 358 @Override offer(T t)359 public boolean offer(T t) { 360 throw new UnsupportedOperationException(); 361 } 362 363 @Override remove()364 public T remove() { 365 checkSize(); 366 return poll(); 367 } 368 369 @Override poll()370 public T poll() { 371 if (size() == 0) { 372 return null; 373 } 374 int rIdx = (int) (((wIdx - 1) - ri++) & maxEventsMask); 375 return elements[rIdx]; 376 } 377 378 @Override element()379 public T element() { 380 checkSize(); 381 return peek(); 382 } 383 384 @Override peek()385 public T peek() { 386 if (size() == 0) { 387 return null; 388 } 389 int rIdx = (int) (((wIdx - 1) - ri) & maxEventsMask); 390 return elements[rIdx]; 391 } 392 checkSize()393 private void checkSize() { 394 if (size() == 0) { 395 throw new IllegalStateException(); 396 } 397 } 398 } 399 } 400