1*27e8546dSMatt Gilbride# PerfMark 2*27e8546dSMatt Gilbride 3*27e8546dSMatt Gilbride 4*27e8546dSMatt Gilbride 5*27e8546dSMatt GilbridePerfMark is a low-overhead, manually-instrumented, tracing library for Java. Users can add the 6*27e8546dSMatt Gilbridetracing function calls to their code to see how long each part takes. 7*27e8546dSMatt Gilbride 8*27e8546dSMatt Gilbride## Features 9*27e8546dSMatt Gilbride 10*27e8546dSMatt Gilbride* **Very Low Overhead**: When enabled, tracing a function call adds about **70ns**. Tracing is 11*27e8546dSMatt Gilbride done in a lock-free, wait-free, thread local buffer, which avoids interfering with your 12*27e8546dSMatt Gilbride latency-sensitive code. 13*27e8546dSMatt Gilbride 14*27e8546dSMatt Gilbride* **Dynamically Enabled**: PerfMark can be enabled or disabled at runtime. When disabled, 15*27e8546dSMatt Gilbride PerfMark has *zero overhead*, taking advantage of the JIT compiler to remove the tracing. 16*27e8546dSMatt Gilbride 17*27e8546dSMatt Gilbride* **Inter-thread Communication**: Existing profilers have difficulty expressing which thread 18*27e8546dSMatt Gilbride wakes up and executes work on another thread. PerfMark allows users to express this 19*27e8546dSMatt Gilbride relationship explicitly, making for a clear picture of how code flows. 20*27e8546dSMatt Gilbride 21*27e8546dSMatt Gilbride* **Small Library Size**: The PerfMark tracing API is only *5 KB* in size, and has minimal 22*27e8546dSMatt Gilbride dependencies making it easy to include in other projects. If no backend for recording the trace 23*27e8546dSMatt Gilbride is present, the library safely disables itself. 24*27e8546dSMatt Gilbride 25*27e8546dSMatt Gilbride* **Multiple Java Versions**: The PerfMark API supports Java 6, making it easy to include on 26*27e8546dSMatt Gilbride older or constrained environments. Additionally, PerfMark includes optimized backends for 27*27e8546dSMatt Gilbride Java 6, Java 7, and Java 9. Each of these backends is automatically loaded at runtime 28*27e8546dSMatt Gilbride (if possible) and uses advanced JVM features for maximum speed. 29*27e8546dSMatt Gilbride 30*27e8546dSMatt Gilbride* **Chrome Trace Viewer Integration**: PerfMark can export to the Chrome Trace Event Format, 31*27e8546dSMatt Gilbride making it easy to view in your Web Browser. 32*27e8546dSMatt Gilbride 33*27e8546dSMatt Gilbride## Usage 34*27e8546dSMatt Gilbride 35*27e8546dSMatt GilbrideTo use PerfMark, add the following dependencies to your `build.gradle`: 36*27e8546dSMatt Gilbride``` 37*27e8546dSMatt Gilbridedependencies { 38*27e8546dSMatt Gilbride implementation 'io.perfmark:perfmark-api:0.25.0' 39*27e8546dSMatt Gilbride // Only needed for applications, not libraries. 40*27e8546dSMatt Gilbride implementation 'io.perfmark:perfmark-traceviewer:0.25.0' 41*27e8546dSMatt Gilbride} 42*27e8546dSMatt Gilbride``` 43*27e8546dSMatt Gilbride 44*27e8546dSMatt GilbrideOr in your `pom.xml`: 45*27e8546dSMatt Gilbride 46*27e8546dSMatt Gilbride``` 47*27e8546dSMatt Gilbride <dependency> 48*27e8546dSMatt Gilbride <groupId>io.perfmark</groupId> 49*27e8546dSMatt Gilbride <artifactId>perfmark-api</artifactId> 50*27e8546dSMatt Gilbride <version>0.25.0</version> 51*27e8546dSMatt Gilbride </dependency> 52*27e8546dSMatt Gilbride``` 53*27e8546dSMatt Gilbride 54*27e8546dSMatt GilbrideIn your code, add the PerfMark tracing calls like so: 55*27e8546dSMatt Gilbride 56*27e8546dSMatt Gilbride```java 57*27e8546dSMatt GilbrideMap<String, Header> parseHeaders(List<String> rawHeaders) { 58*27e8546dSMatt Gilbride try (TaskCloseable task = PerfMark.traceTask("Parse HTTP headers")) { 59*27e8546dSMatt Gilbride Map<String, String> headers = new HashMap<>(); 60*27e8546dSMatt Gilbride for (String rawHeader : rawHeaders) { 61*27e8546dSMatt Gilbride Header header = parseHeader(rawHeader); 62*27e8546dSMatt Gilbride headers.put(header.name(), header); 63*27e8546dSMatt Gilbride } 64*27e8546dSMatt Gilbride return headers; 65*27e8546dSMatt Gilbride } 66*27e8546dSMatt Gilbride} 67*27e8546dSMatt Gilbride 68*27e8546dSMatt Gilbride``` 69*27e8546dSMatt Gilbride 70*27e8546dSMatt GilbridePerfMark can also be used to record asynchronous work: 71*27e8546dSMatt Gilbride 72*27e8546dSMatt Gilbride```java 73*27e8546dSMatt GilbrideFuture<Response> buildResponse() { 74*27e8546dSMatt Gilbride try (TaskCloseable task = PerfMark.traceTask("Build Response")) { 75*27e8546dSMatt Gilbride Link link = PerfMark.linkOut(); 76*27e8546dSMatt Gilbride return executor.submit(() -> { 77*27e8546dSMatt Gilbride try (TaskCloseable task2 = PerfMark.traceTask("Async Response")) { 78*27e8546dSMatt Gilbride PerfMark.linkIn(link); 79*27e8546dSMatt Gilbride return new Response(/* ... */); 80*27e8546dSMatt Gilbride } 81*27e8546dSMatt Gilbride }); 82*27e8546dSMatt Gilbride } 83*27e8546dSMatt Gilbride} 84*27e8546dSMatt Gilbride``` 85*27e8546dSMatt Gilbride 86*27e8546dSMatt GilbrideTo view the traces in your browser, generate the HTML: 87*27e8546dSMatt Gilbride 88*27e8546dSMatt Gilbride```java 89*27e8546dSMatt Gilbride PerfMark.setEnabled(true); 90*27e8546dSMatt Gilbride PerfMark.event("My Task"); 91*27e8546dSMatt Gilbride TraceEventViewer.writeTraceHtml(); 92*27e8546dSMatt Gilbride``` 93*27e8546dSMatt Gilbride 94*27e8546dSMatt GilbrideThe output looks like: 95*27e8546dSMatt Gilbride 96*27e8546dSMatt Gilbride 97*27e8546dSMatt Gilbride 98*27e8546dSMatt Gilbride## Configuration 99*27e8546dSMatt GilbridePerfMark provides some System Properties that allow controlling how it initializes. These can be set 100*27e8546dSMatt Gilbrideby providing them as JVM arguments. (e.g. `-Dio.perfmark.PerfMark.startEnabled=true`) 101*27e8546dSMatt Gilbride 102*27e8546dSMatt Gilbride* `io.perfmark.PerfMark.startEnabled` controls if PerfMark starts enabled. This boolean property 103*27e8546dSMatt Gilbride makes it possible to start tracing calls immediately. This is helpful when it's difficult 104*27e8546dSMatt Gilbride to invoke `setEnabled()` on PerfMark before task tracing calls have started. 105*27e8546dSMatt Gilbride 106*27e8546dSMatt Gilbride* `io.perfmark.PerfMark.debug` controls if PerfMark can log initializing steps. This property 107*27e8546dSMatt Gilbride exists to disable class loading of the logger package (currently `java.util.logging`). If 108*27e8546dSMatt Gilbride the debug property is set, the logger settings still need to be configured to report the logs. 109*27e8546dSMatt Gilbride By default, all PerfMark logs use level `FINE` (SLF4J `DEBUG`) or lower, which means that they 110*27e8546dSMatt Gilbride usually need additional setup to print. 111*27e8546dSMatt Gilbride 112*27e8546dSMatt Gilbride In addition to initialization, the debug property controls if other tracing failures can be 113*27e8546dSMatt Gilbride logged. When calls involving deferred execution are used (e.g. 114*27e8546dSMatt Gilbride `startTask(T, StringFunction<T>)`), the String function provided may throw an exception. In 115*27e8546dSMatt Gilbride these cases, the exception is silently ignored. This makes it easy to ensure the start/stop 116*27e8546dSMatt Gilbride call parity is maintained. To view these failures, the debug property can be set to log such 117*27e8546dSMatt Gilbride problems. As above, the PerfMark logger should be configured as well to report these. 118*27e8546dSMatt Gilbride 119*27e8546dSMatt Gilbride## Versioning and API Stability 120*27e8546dSMatt Gilbride 121*27e8546dSMatt GilbridePerfMark uses Semantic Versioning, and thus will not break existing APIs within a minor version 122*27e8546dSMatt Gilbrideupdate. PerfMark may need to disable some functionality, and thus may need to make some tracing 123*27e8546dSMatt Gilbridecalls become No-ops. In such cases, it will remain safe to call these functions being recorded. 124*27e8546dSMatt Gilbride 125*27e8546dSMatt Gilbride## Users 126*27e8546dSMatt Gilbride 127*27e8546dSMatt GilbridePerfMark was designed originally for [gRPC](https://github.com/grpc/grpc-java). It is also used 128*27e8546dSMatt Gilbrideby [Zuul](https://github.com/Netflix/zuul). 129