// This file is part of the Fuzion language implementation.
//
// The Fuzion language implementation is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, version 3 of the License.
//
// The Fuzion language implementation is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License along with The
// Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.
//
//
//
// -----------------------------------------------------------------------
//
//  Tokiwa Software GmbH, Germany
//
//  ASCIIdoc source of the Profiling Fuzion guide
//
// -----------------------------------------------------------------------

= Profiling Fuzion
The Fuzion Team <info@tokiwa.software>
:doctype: article
:description: Guide explaining how to use tooling to investigate Fuzion's performance
:sectanchors:
:url-repo: https://github.com/tokiwa-software/fuzion
:sectnums:
:icons: font
:toc: macro
:experimental:
:stem:

toc::[]

== About this Document

=== Audience

This document is intended to be used by anyone investigating the performance
of either the Fuzion compiler itself, or the performance of a Fuzion program.

It is expected of the reader to have general knowledge of Java, Fuzion, and
their toolchain, as well as being comfortable working with the UNIX command
line.

=== Conventions

This document follows the conventions generally used by the Fuzion project,
as documented elsewhere.

=== History

This document started out as a collection of notes following an internal
workshop on profiling Fuzion at Tokiwa Software GmbH, on the 30th of October,
2024.

== General Profiling Tools

This section describes general methods to do profiling, not specific to
Fuzion itself, but dedicated to the tools that we generally use when working
on Fuzion.

=== kbd:[Ctrl+\ ] in the JVM

When the JVM is running in the shell, kbd:[Ctrl+\ ] can be used to trigger a
diagnostics output generated by the JVM, including a stack trace. This can be
used especially if the Fuzion compiler seems to be stuck to figure out what it
is doing at the time of hitting kbd:[Ctrl+\ ]. Using the keyboard shortcut
multiple times in sequence can be used to assess whether the process is stuck
at doing the same thing, for example in an infinite loop, or whether progress is
made, but very slowly.

CAUTION: The Java JIT compiler does not necessarily generate a stack frame for
every method that can be called. This might cause the tip of the stack trace
to differ from the actual method that contains the current code.

=== Valgrind

https://valgrind.org/[Valgrind] is useful for profiling programs written in C.
This includes binaries generated by the C backend. Specifically, the `callgrind`
and `cachegrind` tools have proven to be useful, and it has been suggested by
workshop participants that `cachegrind` might have a better output even when
not looking at caching.

CAUTION: Valgrind interprets machine code, which causes a decrease in execution
time.

There exists a nice graphical interface to look at the files Valgrind produces,
called https://kcachegrind.sourceforge.net/html/Home.html[kcachegrind].

=== Method Counter

This technique can be used if a Java method has been identified that accounts
for a significant part of the processing time spent, but it is unclear why it
is called very often.

The first idea may be to make the method print a stack trace on every call.
This might be a lot of information, so the idea is to only print the stack
trace every stem:[2^n]-th invocation. To achieve this, add a method counter
and a way to print the stack trace like follows:

[source,java]
----
void example()
{
  cnt++;

  if (cnt & (cnt - 1) == 0)
    {
      Thread.dumpStack();
    }

  /* complex calculation */
}

static int cnt = 0;
----

=== Other Tools

Platform native profiling such as `perf` (on Linux) and `DTrace` (on BSD and
macOS) exist and can be used in some cases.

`strace` can be used to find blocking system calls.

== Fuzion-specific Tooling

=== Increased Verbosity

Slow performance in some stages of the Fuzion compilation process can be
spotted easily by passing `-verbose=1` or `-verbose=2` to the `fz` command.

=== `-XjavaProf`

IMPORTANT: The `-XjavaProf` option requires the
https://www.brendangregg.com/flamegraphs.html[`flamegraph.pl`] script to be
installed in your `PATH` to work properly.

Passing the `-XjavaProf` option to `fz` starts a profiler thread, which stops
all other running threads every ten milliseconds to create a JVM stack trace.
By default, a flamegraph visualization is created as an SVG file. This SVG
file is interactive, meaning parts of the graph can be clicked on if the SVG
viewer supports this (Firefox is one example of a viewer with support).

CAUTION: The Java JIT compiler does not necessarily generate a stack frame for
every method that can be called. This might cause the tip of the flamegraph
to differ from the actual method that contains the current code.

When given an additional path argument that ends in `.prof`, as in `fz
-XjavaProf=example.prof example.fz` a text file is created that contains a list
of all methods sampled and how many samples have been taken.

IMPORTANT: It is necessary that the argument ends in `.prof` for the output
to be in this described format.

=== Profiling Allocations

Similar to `-XjavaProf`, Fuzion has a simple profiler for allocations. This can
be enabled by uncommenting the related code section in the `dev.flang.util.ANY`
class.

CAUTION: This only accounts for allocations of objects that inherit from the
`ANY` class.

=== Profiling Fuzion Code

Valgrind can be used to profile binaries generated by the C backend.

The methods of profiling using the JVM can be used to profile Fuzion programs
running in the JVM backend.

TIP: Familiarize yourself with the name mangling that the backends do to
identify the Fuzion features.

=== What's Missing?

When multi-threaded code is more widespread in we will need some way of profiling
thread interactions, to see how communication between threads affects performance,
answering question such as: how long is thread A waiting on thread B.

During the workshop, it was suggested that Linux provided a way of doing so, but
this needs to be investigated.

A difficulty that needs to be considered are the vastly differing timescales with
some events happening microseconds apart from each other, and others happening on
a millisecond or even second scale.
