Git Product home page Git Product logo

perfmark's Introduction

PerfMark

PerfMark Hummingbird

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 7 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.

  • 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:

dependencies {
    implementation 'io.perfmark:perfmark-api:0.27.0'
    // Only needed for applications, not libraries.
    implementation 'io.perfmark:perfmark-traceviewer:0.27.0'
}

Or in your pom.xml:

    <dependency>
      <groupId>io.perfmark</groupId>
      <artifactId>perfmark-api</artifactId>
      <version>0.27.0</version>
    </dependency>

In your code, add the PerfMark tracing calls like so:

Map<String, Header> parseHeaders(List<String> rawHeaders) {
  try (TaskCloseable task = PerfMark.traceTask("Parse HTTP headers")) {
    Map<String, String> headers = new HashMap<>();
    for (String rawHeader : rawHeaders) {
      Header header = parseHeader(rawHeader);
      headers.put(header.name(), header);
    }
    return headers;
  }
}

PerfMark can also be used to record asynchronous work:

Future<Response> buildResponse() {
  try (TaskCloseable task = PerfMark.traceTask("Build Response")) {
    Link link = PerfMark.linkOut();
    return executor.submit(() -> {
      try (TaskCloseable task2 = PerfMark.traceTask("Async Response")) {
        PerfMark.linkIn(link);
        return new Response(/* ... */);
      }
    });
  }
}

To view the traces in your browser, generate the HTML:

  PerfMark.setEnabled(true);
  PerfMark.event("My Task");
  TraceEventViewer.writeTraceHtml();

The output looks like:

PerfMark Trace View

Configuration

PerfMark provides some System Properties that allow controlling how it initializes. These can be set by providing them as JVM arguments. (e.g. -Dio.perfmark.PerfMark.startEnabled=true)

  • io.perfmark.PerfMark.startEnabled controls if PerfMark starts enabled. This boolean property makes it possible to start tracing calls immediately. This is helpful when it's difficult to invoke setEnabled() on PerfMark before task tracing calls have started.

  • io.perfmark.PerfMark.debug controls if PerfMark can log initializing steps. This property exists to disable class loading of the logger package (currently java.util.logging). If the debug property is set, the logger settings still need to be configured to report the logs. By default, all PerfMark logs use level FINE (SLF4J DEBUG) or lower, which means that they usually need additional setup to print.

    In addition to initialization, the debug property controls if other tracing failures can be logged. When calls involving deferred execution are used (e.g. startTask(T, StringFunction<T>)), the String function provided may throw an exception. In these cases, the exception is silently ignored. This makes it easy to ensure the start/stop call parity is maintained. To view these failures, the debug property can be set to log such problems. As above, the PerfMark logger should be configured as well to report these.

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. It is also used by Zuul.

perfmark's People

Contributors

adiprerepa avatar carl-mastrangelo avatar creamsoup avatar dependabot[bot] avatar ejona86 avatar ran-su avatar sullis avatar suztomo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

perfmark's Issues

Stop task from different thread?

Is it possible to stop a task from a different thread where it is started?

To simplify from the readme, something like this:

Future<Response> buildResponse() {
  PerfMark.startTask("Build Response");
    return executor.submit(() -> {
        PerfMark.stopTask("Build Response");
    });
}

(Background: I'm starting on the user thread but complete on a netty thread). Thanks!

build error

getting build error , below are errors

[root@4ff8f162987c perfmark]# ./gradlew build

FAILURE: Build failed with an exception.

* Where:
Build file '/perfmark/examples/build.gradle.kts' line: 39

* What went wrong:
* Could not resolve all dependencies for configuration ':perfmark-examples:perfmarkAgent'.
> Failed to calculate the value of task ':perfmark-examples:compileTestJava' property 'javaCompiler'.
   > SystemInfo is not supported on this operating system.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s

Allow configuring whether thread renames should be respected or make perfmark more scalable

We'd like to trace execution of RPCs on our frontend using perfmark.

For debugging purposes, our frontend renames a thread when work is scheduled on it. When the task starts executing, it looks at certain important fields and puts it in the thread name. This is to aid debugging when the process crashes. It allows trivially identifying which requests were running when the server died.

Right now, perfmark creates a new "row" whenever this happens. Sadly, this soon leads to an inability to load the traces in the browser as there will be too many threads.

A couple of options:

  • A configuration option to make perfmark ignore thread renames somehow.
  • A configuration option (or trace display option) to limit the history of traces. I believe that in any given 1 minute window there's not likely to have been too many threads active.
  • Something else...?

Bump PerfMark Min JDK to 8

There have been several things that I'd like to try out with PerfMark, that have have up till now been unavailable due to targetting JDK 6.

  • (JDK7) TaskCloseable should really extend AutoCloseable, not Closeable.
  • (JDK8) StringFunction supplier should extend Function, or better yet be removed
  • (JDK7) Working around Project Loom Thread and Thread local changes would be easier if ConcurrentLinkedDeque was available for ThreadLocal pooling.
  • (JDK7) Numerous things that would otherwise be too slow with reflection would be faster if MethodHandles were generally available.
  • JDK7 No access to ThreadLocalRandom (Android API level 21). Nice to do occasional cleanup work but not too often. Looks like it can be desugared.
  • JDK8 ThreadLocal.withInitial() and java.util.function.Supplier. Nice to have. Would have been nice to add the static method to subclasses of ThreadLocal to hide the parent static method.

I'll add more over time, but these are my wish list.

Cannot call TraceEventViewer

I am trying to implement PerfMark in netflix/zuul, in one of the examples. I added the dependency to the zuul-sample level build.gradle, but for some reason, I cannot call TraceEventViewer.writeTraceHtml();. Is there a reason for this? I'm kind of a newbie at PerfMark, and want to learn more about it.

Caused by: java.lang.NoClassDefFoundError

this is runtimeException :

 Caused by: java.lang.NoClassDefFoundError: Failed resolution of: [Ljava/nio/file/attribute/FileAttribute;
    at io.perfmark.traceviewer.TraceEventViewer.writeTraceHtml(TraceEventViewer.java:90)

Add some way to clear storage

Use case:
On a running program, I want to enable perfmark for a time, and write the trace data to a file.
Then later, I want to restart perfmark again and save a second set of trace data, not containing the trace data from the first time perfmark was activated.

To achieve this there should be some way to clear the Storage, but there is currently no way to this (as far as I could find).
The Storage.resetForTest() method does clear the storage but stops perfmark from properly tracing multiple treads afterwards.
Recording everything and splitting it up later is also not desirable, as this would cause perfmark to take up more and more memory with each use.

disabled perfmark still cost CPU

The SecretPerfMarkImpl$PerfMarkImpl.getGen() is called in every PerfMark methods and it supposed to be no cost after JIT. However, In our production environment, we are seeing some cost under this method, more specifically in the SecretMethodHandleGenerator$MethodHandleGenerator.getGeneration() method. The java6 and java7 packages are always included in our binaries, but the perfmark is rarely enable in the production environment.

The attached picture is a sample breakdown. The percent number in a block represents the CPU cost in that method itself and all methods it invokes.

Screenshot 2021-06-07 3 31 14 PM

The environment are a mix of jdk8 and jdk11.

FR: return if PerfMark.setEnabled changed values

In the use cases I've had, a server endpoint wants to turn on tracing for a while, then turn it off. If two threads both try to do this, neither one knows if it should be the one to turn it off at the end. It'd be nice if setEnabled returned true if the enabled bit changed.

Expose api for attaching and detaching Storage.localMarkHolder

Hi there. I know this project is primarily targeting java, but I was interested in using it with Kotlins Coroutines (Fibers).

One thing holding me back is that suspending methods in kotlin can pause and resume on a different thread than the one it was invoked on.

suspend fun doSomething(){

    PerfMark.startTask("doSomething")
    try {
        // The current method is suspended while 'longRunningOperation' is executed in
        // another thread.
        longRunningOperation()

        // The rest of the methods execution resumes on which ever thread
        // happens pick up the task from a fork join pool
    } finally {
        // Will not work correctly due to the thread local no longer being present.
        PerfMark.stopTask("doSomething")
    }
}

The coroutines API does provide ways to handle this but they would require access to the
thread local.

suspend fun doSomething(){

    PerfMark.startTask("doSomething")
    // The thread local context element is takes care of attaching and detaching
    // values to the current thread before executing the next block of code
    withContext(Storage.localMarkHolder.asContextElement()) {
        try {
            longRunningOperation()
        } finally {
            // Code is resumed on a different thread, but the coroutine dispatcher
            // took care of ensuring our thread local is present before execution.
            PerfMark.stopTask("doSomething")
        }
    }
}

We ran into the same issue previously with io.grpc.Context and were able to leverage the attach() and detach() APIs to get maintain the correct context on the thread during coroutine execution. GrpcContextElement.kt

Would exposing similar methods unnecessarily complicate PerkMarks internals? Ive considered using linkIn but I dont think it was designed with this particular use-case in mind.

Consider making PerfMark accept `Object` for tags

Changing PerfMark.createTag(Object name) instead of PerfMark.createTag(String name) would allowing the implementation to call toString() late in case PerfMark is disabled. Calling toString() is also kind of verbose, when it's trivial for PerfMark to call String.valueOf().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.