| # PerfMark |
| |
|  |
| |
| PerfMark is a low-overhead, manually-instrumented, tracing library for Java. Users can add the |
| tracing function calls to their code to see how long each part takes. |
| |
| ## Features |
| |
| * **Very Low Overhead**: When enabled, tracing a function call adds about **70ns**. Tracing is |
| done in a lock-free, wait-free, thread local buffer, which avoids interfering with your |
| latency-sensitive code. |
| |
| * **Dynamically Enabled**: PerfMark can be enabled or disabled at runtime. When disabled, |
| PerfMark has *zero overhead*, taking advantage of the JIT compiler to remove the tracing. |
| |
| * **Inter-thread Communication**: Existing profilers have difficulty expressing which thread |
| wakes up and executes work on another thread. PerfMark allows users to express this |
| relationship explicitly, making for a clear picture of how code flows. |
| |
| * **Small Library Size**: The PerfMark tracing API is only *5 KB* in size, and has minimal |
| dependencies making it easy to include in other projects. If no backend for recording the trace |
| is present, the library safely disables itself. |
| |
| * **Multiple Java Versions**: The PerfMark API supports Java 6, making it easy to include on |
| older or constrained environments. Additionally, PerfMark includes optimized backends for |
| Java 6, Java 7, and Java 9. Each of these backends is automatically loaded at runtime |
| (if possible) and uses advanced JVM features for maximum speed. |
| |
| * **Chrome Trace Viewer Integration**: PerfMark can export to the Chrome Trace Event Format, |
| making it easy to view in your Web Browser. |
| |
| ## Usage |
| |
| To use PerfMark, add the following dependencies to your `build.gradle`: |
| - `io.perfmark:perfmark-api:0.21.0` |
| - `io.perfmark:perfmark-traceviewer:0.21.0` |
| |
| In your code, add the PerfMark tracing calls like so: |
| |
| ```java |
| Map<String, Header> parseHeaders(List<String> rawHeaders) { |
| PerfMark.startTask("Parse HTTP headers"); |
| try { |
| Map<String, String> headers = new HashMap<>(); |
| for (String rawHeader : rawHeaders) { |
| Header header = parseHeader(rawHeader); |
| headers.put(header.name(), header); |
| } |
| return headers; |
| } finally { |
| PerfMark.stopTask("Parse HTTP headers"); |
| } |
| } |
| |
| ``` |
| |
| PerfMark can also be used to record asynchronous work: |
| |
| ```java |
| Future<Response> buildResponse() { |
| PerfMark.startTask("Build Response"); |
| final Link link = PerfMark.linkOut(); |
| try { |
| return executor.submit(() -> { |
| PerfMark.startTask("Async Response"); |
| PerfMark.linkIn(link); |
| try { |
| return new Response(/* ... */); |
| } finally { |
| PerfMark.stopTask("Async Response"); |
| } |
| }); |
| } finally { |
| PerfMark.stopTask("Build Response"); |
| } |
| } |
| ``` |
| |
| To view the traces in your browser, generate the HTML: |
| |
| ```java |
| PerfMark.setEnabled(true); |
| PerfMark.startTask("My Task"); |
| } finally { |
| PerfMark.stopTask("My Task"); |
| } |
| TraceEventViewer.writeTraceHtml(); |
| } |
| ``` |
| |
| The output looks like: |
| |
|  |
| |
| |
| |
| ## Versioning and API Stability |
| |
| PerfMark uses Semantic Versioning, and thus will not break existing APIs within a minor version |
| update. PerfMark may need to disable some functionality, and thus may need to make some tracing |
| calls become No-ops. In such cases, it will remain safe to call these functions being recorded. |
| |
| ## Users |
| |
| PerfMark was designed originally for [gRPC](https://github.com/grpc/grpc-java). |