-
-
Save korniltsev/68afb0dd09c596b7fd0306fa8b14ba6b to your computer and use it in GitHub Desktop.
App.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io.pyroscope.http.Format; | |
import io.pyroscope.javaagent.Profiler; | |
import io.pyroscope.javaagent.PyroscopeAgent; | |
import io.pyroscope.javaagent.Snapshot; | |
import io.pyroscope.javaagent.api.Exporter; | |
import io.pyroscope.javaagent.api.Logger; | |
import io.pyroscope.javaagent.api.ProfilingScheduler; | |
import io.pyroscope.javaagent.config.Config; | |
import io.pyroscope.javaagent.impl.DefaultLogger; | |
import io.pyroscope.javaagent.impl.PyroscopeExporter; | |
import io.pyroscope.labels.Pyroscope; | |
import io.pyroscope.labels.LabelsSet; | |
import java.time.Instant; | |
import java.util.*; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
public class App { | |
public static final int N_THREADS = 8; | |
public static void main(String[] args) { | |
Config config = new Config.Builder() | |
.setApplicationName("demo.app{qweqwe=asdasd}") | |
.setServerAddress("http://localhost:4040") | |
.setFormat(Format.JFR) | |
.setLogLevel(Logger.Level.DEBUG) | |
.setLabels(mapOf("user", "tolyan")) | |
.build(); | |
DefaultLogger l = new DefaultLogger(Logger.Level.DEBUG, System.err); | |
PyroscopeExporter exporter = new PyroscopeExporter(config, l); | |
MyProfilingScheduler scheduler = new MyProfilingScheduler(exporter, l); | |
PyroscopeAgent.start( | |
new PyroscopeAgent.Options.Builder(config) | |
.setExporter(exporter) | |
.setScheduler(scheduler) | |
.build() | |
); | |
Pyroscope.setStaticLabels(mapOf("region", "us-east-1")); | |
new Thread(() -> { | |
while (true) { | |
scheduler.enable(); | |
try { | |
Thread.sleep(20_000); | |
} catch (InterruptedException e) { | |
Thread.currentThread().interrupt(); | |
break; | |
} | |
try { | |
scheduler.disable(); | |
Thread.sleep(20_000); | |
} catch (InterruptedException e) { | |
Thread.currentThread().interrupt(); | |
break; | |
} | |
} | |
}).start(); | |
appLogic(); | |
} | |
private static void appLogic() { | |
ExecutorService executors = Executors.newFixedThreadPool(N_THREADS); | |
for (int i = 0; i < N_THREADS; i++) { | |
executors.submit(() -> { | |
Pyroscope.LabelsWrapper.run(new LabelsSet("thread_name", Thread.currentThread().getName()), () -> { | |
while (true) { | |
try { | |
fib(32L); | |
} catch (InterruptedException e) { | |
Thread.currentThread().interrupt(); | |
break; | |
} | |
} | |
} | |
); | |
}); | |
} | |
} | |
private static Map<String, String> mapOf(String... args) { | |
Map<String, String> staticLabels = new HashMap<>(); | |
for (int i = 0; i < args.length; i += 2) { | |
staticLabels.put(args[i], args[i + 1]); | |
} | |
return staticLabels; | |
} | |
private static long fib(Long n) throws InterruptedException { | |
if (n == 0L) { | |
return 0L; | |
} | |
if (n == 1L) { | |
return 1L; | |
} | |
// Thread.sleep(100); | |
return fib(n - 1) + fib(n - 2); | |
} | |
private static class MyStdoutExporter implements Exporter { | |
@Override | |
public void export(Snapshot snapshot) { | |
System.out.printf("Export %d %d%n", snapshot.data.length, snapshot.labels.toByteArray().length); | |
} | |
} | |
private static class MyProfilingScheduler implements ProfilingScheduler, Runnable { | |
private final PyroscopeExporter exporter; | |
private final DefaultLogger log; | |
private boolean enabled = true; | |
private Thread myThread; | |
private Profiler profiler; | |
public MyProfilingScheduler(PyroscopeExporter exporter, DefaultLogger l) { | |
this.exporter = exporter; | |
this.log = l; | |
} | |
@Override | |
public void start(Profiler profiler) { | |
synchronized (this) { | |
this.profiler = profiler; | |
if (enabled) { | |
myThread = new Thread(this); | |
myThread.start(); | |
} | |
} | |
} | |
public void enable() { | |
log.log(Logger.Level.DEBUG, "enable"); | |
synchronized (this) { | |
if (enabled) { | |
return; | |
} | |
this.enabled = true; | |
if (this.profiler != null) { | |
if (myThread != null) { | |
throw new IllegalStateException(); | |
} | |
myThread = new Thread(this); | |
myThread.start(); | |
} | |
} | |
} | |
public void disable() throws InterruptedException { | |
log.log(Logger.Level.DEBUG, "disable"); | |
Thread t = myThread; | |
synchronized (this) { | |
if (!enabled) { | |
return; | |
} | |
if (t != null) { | |
t.interrupt(); | |
} | |
enabled = false; | |
} | |
if (t != null) { | |
log.log(Logger.Level.DEBUG, "joining"); | |
t.join(); | |
log.log(Logger.Level.DEBUG, "joined"); | |
} | |
} | |
@Override | |
public void run() { | |
while (true) { | |
if (Thread.currentThread().isInterrupted()) { | |
break; | |
} | |
Instant startTime = Instant.now(); | |
profiler.start(); | |
log.log(Logger.Level.DEBUG, "started at %s", startTime.toString()); | |
try { | |
Thread.sleep(2_000); | |
} catch (InterruptedException e) { | |
log.log(Logger.Level.DEBUG, "interrupted at %s", Instant.now().toString()); | |
profiler.stop(); | |
Thread.currentThread().interrupt(); | |
break; | |
} | |
profiler.stop(); | |
Instant endTime = Instant.now(); | |
log.log(Logger.Level.DEBUG, "stopped at %s", startTime.toString()); | |
exporter.export(profiler.dumpProfile(startTime, endTime)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment