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.impl; 18 19 import java.util.Arrays; 20 import javax.annotation.Nullable; 21 22 public final class Mark { 23 // TODO: make sure these match the values in Impl 24 public static final String NO_TAG_NAME = ""; 25 public static final long NO_TAG_ID = Long.MIN_VALUE; 26 public static final long NO_LINK_ID = Long.MIN_VALUE; 27 28 public static final long NO_NANOTIME = 0; 29 30 private static final long N0 = 0; 31 private static final String S0 = null; 32 33 private final long generation; 34 35 private final long n1; 36 private final long n2; 37 private final long n3; 38 39 @Nullable private final String s1; 40 @Nullable private final String s2; 41 @Nullable private final String s3; 42 43 private final Operation operation; 44 taskStart(long generation, long nanoTime, String name)45 public static Mark taskStart(long generation, long nanoTime, String name) { 46 return new Mark(nanoTime, N0, N0, name, S0, S0, generation, Operation.TASK_START_N1S1); 47 } 48 taskStart(long generation, long nanoTime, String name, String subName)49 public static Mark taskStart(long generation, long nanoTime, String name, String subName) { 50 return new Mark(nanoTime, N0, N0, name, subName, S0, generation, Operation.TASK_START_N1S2); 51 } 52 taskEnd(long generation, long nanoTime)53 public static Mark taskEnd(long generation, long nanoTime) { 54 return new Mark(nanoTime, N0, N0, S0, S0, S0, generation, Operation.TASK_END_N1S0); 55 } 56 taskEnd(long generation, long nanoTime, String name)57 public static Mark taskEnd(long generation, long nanoTime, String name) { 58 return new Mark(nanoTime, N0, N0, name, S0, S0, generation, Operation.TASK_END_N1S1); 59 } 60 taskEnd(long generation, long nanoTime, String name, String subName)61 public static Mark taskEnd(long generation, long nanoTime, String name, String subName) { 62 return new Mark(nanoTime, N0, N0, name, subName, S0, generation, Operation.TASK_END_N1S2); 63 } 64 event(long generation, long nanoTime, String name)65 public static Mark event(long generation, long nanoTime, String name) { 66 return new Mark(nanoTime, N0, N0, name, S0, S0, generation, Operation.EVENT_N1S1); 67 } 68 event(long generation, long nanoTime, String name, String subName)69 public static Mark event(long generation, long nanoTime, String name, String subName) { 70 return new Mark(nanoTime, N0, N0, name, subName, S0, generation, Operation.EVENT_N1S2); 71 } 72 event( long generation, long nanoTime, String taskName, String tagName, long tagId)73 public static Mark event( 74 long generation, long nanoTime, String taskName, String tagName, long tagId) { 75 return new Mark( 76 nanoTime, tagId, N0, taskName, tagName, S0, generation, Operation.EVENT_N2S2); 77 } 78 event( long generation, long nanoTime, String taskName, String subTaskName, String tagName, long tagId)79 public static Mark event( 80 long generation, 81 long nanoTime, 82 String taskName, 83 String subTaskName, 84 String tagName, 85 long tagId) { 86 return new Mark( 87 nanoTime, tagId, N0, taskName, subTaskName, tagName, generation, Operation.EVENT_N2S3); 88 } 89 tag(long generation, String tagName, long tagId)90 public static Mark tag(long generation, String tagName, long tagId) { 91 return new Mark(tagId, N0, N0, tagName, S0, S0, generation, Operation.TAG_N1S1); 92 } 93 tag(long generation, long tagId)94 public static Mark tag(long generation, long tagId) { 95 return new Mark(tagId, N0, N0, S0, S0, S0, generation, Operation.TAG_N1S0); 96 } 97 tag(long generation, String tagName)98 public static Mark tag(long generation, String tagName) { 99 return new Mark(N0, N0, N0, tagName, S0, S0, generation, Operation.TAG_N0S1); 100 } 101 keyedTag(long generation, String tagName, String value)102 public static Mark keyedTag(long generation, String tagName, String value) { 103 return new Mark(N0, N0, N0, tagName, value, S0, generation, Operation.TAG_KEYED_N0S2); 104 } 105 keyedTag(long generation, String tagName, long value)106 public static Mark keyedTag(long generation, String tagName, long value) { 107 return new Mark(value, N0, N0, tagName, S0, S0, generation, Operation.TAG_KEYED_N1S1); 108 } 109 keyedTag(long generation, String tagName, long value0, long value1)110 public static Mark keyedTag(long generation, String tagName, long value0, long value1) { 111 return new Mark(value0, value1, N0, tagName, S0, S0, generation, Operation.TAG_KEYED_N2S1); 112 } 113 link(long generation, long linkId)114 public static Mark link(long generation, long linkId) { 115 return new Mark(linkId, N0, N0, S0, S0, S0, generation, Operation.LINK); 116 } 117 withTaskName(String name)118 public Mark withTaskName(String name) { 119 switch (operation) { 120 case EVENT_N1S1: 121 case TASK_END_N1S1: 122 case TASK_START_N1S1: 123 return new Mark(n1, n2, n3, name, s2, s3, generation, operation); 124 case TASK_START_N1S2: 125 case TASK_END_N1S0: 126 case NONE: 127 case TASK_END_N1S2: 128 case EVENT_N1S2: 129 case EVENT_N2S2: 130 case EVENT_N2S3: 131 case LINK: 132 case TAG_N0S1: 133 case TAG_N1S0: 134 case TAG_N1S1: 135 case TAG_KEYED_N1S1: 136 case TAG_KEYED_N2S1: 137 case TAG_KEYED_N0S2: 138 throw new UnsupportedOperationException(); 139 } 140 throw new AssertionError(); 141 } 142 Mark( long n1, long n2, long n3, @Nullable String s1, @Nullable String s2, @Nullable String s3, long generation, Operation operation)143 private Mark( 144 long n1, 145 long n2, 146 long n3, 147 @Nullable String s1, 148 @Nullable String s2, 149 @Nullable String s3, 150 long generation, 151 Operation operation) { 152 if (operation == null) { 153 throw new NullPointerException("operation"); 154 } 155 this.operation = operation; 156 this.generation = generation; 157 158 if (operation == Operation.NONE) { 159 throw new IllegalArgumentException("bad operation"); 160 } 161 this.n1 = n1; 162 this.n2 = n2; 163 this.n3 = n3; 164 165 this.s1 = s1; 166 this.s2 = s2; 167 this.s3 = s3; 168 } 169 170 public enum OperationType { 171 NONE, 172 TASK_START, 173 TASK_END, 174 EVENT, 175 LINK, 176 TAG, 177 ; 178 } 179 180 public enum Operation { 181 NONE(OperationType.NONE, 0, 0), 182 /** startTask(String taskName) 1 long for nanoTime. */ 183 TASK_START_N1S1(OperationType.TASK_START, 1, 1), 184 /** startTask(String name, String subTaskName) 1 long for nanoTime. */ 185 TASK_START_N1S2(OperationType.TASK_START, 1, 2), 186 187 TASK_END_N1S0(OperationType.TASK_END, 1, 0), 188 TASK_END_N1S1(OperationType.TASK_END, 1, 1), 189 TASK_END_N1S2(OperationType.TASK_END, 1, 2), 190 191 EVENT_N1S1(OperationType.EVENT, 1, 1), 192 EVENT_N1S2(OperationType.EVENT, 1, 2), 193 /** Tagged event, since attach tags can't apply to events */ 194 EVENT_N2S2(OperationType.EVENT, 2, 2), 195 /** Tagged event, since attach tags can't apply to events */ 196 EVENT_N2S3(OperationType.EVENT, 2, 3), 197 198 LINK(OperationType.LINK, 1, 0), 199 200 /** An unkeyed tag that has a single string value. */ 201 TAG_N0S1(OperationType.TAG, 0, 1), 202 /** An unkeyed tag that has a single numeric value. */ 203 TAG_N1S0(OperationType.TAG, 1, 0), 204 /** 205 * An unkeyed tag that has a string and numeric value. The values are unrelated to each other. 206 */ 207 TAG_N1S1(OperationType.TAG, 1, 1), 208 209 TAG_KEYED_N1S1(OperationType.TAG, 1, 1), 210 211 TAG_KEYED_N2S1(OperationType.TAG, 2, 1), 212 213 TAG_KEYED_N0S2(OperationType.TAG, 0, 2), 214 ; 215 216 private final OperationType opType; 217 private final int longs; 218 private final int strings; 219 Operation(OperationType opType, int longs, int strings)220 Operation(OperationType opType, int longs, int strings) { 221 this.opType = opType; 222 this.longs = longs; 223 this.strings = strings; 224 assert longs <= maxNumbers(); 225 assert strings <= maxStrings(); 226 } 227 228 private static final Operation[] values = Operation.values(); 229 230 static { 231 assert values.length <= (1 << Generator.GEN_OFFSET); 232 } 233 getOpType()234 public OperationType getOpType() { 235 return opType; 236 } 237 getNumbers()238 public int getNumbers() { 239 return longs; 240 } 241 getStrings()242 public int getStrings() { 243 return strings; 244 } 245 maxNumbers()246 public static int maxNumbers() { 247 return 2; 248 } 249 maxStrings()250 public static int maxStrings() { 251 return 3; 252 } 253 maxMarkers()254 public static int maxMarkers() { 255 return 1; 256 } 257 valueOf(int code)258 public static Operation valueOf(int code) { 259 return values[code]; 260 } 261 } 262 getNanoTime()263 public long getNanoTime() { 264 switch (operation.opType) { 265 case TASK_START: 266 case TASK_END: 267 case EVENT: 268 return n1; 269 case NONE: 270 case LINK: 271 case TAG: 272 throw new UnsupportedOperationException(); 273 } 274 throw new AssertionError(operation.opType); 275 } 276 getGeneration()277 public long getGeneration() { 278 return generation; 279 } 280 getOperation()281 public Operation getOperation() { 282 return operation; 283 } 284 getTagStringValue()285 public String getTagStringValue() { 286 switch (operation) { 287 case TAG_N0S1: 288 case TAG_N1S1: 289 return s1; 290 case TAG_KEYED_N0S2: 291 case EVENT_N2S2: 292 return s2; 293 case EVENT_N2S3: 294 return s3; 295 case TAG_N1S0: 296 case NONE: 297 case TASK_START_N1S1: 298 case TASK_START_N1S2: 299 case TASK_END_N1S0: 300 case TASK_END_N1S1: 301 case TASK_END_N1S2: 302 case EVENT_N1S1: 303 case EVENT_N1S2: 304 case TAG_KEYED_N1S1: 305 case TAG_KEYED_N2S1: 306 case LINK: 307 throw new UnsupportedOperationException(); 308 } 309 throw new AssertionError(operation.opType); 310 } 311 getTagFirstNumeric()312 public long getTagFirstNumeric() { 313 switch (operation) { 314 case TAG_N1S0: 315 case TAG_N1S1: 316 case TAG_KEYED_N1S1: 317 case TAG_KEYED_N2S1: 318 return n1; 319 case EVENT_N2S2: 320 case EVENT_N2S3: 321 return n2; 322 case TAG_N0S1: 323 case TAG_KEYED_N0S2: 324 case NONE: 325 case TASK_START_N1S1: 326 case TASK_START_N1S2: 327 case TASK_END_N1S0: 328 case TASK_END_N1S1: 329 case TASK_END_N1S2: 330 case EVENT_N1S1: 331 case EVENT_N1S2: 332 case LINK: 333 throw new UnsupportedOperationException(); 334 } 335 throw new AssertionError(operation.opType); 336 } 337 getTagSecondNumeric()338 public long getTagSecondNumeric() { 339 switch (operation) { 340 case TAG_KEYED_N2S1: 341 return n2; 342 case TAG_N1S0: 343 case TAG_N1S1: 344 case TAG_KEYED_N1S1: 345 case EVENT_N2S2: 346 case EVENT_N2S3: 347 case TAG_N0S1: 348 case TAG_KEYED_N0S2: 349 case NONE: 350 case TASK_START_N1S1: 351 case TASK_START_N1S2: 352 case TASK_END_N1S0: 353 case TASK_END_N1S1: 354 case TASK_END_N1S2: 355 case EVENT_N1S1: 356 case EVENT_N1S2: 357 case LINK: 358 throw new UnsupportedOperationException(); 359 } 360 throw new AssertionError(operation.opType); 361 } 362 getTagKey()363 public String getTagKey() { 364 switch (operation) { 365 case TAG_KEYED_N0S2: 366 case TAG_KEYED_N1S1: 367 case TAG_KEYED_N2S1: 368 return s1; 369 case TAG_N1S1: 370 case TAG_N0S1: 371 case TAG_N1S0: 372 case NONE: 373 case TASK_START_N1S1: 374 case TASK_START_N1S2: 375 case TASK_END_N1S0: 376 case TASK_END_N1S1: 377 case TASK_END_N1S2: 378 case EVENT_N1S1: 379 case EVENT_N1S2: 380 case EVENT_N2S2: 381 case EVENT_N2S3: 382 case LINK: 383 throw new UnsupportedOperationException(); 384 } 385 throw new AssertionError(operation.opType); 386 } 387 getTaskName()388 public String getTaskName() { 389 switch (operation) { 390 case TASK_START_N1S1: 391 case TASK_START_N1S2: 392 case TASK_END_N1S1: 393 case TASK_END_N1S2: 394 case EVENT_N1S1: 395 case EVENT_N1S2: 396 case EVENT_N2S2: 397 case EVENT_N2S3: 398 return s1; 399 case NONE: 400 case LINK: 401 case TASK_END_N1S0: 402 case TAG_N0S1: 403 case TAG_N1S0: 404 case TAG_N1S1: 405 case TAG_KEYED_N0S2: 406 case TAG_KEYED_N1S1: 407 case TAG_KEYED_N2S1: 408 throw new UnsupportedOperationException(); 409 } 410 throw new AssertionError(operation); 411 } 412 getSubTaskName()413 public String getSubTaskName() { 414 switch (operation) { 415 case TASK_END_N1S2: 416 case TASK_START_N1S2: 417 case EVENT_N1S2: 418 case EVENT_N2S3: 419 return s2; 420 case TASK_START_N1S1: 421 case TASK_END_N1S0: 422 case TASK_END_N1S1: 423 case EVENT_N1S1: 424 case EVENT_N2S2: 425 case NONE: 426 case LINK: 427 case TAG_N0S1: 428 case TAG_KEYED_N0S2: 429 case TAG_KEYED_N1S1: 430 case TAG_KEYED_N2S1: 431 case TAG_N1S0: 432 case TAG_N1S1: 433 throw new UnsupportedOperationException(); 434 } 435 throw new AssertionError(operation); 436 } 437 getLinkId()438 public long getLinkId() { 439 switch (operation.opType) { 440 case LINK: 441 return n1; 442 case TASK_START: 443 case TASK_END: 444 case EVENT: 445 case NONE: 446 case TAG: 447 throw new UnsupportedOperationException(); 448 } 449 throw new AssertionError(operation.opType); 450 } 451 452 @Override equals(Object obj)453 public boolean equals(Object obj) { 454 if (!(obj instanceof Mark)) { 455 return false; 456 } 457 Mark that = (Mark) obj; 458 return equal(this.s1, that.s1) 459 && equal(this.s2, that.s2) 460 && equal(this.s3, that.s3) 461 && this.n1 == that.n1 462 && this.n2 == that.n2 463 && this.n3 == that.n3 464 && this.operation == that.operation 465 && this.generation == that.generation; 466 } 467 468 @Override hashCode()469 public int hashCode() { 470 return Arrays.hashCode(new Object[] {operation, s1, s2, s3, n1, n2, n3, generation}); 471 } 472 473 @Override toString()474 public String toString() { 475 return "Mark{" 476 + "operation=" 477 + operation 478 + ", " 479 + "s1=" 480 + s1 481 + ", " 482 + "s2=" 483 + s2 484 + ", " 485 + "s3=" 486 + s3 487 + ", " 488 + "n1=" 489 + n1 490 + ", " 491 + "n2=" 492 + n2 493 + ", " 494 + "n3=" 495 + n3 496 + ", " 497 + "generation=" 498 + generation 499 + "}"; 500 } 501 equal(T a, T b)502 static <T> boolean equal(T a, T b) { 503 return a == b || a.equals(b); 504 } 505 } 506