Giter Site home page Giter Site logo

seafoam's Introduction

Seafoam

Seafoam is a tool for working with compiler graphs dumped by the GraalVM compiler, including the Graal JIT, Native Image, and Truffle.

The Ideal Graph Visualizer, or IGV, is the tool usually used to work with GraalVM compiler graphs. Seafoam aims to solve several problems with IGV. Unlike IGV, Seafoam:

  • has special passes to make Truffle graphs easier to read
  • is open source and can be used according to the MIT license
  • supports gzip-compressed BGV files
  • is able to some extent seek BGV files to load specific graphs without loading the rest of the file
  • has a command-line interface
  • can be used as a library
  • has easy PDF, SVG, PNG, Mermaid, and Markdown graph output
  • has data JSON output
  • is designed for accessibility
  • looks prettier, in our opinion

Admittedly, Seafoam does not yet have:

  • an interactive user interface
  • diffing of graphs
  • breaking of edges for very congested graphs
  • the same speed in rendering big graphs - Seafoam is best suited for looking at graphs before lowering, which is what language developers are usually doing, or use spotlight

Seafoam compared to IGV

Installation

macOS

% brew install graphviz
% gem install seafoam
% seafoam --version
seafoam 0.1

Ubuntu

% sudo apt-get install ruby graphviz
% gem install seafoam
% seafoam --version
seafoam 0.1

RedHat

% sudo yum install ruby graphviz
% gem install seafoam
% seafoam --version
seafoam 0.1

Quick-start demo

% seafoam examples/fib-java.bgv.gz:0 render

Getting compiler graphs

If you are just experimenting, there are example graphs such as examples/fib-java.bgv.gz.

This is just a quick summary - see more information on getting graphs out of compilers.

GraalVM for Java

% javac Fib.java
% java -XX:CompileOnly=::fib -Dgraal.Dump=:1 Fib 14

GraalVM Native Image

% native-image -H:Dump=:1 -H:MethodFilter=fib Fib

TruffleRuby and other Truffle languages

% ruby --experimental-options --engine.CompileOnly=fib --engine.Inlining=false --engine.OSR=false --vm.Dgraal.Dump=Truffle:1 fib.rb 14

You will usually want to look at the After TruffleTier graph.

Name syntax

When using a command-line interface, Seafoam refers to file.bgv[:graph][:node[-edge]], where file.bgv is a file, graph is a graph index, node is a node index, and to is another node index to form an edge from node to another node edge.

Note that a graph ID is an ID found in BGV files, but is not unique. A graph index is what we use in names, and is unique.

Use cases

Print information about a file

% seafoam examples/fib-java.bgv.gz info
BGV 7.0

To simplify automation use cases, you can also capture the output as JSON:

% seafoam --json examples/fib-java.bgv.gz info | jq --sort-keys
{
  "major_version": 7,
  "minor_version": 0
}

List graphs in a file

% seafoam examples/fib-java.bgv.gz list
examples/fib-java.bgv.gz:0  17:Fib.fib(int)/After parsing
examples/fib-java.bgv.gz:1  17:Fib.fib(int)/Before phase org.graalvm.compiler.phases.common.LoweringPhase
examples/fib-java.bgv.gz:2  17:Fib.fib(int)/After high tier
examples/fib-java.bgv.gz:3  17:Fib.fib(int)/After mid tier
examples/fib-java.bgv.gz:4  17:Fib.fib(int)/After low tier
...

To simplify automation use cases, you can also capture the output as JSON:

% seafoam --json examples/fib-java.bgv.gz list | jq --sort-keys
[
  {
    "graph_file": "examples/fib-java.bgv.gz",
    "graph_index": 0,
    "graph_name_components": [
      "17:Fib.fib(int)",
      "After parsing"
    ]
  },
  {
    "graph_file": "examples/fib-java.bgv.gz",
    "graph_index": 1,
    "graph_name_components": [
      "17:Fib.fib(int)",
      "Before phase org.graalvm.compiler.phases.common.LoweringPhase"
    ]
  },
  ...
]

Search for strings in a graph, or node or edge within a graph

% seafoam examples/fib-java.bgv.gz:0 search Start
examples/fib-java.bgv.gz:0:0  ...node_class":"org.graalvm.compiler.nodes.StartNode","name_template":"Start","inputs":[...
examples/fib-java.bgv.gz:0:0  ...piler.nodes.StartNode","name_template":"Start","inputs":[{"direct":true,"name":"state...

NB: This command is intended for interactive usage and as such, has no JSON output option.

Print edges of a graph, or node or edge within a graph

% seafoam examples/fib-java.bgv.gz:0 edges
21 nodes, 30 edges
% seafoam examples/fib-java.bgv.gz:0:13 edges
Input:
  13 (Call Fib.fib) <-() 6 (Begin)
  13 (Call Fib.fib) <-() 14 (FrameState Fib#fib Fib.java:20)
  13 (Call Fib.fib) <-() 12 (MethodCallTarget)
Output:
  13 (Call Fib.fib) ->() 18 (Call Fib.fib)
  13 (Call Fib.fib) ->(values) 14 (FrameState Fib#fib Fib.java:20)
  13 (Call Fib.fib) ->(values) 19 (FrameState Fib#fib Fib.java:20)
  13 (Call Fib.fib) ->(x) 20 (+)
% seafoam examples/fib-java.bgv.gz:0:13-20 edges
13 (Call Fib.fib) ->(x) 20 (+)

To simplify automation use cases, you can also capture the output as JSON:

% seafoam --json examples/fib-java.bgv.gz:0 edges | jq --sort-keys
{
  "edge_count": 30,
  "node_count": 21
}

seafoam --json examples/fib-java.bgv.gz:0 edges | jq --sort-keys
{
  "edge_count": 30,
  "node_count": 21
}

% seafoam --json examples/fib-java.bgv.gz:0:13 edges | jq --sort-keys
{
  "input": [
    {
      "from": {
        "id": "6",
        "label": "Begin"
      },
      "label": null,
      "to": {
        "id": "13",
        "label": "Call Fib.fib"
      }
    },
    ...
  ],
  "output": [
    {
      "from": {
        "id": "13",
        "label": "Call Fib.fib"
      },
      "label": null,
      "to": {
        "id": "18",
        "label": "Call Fib.fib"
      }
    },
    ...
  ]
}

% seafoam --json examples/fib-java.bgv.gz:0:13-20 edges | jq --sort-keys
[
  {
    "from": {
      "id": "13",
      "label": "Call Fib.fib"
    },
    "label": "x",
    "to": {
      "id": "20",
      "label": "+"
    }
  }
]

Print properties of a file, graph, or node or edge within a graph

% seafoam examples/fib-java.bgv.gz:0 props
{
  "group": [
    {
      "name": "17:Fib.fib(int)",
      "short_name": "17:Fib.fib(int)",
      "method": null,
...
% seafoam examples/fib-java.bgv.gz:0:13 props
{
  "relativeFrequency": 0.4995903151404586,
  "targetMethod": "Fib.fib",
  "nodeCostSize": "SIZE_2",
  "stamp": "i32",
  "bci": 10,
  "polymorphic": false,
...
% seafoam examples/fib-java.bgv.gz:0:13-20 props
{
  "direct": true,
  "name": "x",
  "type": "Value",
  "index": 0
}

NB: The output from the props command is always in JSON so there is no need to supply the --json flag.

Print node source information

For Truffle graphs you need to run with --engine.NodeSourcePositions to get useful source information. This only works on JVM or on Native when built with -H:+IncludeNodeSourcePositions, which isn't set by default.

% seafoam examples/fib-ruby.bgv.gz:2:2436 source
java.lang.Math#addExact
org.truffleruby.core.numeric.IntegerNodes$AddNode#add
org.truffleruby.core.numeric.IntegerNodesFactory$AddNodeFactory$AddNodeGen#executeAdd
org.truffleruby.core.inlined.InlinedAddNode#intAdd
org.truffleruby.core.inlined.InlinedAddNodeGen#execute
org.truffleruby.language.control.IfElseNode#execute
org.truffleruby.language.control.SequenceNode#execute
org.truffleruby.language.RubyMethodRootNode#execute
org.graalvm.compiler.truffle.runtime.OptimizedCallTarget#executeRootNode
org.graalvm.compiler.truffle.runtime.OptimizedCallTarget#profiledPERoot

To simplify automation use cases, you can also capture the output as JSON:

% seafoam --json examples/fib-ruby.bgv.gz:2:2436 source | jq --sort-keys
[
  {
    "class": "java.lang.Math",
    "method": "addExact"
  },
  {
    "class": "org.truffleruby.core.numeric.IntegerNodes$AddNode",
    "method": "add"
  },
  {
    "class": "org.truffleruby.core.numeric.IntegerNodesFactory$AddNodeFactory$AddNodeGen",
    "method": "executeAdd"
  },
  {
    "class": "org.truffleruby.core.inlined.InlinedAddNode",
    "method": "intAdd"
  },
  {
    "class": "org.truffleruby.core.inlined.InlinedAddNodeGen",
    "method": "execute"
  },
  {
    "class": "org.truffleruby.language.control.IfElseNode",
    "method": "execute"
  },
  {
    "class": "org.truffleruby.language.control.SequenceNode",
    "method": "execute"
  },
  {
    "class": "org.truffleruby.language.RubyMethodRootNode",
    "method": "execute"
  },
  {
    "class": "org.graalvm.compiler.truffle.runtime.OptimizedCallTarget",
    "method": "executeRootNode"
  },
  {
    "class": "org.graalvm.compiler.truffle.runtime.OptimizedCallTarget",
    "method": "profiledPERoot"
  }
]

Describe a graph

Describe the key features of a graph without rendering it.

% seafoam examples/fib-java.bgv.gz:1 describe
21 nodes, branches, calls

The graph description is a useful way to quickly catch unexpected or undesired attributes in a graph and makes comparing two graphs to each other straightforward. Such a comparison could be the basis of a regression test.

To simplify automation use cases, you can also capture the output as JSON:

% seafoam --json examples/fib-java.bgv.gz:1 describe | jq
{
  "branches": true,
  "calls": true,
  "deopts": false,
  "linear": false,
  "loops": false,
  "node_count": 21,
  "node_counts": {
    "AddNode": 3,
    "ConstantNode": 3,
    "FrameState": 3,
    "BeginNode": 2,
    "InvokeNode": 2,
    "MethodCallTargetNode": 2,
    "ReturnNode": 2,
    "IfNode": 1,
    "IntegerLessThanNode": 1,
    "ParameterNode": 1,
    "StartNode": 1
  }
}

Render a graph

Render a graph as a PDF image and have it opened automatically.

% seafoam examples/fib-java.bgv.gz:0 render

Render a graph showing just a few nodes and those surrounding them, similar to the IGV feature of gradually revealing nodes.

% seafoam examples/fib-java.bgv.gz:0 render --spotlight 13,20

render supports these options:

  • --out filename.pdf or .pdf, .svg, .png, .dot, .mmd, .md
  • --md
  • --option key value for pass options.

Convert a file

Convert a BGV file to the Isabelle graph format.

% bgv2isabelle examples/fib-java.bgv.gz
graph0 = # 2:Fib.fib(int)/After phase org.graalvm.compiler.java.GraphBuilderPhase
 (add_node 0 StartNode [2] [8]
 (add_node 1 (ParameterNode 0) [] [2, 5, 9, 11, 14, 16]
 (add_node 2 FrameState [1] [0]
 (add_node 3 (ConstantNode 1) [] []
 (add_node 4 (ConstantNode 2) [] [5]
 (add_node 5 IntegerLessThanNode [1, 4] [8]
 (add_node 6 BeginNode [8] [13]
 (add_node 7 BeginNode [8] [9]
 (add_node 8 IfNode [0, 5] [7, 6]
...

Convert a BGV file to JSON.

% bgv2json examples/fib-java.bgv.gz
graph0 = # 2:Fib.fib(int)/After phase org.graalvm.compiler.java.GraphBuilderPhase
 (add_node 0 StartNode [2] [8]
 (add_node 1 (ParameterNode 0) [] [2, 5, 9, 11, 14, 16]
 (add_node 2 FrameState [1] [0]
 (add_node 3 (ConstantNode 1) [] []
 (add_node 4 (ConstantNode 2) [] [5]
 (add_node 5 IntegerLessThanNode [1, 4] [8]
 (add_node 6 BeginNode [8] [13]
 (add_node 7 BeginNode [8] [9]
 (add_node 8 IfNode [0, 5] [7, 6]
...

Options for GraalVM graphs

  • --full-truffle-args shows full Truffle argument nodes, which are simplified by default
  • --show-frame-state shows frame state nodes, which are hidden by default
  • --no-simplify-alloc turns off the pass to create synthetic allocation nodes
  • --show-reachability-fences turns off the pass to hide reachability fences
  • --show-null-fields shows null fields to allocations, which are hidden by default
  • --show-pi shows pi nodes, which are hidden by default
  • --show-begin-end shows begin and end nodes, which are hidden by default
  • --hide-floating hides nodes that aren't fixed by control flow
  • --no-reduce-edges turns off the pass to reduce the number of edges by inlining simple nodes above their users
  • --no-simplify turns off passes that simplify the graph, except frame states are still hidden
  • --draw-blocks to draw basic block information if available

Debugging

Exception backtraces are printed if $DEBUG (-d) is set.

Use seafoam file.bgv debug to debug file parsing.

NB: This command is intended for interactive usage and as such, has no JSON output option.

More documentation

Frequently asked questions

Why is it called Seafoam?

GraalVM graphs are seas of nodes. Seafoam is a shade of green, and Seafoam was written at Shopify, which has green as a brand colour. Graphs can sometimes be very complicated, appearing like a foam without any structure - Seafoam tries to help you make sense of it all.

What do you mean by graphs, and seas or soups of nodes?

Graphs, as in edges and nodes, are the data structure some compilers use to represent your program while they're compiling it. It's a form of intermediate representation. Graphs are how the compiler understands the programs and if the compiler isn't doing what you want you need to look at the graph and make sense of it. Some graphs are loosely structured and large, making them like a sea or soup of nodes.

Doesn't reduce edges actually introduce more edges?

Yes, but they're shorter edges, and it achieves the intended effect of less edges crossing over the graph.

Related work

The graph layout algorithm we use, via Graphviz, is

IGV is the existing tool for working with Graal graphs. It uses a hierarchical layout algorithm, rather than the force directed algorithm we use when we use Graphviz. It's based on the NetBeans IDE platform. It's related to the C1 Visualiser, for control-flow graphs. The C1 Visualiser can also be used with Graal as the backend of Graal is similar enough to C1. IGV is closed-source and available under a proprietary licence.

Turbolizer is a similar tool for the intermediate representation in the V8 JavaScript compiler.

Author

Seafoam was written by Chris Seaton at Shopify, [email protected].

Citations

License

MIT

seafoam's People

Contributors

chrisseaton avatar cursedcoder avatar eregon avatar fbogsany avatar galderz avatar jenshenny avatar jjfumero avatar kethomassen avatar kipply avatar lillianz avatar mattco98 avatar mikepapadim avatar nirvdrum avatar shopify-rails[bot] avatar xrxr 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  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

seafoam's Issues

A way to get describe stats after passes

Currently the stats from seafoam render --describe seem to be before any passes are done, and so e.g.:

38 nodes, linear
ConstantNode: 12
LoadIndexedNode: 10
PiNode: 3
BoxNode$TrustedBoxedValue: 2
UnboxNode: 2
BoxNode$AllocatingBoxNode: 1
FixedGuardNode: 1
FrameState: 1
IntegerAddExactNode: 1
IntegerAddExactOverflowNode: 1
ParameterNode: 1
PiArrayNode: 1
ReturnNode: 1
StartNode: 1```

But there are actually no LoadIndexedNode in the rendered output (`seafoam render`).

It'd be nice if we run passes before describe, and then with the previously-mentioned flag to disable all passes we could get the same output as now.

We'll also need to ignore hidden nodes for `--describe`.

Phi "from" labels reference removed nodes

On Phi nodes, each incoming data edge is associated with a particular input to the Phi's associated Merge node. Seafoam renders a "from ID" label to denote which branch a value comes from, but sometimes node ID is hidden in the rendered graph.

For example:

image

This graph references nodes 14 and 16, which have been removed from the graph. In this case, these nodes are just End nodes (maybe this is always the case? I'm not familiar with Graal graph invariants):

image

Since these nodes are removed from the graph entirely, we can't simply update the label to reference the End's predecessor. Could we assume the Merge inputs are in the same order as the Phi inputs?

(In any case, not a big blocker for me. I'm content to manually rewrite the .dot files for the small graphs I'm working with.)

Add a graph diff tool

I want to be able to do

% seafoam examples/diff/added-truffle-profile-before.bgv.gz:4 render --diff examples/diff/added-truffle-profile-after.bgv.gz:4

And see nodes that haven't changed greyed out, removed nodes in red, added nodes in green, like a source code diff.

Example graph and start of implementation in https://github.com/Shopify/seafoam/tree/diff.

Mermaid support missing from --help menu

I was just looking to use Seafoam's support for Mermaid files and couldn't find any mention of it in seafoam --help. It should be a quick fix since the docs appear in the README.

Add option for automation-friendly output

I'm working on a tool that uses Seafoam internally, parsing the data returned by Seafoam on STDOUT. While that mostly works, I've run into a problem with the list command. It outputs two pieces of information, separated by some whitespace:

@out.puts "#{file}:#{index} #{parser.graph_name(graph_header)}"

Parsing the "#{file}:#{index} column can be slightly tricky because the filename may have : in it. E.g., a compilation of Truffle::RegexpOperations.match will include the qualified method name in the filename. I've had success splitting on the last :, but I'm not confident that'll hold up in the long-run.

Parsing the "#{parser.graph_name(graph_header)}" column is proving to be much trickier. Seafoam uses a /delimite to join the components of thegraph_name`:

def graph_name(graph_header)
groups_names = graph_header[:group].map { |g| g[:short_name] }
count = 0
name = graph_header[:format].sub(/%s/) do
arg = graph_header[:args][count]
count += 1
arg
end
components = groups_names + [name]
components.join('/')
end

Those components may have an / embedded in them, however, such as is the case with a JIT compiled regex. The phase name nested in a group may also have an /, such as "Call Tree/Before Inline". As a result, I can't split on / and reliably separate the phase name from the method name.

It would be helpful if there were a structured output format for the Seafoam commands. I'd suggest JSON since it's common, but I'd be happy with anything that will allow faithful representation of the values from the various commands. Parsing difficulties aside, having a machine-readable output format also means tooling won't break every time Seafoam changes the way it presents data to the user.

The Truffle language translator misses proper language detection

When looking at the graph generated by the following Ruby code:

def foo(a, b)
  a + b
end

vals = (1...100).to_a
100_000.times { foo(vals.sample, vals.sample) }

you'll see that the two arguments a and b are represented in the Seafoam's simplified output as T(8) and T(9). These should render as T(args[0]) and T(args[1]) using the language translator pass. However, the translator is failing to detect that these are correspond to a TruffleRuby method.

Undefined method `prepare_json` for using `bgv2json`

Been having some trouble using bgv2json, not sure I'm doing something wrong?

❯ bgv2json examples/fib-java.bgv.gz
seafoam: undefined method `prepare_json' for #<Seafoam::JSONWriter:0x000000011801d1a0 @out=#<IO:<STDOUT>>>

version info

# bgv2json --version
seafoam 0.15
# ruby -v
ruby 3.0.4p208 (2022-04-12 revision 3fa771dded) [x86_64-linux]

Add basic support for getting disassembly from CFG files

The BGV file format that Seafoam usually deals with is Graal's HIR (higher intermediate representation.) HIR is used for partial evaluation and most compiler phases. Graal's LIR (lower intermediate representation) is used for scheduling, register allocation, instruction selection, and code generation. The LIR equivalent of BGV files is CFG files.

CFG files can be viewed using the c1visualiser but it's unmaintained and it's a complex Netbeans application.

Instead of trying to use a disassembler from within Graal, maybe it's simpler to just use the CFG files, and add support for them to Seafoam.

Initial work in https://github.com/Shopify/seafoam/tree/cfg2asm. The idea is there would be a command like

% cfg2asm foo.cfg
...assembly code

Then we'd drop oracle/graal#2094.

You can get new CFG files using --vm.Dgraal.Dump --vm.Dgraal.PrintBackendCFG=true (see oracle/graal#2983.)

Seafoam won't render phases nested under a group

Capturing compiled methods from Graal includes a phase named "Before Inline" nested under "Call Tree" for any of the TruffleIR methods. seafoam ... list includes them in its output:

TruffleHotSpotCompilation-7241[Symbol#to_s].bgv:0  TruffleIR::Symbol#to_s()/Call Tree/Before Inline
TruffleHotSpotCompilation-7241[Symbol#to_s].bgv:1  TruffleIR::Symbol#to_s()/After phase org.graalvm.compiler.truffle.compiler.phases.inlining.AgnosticInliningPhase
TruffleHotSpotCompilation-7241[Symbol#to_s].bgv:2  TruffleIR::Symbol#to_s()/After Partial Evaluation
...

However, seafoam render for that phase always generates an empty graph:

digraph G {
  graph [bgcolor="white"];
}

I haven't looked into Seafoam's internals to see what's going on, so my suggestion of the issue affecting phases nested under groups may be incorrect. This is the only phase I've seen nested so far so I can't verify with others.

Less aggresive color for loads and side effects

I'm using:

def foo(s)
  /a/ =~ s
end

loop do
  foo("abc")
end

and

jt -u jvm-ce graph --method 'block in <main>' test.rb 

(needs oracle/truffleruby@master...eregon:jt-graph-vm-args)

And only showing after the LoopBegin and what follows.

Seafoam:
Screenshot from 2021-10-07 16-47-15

IGV:
Screenshot from 2021-10-07 16-47-31

I find the bright red from Seafoam to be aggressive on the eyes and hurting readability of the produced graph.
Red is usually used to bring attention but reading a field is nothing special and certainly not what's worth highlighting in this graph.
The colors from IGV seem much better there, I find it so much easier to see the control flow in IGV, and part of it is using red only for "big control flow" like loops (LoopBegin/LoopExit/LoopEnd), If, Merge, Return, Invoke.

Seafoam uses bright red for load/store fields, deopts, etc but those are all pretty much normal in the graph and I think not worth highlighting specifically.

Could you use a less strong color for load/store fields, etc?
I also thing Deopt TransferToInterpreter should be a different color, it's not really the same category as memory accesses.
I think non-inlined calls should remain red as those are typically what's expensive.

Add a changelog

Currently, the project does not have a changelog or GitHub releases. While one could look at the list of commits, it's not always clear what's going on. A changelog with high-level entries that describe what changes were made would be helpful.

Mermaid renderer can't handle some nodes

While generating Mermaid graphs with TruffleRuby 24.0.0 I ran into an instance where the output is not valid Mermaid syntax. I've extracted the problematic snippet from a larger graph:

flowchart TD
  node3("3 @{:declaring_class=>\"com.oracle.truffle.runtime.OptimizedCallTarget\", :method_name=>\"profiledPERoot\", :signature=>{:args=>[\"[Ljava/lang/Object;\"], :ret=>\"Ljava/lang/Object;\"}, :modifiers=>20}:0")

Write a command to convert a graph to pseudo-Ruby code

Reading and understanding graphs is hard - maybe reading pseudo-Ruby code would be easier.

$ seafoam decompile examples/fib-java.bgv:0
def fib(p0)
  if p0 < 2
    return p0
  else
    temp1 = Fib.fib(p0 - 1)
    temp2 = Fib.fib(p0 - 2)
    return temp1 - temp2
  end
end

Related work we can build from is this old Graal to JS backend https://www.davidleopoldseder.com/publications/aotjs_dsl_paper_authorversion.pdf.

I'd focus on Java graphs when getting started, as they're simpler.

Match up CFG architecture with Capstone architecture

CFG files contain the architecture and word-size (just grep in them), but we currently assume they're always AMD64 and then hardcode this for Capstone.

Add a mapping from known CFG architectures and word-sizes (probably just containing AMD64 for now) to Capstone architectures and give an error if the CFG uses any architecture of word-size that we don't support.

Make node source output stack trace clickable

Usually when we copy and paste something into Analyze > Stack Thread or Tread Dump in IntelliJ IDEA, the stacktrace is clickable to the location of the code.

Currently when you paste seafoam source output it looks like this:

Screen Shot 2021-09-21 at 3 50 23 PM

But in order to be clickable it should look something like this (right panel):

image
Image from JetBrain documentation on: Analyzing External Stack Traces

It seems to contain the full file name and line number.

I know that we currently don't have access to the specific line number, but would it still work with just the full file name?

PDF and PNG output needs a white background

The PDF and PNG output needs a white background - otherwise you can't see things like the basic block boxes. added #24.

Should be optional as it is sometimes very useful to be able to compose on top of another background.

Found by @nirvdrum.

Fix seafoam's CI for ubuntu

Seems like the Ubuntu build is failing on CI with this error on the setup ruby stage:

Error: The process '/opt/hostedtoolcache/Ruby/2.5.9/x64/bin/bundle' failed with exit code 16

simplify_alloc doesn't support nested clases

(m = /^(\w+(?:\[\])?)\[([0-9,]+)\]$/.match(value)) || raise(value)

Doesn't match for example Foo$Bar.

Should it just be:

(m = /^([\w\$]+(?:\[\])?)\[([0-9,]+)\]$/.match(value)) || raise(value)

Also raising with a better error message would be better.

@eregon

`describe` is somewhat broken in Seafoam 0.16

I noticed when running seafoam describe on some graphs I would get a cryptic error:

seafoam: comparison of Array with Array failed

Running with debug mode to get a real trace, I see:

> ruby -d -S seafoam /Users/nirvdrum/dev/workspaces/truffleruby-ws/truffleruby/TruffleHotSpotCompilation-
Exception `ArgumentError' at /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/lib/seafoam/graal/graph_description.rb:25 - comparison of Array with Array failed
Exception `ArgumentError' at /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/bin/seafoam:16 - comparison of Array with Array failed
/Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/lib/seafoam/graal/graph_description.rb:25:in `sort_by': comparison of Array with Array failed (ArgumentError)
	from /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/lib/seafoam/graal/graph_description.rb:25:in `sorted_node_counts'
	from /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/lib/seafoam/formatters/text.rb:11:in `format'
	from /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/lib/seafoam/commands.rb:414:in `block in describe'
	from <internal:kernel>:187:in `loop'
	from /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/lib/seafoam/commands.rb:372:in `describe'
	from /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/lib/seafoam/commands.rb:54:in `seafoam'
	from /Users/nirvdrum/.rubies/ruby-3.3.0/lib/ruby/gems/3.3.0/gems/seafoam-0.16/bin/seafoam:11:in `<top (required)>'
	from /Users/nirvdrum/.rubies/ruby-3.3.0/bin/seafoam:25:in `load'
	from /Users/nirvdrum/.rubies/ruby-3.3.0/bin/seafoam:25:in `<main>'

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.