Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use FlatBuffers for cflamegraph files #31

Merged
merged 3 commits into from
Jul 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ visualization/node_modules/
/protobuf/src/main/gen/*
/visualization/static/js/generated/*
protobuf/generated/main/
/src/gen/
17 changes: 15 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
language: java
sudo: required # to install flatbuffers
jdk:
- openjdk8

install: true # skip installation
addons:
apt:
update: true
packages:
- git
- cmake
- make

before_install:
- chmod +x ./scripts/install-flatbuffers.sh
- ./scripts/install-flatbuffers.sh

install: true

script:
- ./gradlew compilePlugin
- ./gradlew test
- ./gradlew test -x :agent-test:test
- ./gradlew buildPlugin
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ https://plugins.jetbrains.com/plugin/10305-flamegraph-profiler
* [Hot Spots](#hot-spots)
* [Call Tree](#call-tree)
* [Detailed View of Thread](#detailed-view-of-thread)
* [Roadmap](#roadmap)
* [Contribution](#contribution)
* [Building from sources](#building-from-sources)

Expand Down Expand Up @@ -111,18 +110,30 @@ On this page you can see what was happening inside some thread. All method calls
You can see popup with detailed information about method if you place the cursor on the method (also there are parameters and return value if they were saved).
![](screenshots/thread.png)

## Roadmap
1. Start using [Cap'n Proto](https://capnproto.org/) instead of [Google Protobuf](https://github.com/google/protobuf) for client-server communications. This will speed up visualization and reduce memory consumption.
2. Add subsecond-offset heatmap

## Contribution
If you would like to contribute please ping me on telegram @lkornilova, there are plenty of tasks to do :)

If you have any suggestions, just [open an issue](https://github.com/kornilova-l/flamegraph-visualizer/issues)
If you have a suggestions or found a bug [open an issue]

## Building from sources
If only want to use plugin then you should simply install ready-to-use [jar](https://plugins.jetbrains.com/plugin/10305-flamegraph-profiler).

To build plugin from sources FlatBuffers compiler version 1.9.0 should be installed on the system.

For information on building and installing the compiler please refer to the [FlatBuffers Documentation] or follow
the instructions:
* Ubuntu:
```bash
$ git clone https://github.com/google/flatbuffers.git
$ cd flatbuffers
$ git checkout tags/v1.9.0
$ mkdir target
$ cd target
$ cmake .. -G "Unix Makefiles"
$ make
$ sudo mv flatc /usr/local/bin/
```

Windows:
```
gradlew compilePlugin
Expand All @@ -134,3 +145,6 @@ Linux:
./gradlew compilePlugin
./gradlew runIdea
```

[FlatBuffers Documentation]: https://google.github.io/flatbuffers/flatbuffers_guide_building.html
[open an issue]: https://github.com/kornilova-l/flamegraph-visualizer/issues
26 changes: 24 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import io.netifi.flatbuffers.plugin.tasks.FlatBuffers

buildscript {
ext.kotlin_version = '1.2.51'
repositories {
Expand Down Expand Up @@ -28,6 +30,8 @@ plugins {
id 'com.google.protobuf' version '0.8.6' apply false
id 'com.moowork.node' version '1.2.0'
id 'com.liferay.soy' version '3.1.6'
id "io.netifi.flatbuffers" version "1.0.4"
id 'idea'
}

allprojects {
Expand Down Expand Up @@ -56,6 +60,7 @@ configurations {

dependencies {
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.1'
compile group: 'com.github.davidmoten', name: 'flatbuffers-java', version: '1.9.0.1'
compile fileTree(dir: 'lib', include: ['com.jrockit.mc.flightrecorder_5.5.1.172852.jar'])
compile fileTree(dir: 'lib', include: ['com.jrockit.mc.common_5.5.1.172852.jar'])
compile fileTree(dir: 'lib', include: ['flight-recorder-parser-for-java-9.jar'])
Expand Down Expand Up @@ -113,8 +118,6 @@ task copyAgent(type: Copy, dependsOn: [':agent:agentJar', ':agent:proxyJar']) {
into 'build/classes/main'
}

task compilePlugin(dependsOn: [copyAgent, copyStatic]) {}

compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
Expand All @@ -126,6 +129,25 @@ compileTestKotlin {
}
}

flatbuffers {
flatcPath = '/usr/local/bin/flatc'
language = 'java'
}

task compileFlatBuffers(type: FlatBuffers) {
inputDir = file("src/main/flatbuffers")
outputDir = file("src/gen/java")
}

task compilePlugin(dependsOn: [copyAgent, copyStatic, compileFlatBuffers]) {}

sourceSets.main.java.srcDir file('src/gen/java')
idea {
module {
generatedSourceDirs += file('src/gen/java')
}
}

/* if have some problems with jmh - execute clean first */
jmh {
/* jmh Jar warns about duplicate dependencies
Expand Down
12 changes: 12 additions & 0 deletions scripts/install-flatbuffers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

mkdir dependencies
cd dependencies
git clone https://github.com/google/flatbuffers.git
cd flatbuffers
git checkout tags/v1.9.0
mkdir target
cd target
cmake .. -G "Unix Makefiles"
make
sudo mv flatc /usr/local/bin/
24 changes: 24 additions & 0 deletions src/main/flatbuffers/cflamegraph_schema.fbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace com.github.kornilova_l.flamegraph.cflamegraph;

// Contains the same information as flamegraph format

table Names {
class_names:[string];
method_names:[string];
descriptions:[string];
}

struct Node {
class_name_id:int; // -1 if class name is not set
method_name_id:int;
description_id:int; // -1 if description is not set
width:int; // cannot be 0
depth:int; // depth starts with 1
}

table Tree {
names:Names;
nodes:[Node];
}

root_type Tree;
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,48 @@ import java.io.File


/**
* Original flamegraph format consumes a lot of memory on disk and it takes more time to parse
* because it has lots of duplicate parts of call traces.
* Original flamegraph format consumes a lot of memory on disk and it takes more
* time to parse because it has lots of duplicate parts of call traces.
* cflamegraph (compressed flamegraph) solves this problem.
* It uses FlatBuffers for data serialization and does not duplicate
* class names, method names and descriptions.
*
* Header of file contains ids of class names, method names and descriptions.
* For example:
* C
* ClassName1 0
* ClassName2 1
* M
* method1 0
* method2 1
* D
* () 0
* (int)int 1
*
* Each line of cflamegraph contains information in following format:
* C=<class name id> M=<method name id> D=<description id> w=<width> d=<depth>
*
* C and D are optional.
* See schema in /src/main/flatbuffers/cflamegraph_schema.fbs
*
* Example:
* ._ _
* |c|d|___ _
* |b()____|e|_______ _
* |Class.a__________|f|
*
* --C-- 1
* Class 0
* --M-- 6
* a 0
* b 1
* c 2
* d 3
* e 4
* f 5
* --D-- 1
* () 0
* C0M0w100d1
* M1w40d2
* M2w5d3
* M3w5d3
* M4w5d2
* M5w5d1
*
* As you can see order of lines matters
* because if a call has bigger depth than previous it means that
* the call is a child of previous call.
* |c|d|____ _
* |void b()|e|_______ _
* |Class.a___________|f|
*
* In original flamegraph format this example would look like this:
* a;b;c 5
* a;b;d 5
* a;b 10
* a;b();c 5
* a;void b();d 5
* a;b() 10
* a;e 5
* a 50
* f 5
*
* In cflamegraph files strings are not duplicated and equal parts of stacktraces are also not duplicated.
* Serialized with flatbuffers tree will have following structure:
* Names: {
* classNames: ["Class"],
* methodNames: ["a", "b", "c", "d", "e", "f"],
* descriptions: ["()void"]
* }
* Tree: {
* nodes: [
* { class_name_id: 0, method_name_id: 0, width: 100, depth: 1 },
* { method_name_id: 1, description_id: 0, width: 40, depth: 2 },
* { method_name_id: 2, width: 5, depth: 3 },
* { method_name_id: 3, width: 5, depth: 3 },
* { method_name_id: 4, width: 5, depth: 2 },
* { method_name_id: 5, width: 5, depth: 1 }
* ]
* }
*
* Order of nodes matters.
* If a call has bigger depth than previous it means that the call is a child
* of previous call.
*
* Converter merges unmerged stacktraces.
*/
Expand Down
Loading