Compare commits

..
171 Commits
Author SHA1 Message Date
Jamie Wong 0414c2f617 1.15.1 2023-06-04 04:14:07 -07:00
Jamie Wong f23f65b3af Callgrind: Subposition compression and weight correction (#423)
This fixes a number of bugs with callgrind import. Dealing with this file format is a big pain because the documentation on https://www.valgrind.org/docs/manual/cl-format.html doesn't contain enough examples to disambiguate some of the behaviour, and because there's a fundamental impedance mismatch between call-trees and call-graphs.

In any case, after this PR, the behavior of callgrind file import is much better.
The file provided in #414 now imports correctly and, as far as I can tell, displays the same weights as what I see in KCacheGrind.

Some of the key changes:
- Implementing subposition compression. This was just a TODO in the code that was never implemented
- Fixing a misinterpretation of how `fe` and `fi` were intended to be used. Previously, I was using it to change the filename of a symbol, meaning that an `fi` or an `fe` line in the middle of a block describing costs for an `fn` would split a node in the call-graph into multiple nodes causing all manners of problems
- Fixing a bug where `cfn` was persisting beyond a single call, also resulting in call graph nodes being split when they shouldn't be

Fixes #414
2023-06-04 04:06:22 -07:00
Jamie Wong 8da9088ec1 Fix import from Chrome Devtools performance tab in Chrome >= 114 (#422)
The file format uses by Chrome Devtools performance tab periodically changes. It uses the Chrome trace event format (https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview).

This format, however, has two different types: one is `TraceEvent[]`, the other is `{traceEvents: traceEvent[]}`. The importer for non-Chrome devtools profiles already handled this, but the one for Chrome Devtools didn't because Chrome < 114 never used it. It seems like they changed the file format. This PR addresses that change.

Fixes #420
2023-06-03 22:35:13 -07:00
Jamie Wong 81a6f29ad1 1.15.0 2022-10-22 00:18:24 +08:00
Jamie Wong 263f7d513e Update package.json to use upstream version of uint8array-json-parser (#408)
In #385, I introduced a dependency on the `uint8array-json-parser` npm package, but used a fork because of a typescript error. This was resolved in evanw/uint8array-json-parser#1 and published as part of `uint8array-json-parser@0.0.2`. Let's use the upstream.

This also conveniently fixes a new typechecking error that was preventing deployment. The error looked like this:

```
src/import/utils.ts(2,26): error TS2306: File '\''/Users/jlfwong/code/speedscope/node_modules/uint8array-json-parser/uint8array-json-parser.ts'\'' is not a module.'
```

After updating to the upstream, the problem is fixed.
2022-10-22 00:12:45 +08:00
Jamie Wong 1bce806933 Replace fuzzy matching with exact substring matching for finding matching frames (#407)
In #297, I re-used the fuzzy matching logic I implemented in #282 for profile selection. Based on feedback from several people in #352, this is surprising behavior.

Upon reflection, this should have been obvious -- I hijacked the Ctrl/Cmd+F browser behaviour, so I should try to replicate the expected behaviour there as closely as possible. Given more patience, I also would've done some user research :)

This PR updates this logic to try to more closely match browser behaviour. This means case-insensitive, exact-substring matching.

I've left the fuzzy matching alone for profile selection since that doesn't attempt to mimic browser behaviour.

The non-fuzzy matching feels slightly odd to me given the filtering behaviour on the sandwich view, but I think consistency across this find UI is important.

Here are the before & after results when searching for the string "ca" in the example profile.

|Before|After|
|-|-|
|<img width="1791" alt="image" src="https://user-images.githubusercontent.com/150329/197232741-6d1d7a8a-8b8c-4a4f-98e3-2c043fd7efd5.png">|<img width="1789" alt="image" src="https://user-images.githubusercontent.com/150329/197232694-82697b68-ca15-49e7-887b-2606646ee5e9.png">|

Fixes #352 
Supersedes #403
2022-10-21 23:53:46 +08:00
Jamie Wong 6493c5f66f Update deploy script to python3 2022-07-30 23:20:36 -07:00
Evan Wallace 639dae322b Add support for cycle-based Instruments deep copy (#400)
Unlike the Time Profiler, the CPU Profiler in Instruments use `cycles` for units instead of `ms`:

<img width="872" src="https://user-images.githubusercontent.com/406394/175755999-289cb7c0-f29a-44b1-b00e-b55ef17ee303.png">

Currently Speedscope fails to import the data with the following error in the console:

```
Failed to load format Error: Unrecognized units Gc
```

This PR adds support for `cycles` as a unit to the Instruments deep copy importer as well as `Kc`, `Mc`, and `Gc`, which I'm assuming are increasing in multiples of 1000. Hopefully I've added support for this correctly and this PR is helpful.
2022-07-02 22:01:08 -04:00
Jamie Wong 33a8f3f313 1.4.0
Node.js CI / test (10.x) (push) Has been cancelled
Node.js CI / test (12.x) (push) Has been cancelled
Node.js CI / test (14.x) (push) Has been cancelled
Node.js CI / finish (push) Has been cancelled
2022-05-19 01:37:56 -07:00
Jamie Wong 7ae545a6c3 Improve HoverTip placement logic (#395)
This changes the HoverTip placement logic to use measurements from the actual DOM node rather than basing everything on the maximum sizes.

This avoids some counter-intuitive behaviour, most importantly situations where the label would overflow off the left side of the screen for no obvious reason.

Fixes #394
Fixes #256
2022-05-17 13:42:13 -07:00
David Judd 48d692c2a3 Add a hash param to control view-mode (#362)
e.g. "view=left-heavy", "view=sandwich"

Fixes #355
2022-05-17 00:15:51 -07:00
Alex Coco ca8fcb48cc Support stackprof object mode (#391)
This PR attempts to support stackprof's object mode which tracks the number of allocated objects. This differs from the other modes (cpu and wall) by taking samples every time a Ruby object is allocated using Ruby's [`NEWOBJ` tracepoint](https://github.com/tmm1/stackprof/blob/df24b85953bb45d3abff58d9c82169a3003a60f1/ext/stackprof/stackprof.c#L198-L199).

When importing an object mode profile into speedscope today it still works but what you see is a profile using time units. The profile will only have samples for when an object was allocated which means even if time is reported, the profile is not really meaningful when looking at time.

To address this I've done three things when `mode` is `object`:
+ adjusted the total size of the `StackListProfileBuilder` to use the number of samples (since each sample is one allocation)
+ adjusted the weight of each sample to be `nSamples` (which I believe is always `1` but I'm not positive)
+ do not set the value formatter to a time formatter

Here's what it looks like before and after my changes (note the units and weight of samples):

wall (before) | object (before) | object (after)
-- | -- | --
<img width="1624" alt="Screen Shot 2022-05-11 at 4 51 31 PM" src="https://user-images.githubusercontent.com/898172/167945635-2401ca73-4de7-4559-b884-cf8947ca9738.png"> | <img width="1624" alt="Screen Shot 2022-05-11 at 4 51 34 PM" src="https://user-images.githubusercontent.com/898172/167945641-ef302a60-730b-4afd-8e44-5f02e54b3cb7.png"> | <img width="1624" alt="Screen Shot 2022-05-11 at 4 51 42 PM" src="https://user-images.githubusercontent.com/898172/167945643-5611b267-f8b2-4227-a2bf-7145c4030aa2.png">

<details>
<summary>Test code</summary>

```ruby
require 'stackprof'
require 'json'

def do_test
  5.times do
    make_a_word
  end
end

def make_a_word
  ('a'..'z').to_a.shuffle.map(&:upcase).join
end

StackProf.start(mode: :object, interval: 1, raw: true)
do_test
StackProf.stop

File.write('tmp/object_profile.json', JSON.generate(StackProf.results))

StackProf.start(mode: :wall, interval: 1, raw: true)
do_test
StackProf.stop

File.write('tmp/wall_profile.json', JSON.generate(StackProf.results))
```
</details>
2022-05-17 00:05:49 -07:00
Dan Vanderkam 63f3bc0395 Support relative URLs (#357)
Fixes #312 

This turns out not to be very deep: you have to pass an optional second parameter to the [`URL` constructor](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) to resolve relative URLs.

```
> new URL('/path/to/file#hashcode').pathnaem
VM252:1 Uncaught TypeError: Failed to construct 'URL': Invalid URL
    at <anonymous>:1:1
(anonymous) @ VM252:1
> new URL('/path/to/file#hashcode', 'http://example.com/').pathname
"/path/to/file"
```
2022-05-17 00:01:02 -07:00
Tobias Koppers 1ac88cc09a add file and line information (#365)
* add file and line to tooltips
* add file and line to anonymous methods

## Before:

![image](https://user-images.githubusercontent.com/1365881/134863173-0d5635e8-1884-4276-a2cc-b0b7af5a579b.png)

![image](https://user-images.githubusercontent.com/1365881/134863456-f56aca3b-2742-4194-ba1e-823ff871a316.png)

While you was able to get this info with clicking in "Time Order" and "Left Heavy" view, it was impossible to receive in the sandwich view.

## After:

![image](https://user-images.githubusercontent.com/1365881/134863282-6719db20-e528-4eb5-b876-b35f99c34da4.png)

![image](https://user-images.githubusercontent.com/1365881/134863365-b6a550d4-56d8-4cf0-a17f-f682f1d2fe57.png)
2022-05-16 23:59:17 -07:00
Jamie Wong 9a2c2a270b Add PHP import instructions (fixes #368) 2022-05-16 23:24:14 -07:00
Jamie Wong 229d48eca5 Update README-zh_CN.md to reflect changes in 103db68 2022-05-16 23:18:11 -07:00
Joe Rickerby 103db681d2 Add link to pyinstrument wiki page (#377) 2022-05-16 23:14:25 -07:00
Jamie Wong 21167e69d8 Support importing profiles whose contents exceed V8s maximum string size (#385)
Browsers have a limit on how big you can make strings. In Chrome on a 64 bit machine, this is around 512MB, which explains why in #340, a 600MB file fails to load.

To work around this issue, we avoid making strings this large.

To do so, we need two core changes:
1. Instead of sending large strings as the import mechanism to different file format importers, we introduce a new `TextFileContent` interface which exposes methods to get the lines in the file or the JSON representation. In the case of line splitting, we assume that no single line exceeds the 512MB limit.
2. We introduce a dependency on https://github.com/evanw/uint8array-json-parser to allow us to parse JSON files contained in `Uint8Array` objects

To ensure that this code doesn't code rot without introducing 600MB test files or test file generation into the repository, we also re-run a small set of tests with a mocked maximum string size of 100 bytes. You can see that the chunked string representation code is getting executed via test coverage.

Fixes #340
2022-05-16 23:11:13 -07:00
轩灵 e37f6fa7c3 Add README-zh_CN.md file (#364) 2021-09-22 11:20:25 -07:00
Daniel Giger 6d02bf510f Fix typo in README (#360) 2021-08-09 23:20:20 -07:00
Jamie Wong b71cef5db4 Bump TypeScript to 4.3.2 (#343)
* Bump TypeScript to 4.3.2

* Bump eslint deps

* Fix eslint errors from upgrade
2021-03-28 16:08:15 -07:00
Jamie Wong e6351a3c22 Remove accidentally checked-in vscode settings 2021-03-28 15:32:09 -07:00
Gabriele N. Tornetta 36aebfbda6 Allow collapsed stacks with invalid lines (#336)
Ingest files containing collapsed stacks and tolerate invalid lines,
like FlameGraph does.

Some files might contain lines starting with a # to add comments to the
collected samples. Speedscope should still attempt to parse these files
as collapsed stacks and only keep the samples that it can find. Only
fail if there are no samples reported.
2021-03-28 15:30:36 -07:00
Jamie Wong 246fc3dd5d Remove redux in favor of a small recoil-inspired "atom" library (#341)
This is an experiment in replacing redux entirely with a tiny library I wrote for global application state management.

Redux has been okay, but all of the redux actions in speedscope are setters, which always made me think there must be a simpler way. This is an attempt to find that simpler way.

See `src/lib/atom.ts` for the library.
2021-03-28 02:44:43 -07:00
Gabriele N. Tornetta d6f5efa06c fix(search): allow paste in search box (#338) 2021-03-27 15:05:16 -07:00
Jamie Wong 03a5104317 1.13.0 2021-02-14 23:36:12 -08:00
Jamie Wong 7dcfab1bbc Update a few remaining references to amster (#333)
Fixes #332
2021-02-14 23:31:33 -08:00
Jamie Wong 24b60dfd4a Callgrind import format support (#331)
Implements import from the [callgrind format](https://www.valgrind.org/docs/manual/cl-format.html).

This comes with a big caveat that the call graph information contained with callgrind formatted files don't uniquely define a flamegraph, so the generated flamegraph is a best-effort guess. Here's the comment from the top of the main file for the callgrind importer with an examplataion:

```
// https://www.valgrind.org/docs/manual/cl-format.html
//
// Larger example files can be found by searching on github:
// https://github.com/search?q=cfn%3D&type=code
//
// Converting callgrind files into flamegraphs is challenging because callgrind
// formatted profiles contain call graphs with weighted nodes and edges, and
// such a weighted call graph does not uniquely define a flamegraph.
//
// Consider a program that looks like this:
//
//    // example.js
//    function backup(read) {
//      if (read) {
//        read()
//      } else {
//        write()
//      }
//    }
//
//    function start() {
//       backup(true)
//    }
//
//    function end() {
//       backup(false)
//    }
//
//    start()
//    end()
//
// Profiling this program might result in a profile that looks like the
// following flame graph defined in Brendan Gregg's plaintext format:
//
//    start;backup;read 4
//    end;backup;write 4
//
// When we convert this execution into a call-graph, we get the following:
//
//      +------------------+     +---------------+
//      | start (self: 0)  |     | end (self: 0) |
//      +------------------+     +---------------|
//                   \               /
//        (total: 4)  \             / (total: 4)
//                     v           v
//                 +------------------+
//                 | backup (self: 0) |
//                 +------------------+
//                    /            \
//       (total: 4)  /              \ (total: 4)
//                  v                v
//      +----------------+      +-----------------+
//      | read (self: 4) |      | write (self: 4) |
//      +----------------+      +-----------------+
//
// In the process of the conversion, we've lost information about the ratio of
// time spent in read v.s. write in the start call v.s. the end call. The
// following flame graph would yield the exact same call-graph, and therefore
// the exact sample call-grind formatted profile:
//
//    start;backup;read 3
//    start;backup;write 1
//    end;backup;read 1
//    end;backup;write 3
//
// This is unfortunate, since it means we can't produce a flamegraph that isn't
// potentially lying about the what the actual execution behavior was. To
// produce a flamegraph at all from the call graph representation, we have to
// decide how much weight each sub-call should have. Given that we know the
// total weight of each node, we'll make the incorrect assumption that every
// invocation of a function will have the average distribution of costs among
// the sub-function invocations. In the example given, this means we assume that
// every invocation of backup() is assumed to spend half its time in read() and
// half its time in write().
//
// So the flamegraph we'll produce from the given call-graph will actually be:
//
//    start;backup;read 2
//    start;backup;write 2
//    end;backup;read 2
//    end;backup;write 2
//
// A particularly bad consequence is that the resulting flamegraph will suggest
// that there was at some point a call stack that looked like
// strat;backup;write, even though that never happened in the real program
// execution.
```

Fixes #18
2021-02-14 23:14:58 -08:00
Jamie Wong 6a979bb568 1.12.1 2020-11-12 02:35:59 -08:00
Jamie Wong 36911599cb Fix infinite recursion in resizing on retina displays (fixes #327) 2020-11-12 02:34:19 -08:00
Jamie Wong b32ff08ca3 1.12.0 2020-11-12 01:57:41 -08:00
Jamie Wong 361bdc9cd2 Fix bug in remapRangesToTrimmedText (#326)
Welp, looks like I missed a pretttty important edge case in my test.

Fixes #324
2020-11-12 01:52:47 -08:00
Jamie Wong a1384b03be Add a system for theming, use it to implement dark mode (#323)
Dark mode:
![image](https://user-images.githubusercontent.com/150329/98463526-9680a880-2170-11eb-9fc2-9018604ff1ad.png)

Light mode:
![image](https://user-images.githubusercontent.com/150329/98463537-a5fff180-2170-11eb-8b60-afe2096d848e.png)

Fixes #220
2020-11-12 01:51:55 -08:00
Jamie Wong 5f32640060 1.11.1 2020-10-25 01:50:28 -07:00
Jamie Wong a10c834f99 Fix trace-event import for many cases where there are 'ts' collisions (#322)
The trace event format has a very unfortunate combination of requirements in order to give a best-effort interpretation of a given trace file:

1. Events may be recorded out-of-order by timestamp
2. Events with the *same* timestamp should be processed in the order they were provided in the file. Mostly.

The first requirement is written explicitly [in the spec](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview).

> The events do not have to be in timestamp-sorted order.

The second one isn't explicitly written, but it's implicitly true because otherwise the interpretation of a file is ambiguous. For example, the following file has all events with the same `ts` field, but re-ordering the fields changes the interpretation.

```
[
  { "pid": 0, "tid": 0, "ph": "X", "ts": 0, "dur": 20, "name": "alpha" },
  { "pid": 0, "tid": 0, "ph": "X", "ts": 0, "dur": 20, "name": "beta" }
}
```

If we allowed arbitrary reordering, it would be ambiguous whether the alpha frame should be nested inside of the beta frame or vice versa. Since traces are interpreted as call trees, it's not okay to just arbitrarily choose.

So you might next guess that a reasonable approach would be to do a [stable sort](https://wiki.c2.com/?StableSort) by "ts", then process the events one-by-one. This almost works, except for two additional problems. The first problem is that in some situations this would still yield invalid results.

```
[
  {"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
  {"pid": 0, "tid": 0, "ph": "B", "name": "beta", "ts": 0},
  {"pid": 0, "tid": 0, "ph": "E", "name": "alpha", "ts": 1},
  {"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 1}
]
```

If we were to follow this rule, we would try to execute the `"E"` for alpha before the `"E"` for beta, even though beta is on the top of the stack. So in *that* case, we actually need to execute the `"E"` for beta first, otherwise the resulting profile is incorrect.

The other problem with this approach of using the stable sort order is the question of how to deal with `"X"` events. speedscope translates `"X"` events into a `"B"` and `"E"` event pair. But where should it put the `"E"` event? Your first guess might be "at the index where the `"X"` events occur in the file". This runs into trouble in cases like this:

```
[
  { "pid": 0, "tid": 0, "ph": "X", "ts": 9, "dur": 1, "name": "beta" },
  { "pid": 0, "tid": 0, "ph": "X", "ts": 9, "dur": 2, "name": "gamma" },
]
```

The most natural translation of this would be to convert it into the following `"B"` and `"E"` events:

```
[
  { "pid": 0, "tid": 0, "ph": "B", "ts": 9, "name": "beta" },
  { "pid": 0, "tid": 0, "ph": "E", "ts": 10, "name": "beta" },
  { "pid": 0, "tid": 0, "ph": "B", "ts": 9, "name": "gamma" },
  { "pid": 0, "tid": 0, "ph": "E", "ts": 11, "name": "gamma" },
]
```

Which, after a stable sort turns into this:

```
[
  { "pid": 0, "tid": 0, "ph": "B", "ts": 9, "name": "beta" },
  { "pid": 0, "tid": 0, "ph": "B", "ts": 9, "name": "gamma" },
  { "pid": 0, "tid": 0, "ph": "E", "ts": 10, "name": "beta" },
  { "pid": 0, "tid": 0, "ph": "E", "ts": 11, "name": "gamma" },
]
```

Notice that we again have a problem where we open "beta" before "gamma", but we need to close "beta" first because it ends first!

Ultimately, I couldn't figure out any sort order that would allow me to predict ahead-of-time what order to process the events in. So instead, I create two event queues: one for `"B"` events, and one for `"E"` events, and then try to be clever about how I merge them together.

AFAICT, chrome://tracing does not sort events before processing them, which is kind of baffling. But chrome://tracing also has really bizarre behaviour for things like this where the resulting flamegraph isn't even a valid tree (there are overlapping ranges):

```
[
  { "pid": 0, "tid": 0, "ph": "X", "ts": 0, "dur": 10, "name": "alpha" },
  { "pid": 0, "tid": 0, "ph": "X", "ts": 5, "dur": 10, "name": "beta" }
}
```

So I'm going to call this "good enough" for now.

Fixes #223
Fixes #320
2020-10-25 01:45:13 -07:00
Jamie Wong de3ab89eb5 Fix import of trace event files where B/E events' args don't match (#321)
In #273, I changed `CallTreeProfileBuilder.leaveFrame` to fail hard when you request to leave a frame different from the one at the top of the stack. It turns out we were intentionally doing this for trace event imports, because `args` are part of the frame key, and we want to allow profiles to be imported where the `"B"` and `"E"` events have differing `args` field.

This PR fixes the import code to permissively allow the `"args"` field to not match between the `"B"` and `"E"` fields.

**A note on intentional differences between speedscope and chrome://tracing**

`chrome://tracing` will close whichever frame is at the top when it gets an `"E"` event, regardless of whether the name or the args match. speedscope will ignore the event entirely if the `"name"` field doesn't match, but will warn but still close the frame if the `"name"`s match but the `"args"` don't.
```
[
  {"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
  {"pid": 0, "tid": 0, "ph": "B", "name": "beta", "ts": 1},
  {"pid": 0, "tid": 0, "ph": "E", "name": "gamma", "ts": 2},
  {"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 9},
  {"pid": 0, "tid": 0, "ph": "E", "name": "alpha", "ts": 10}
]
```
### speedscope
![image](https://user-images.githubusercontent.com/150329/97098205-7365dd00-1637-11eb-9869-4e81ebebcee1.png)
```
warning: ts=2: Request to end "gamma" when "beta" was on the top of the stack. Doing nothing instead.
```
### chrome://tracing
![image](https://user-images.githubusercontent.com/150329/97098215-87114380-1637-11eb-909c-b2e70c7291a4.png)
2020-10-24 21:58:31 -07:00
Jamie Wong aee2dfdf89 1.11.0 2020-10-13 01:05:26 -07:00
Jamie Wong d9b3950274 Support remapping profiles using source maps (#317)
This PR adds the ability to remap an already-loaded profile using a JavaScript source map. This is useful for e.g. recording minified profiles in production, and then remapping their symbols when the source map isn't made directly available to the browser in production.

This is a bit of a hidden feature. The way it works is to drop a profile into speedscope, then drop the sourcemap file on top of it.

To test this, I used a small project @cricklet made (https://gist.github.com/cricklet/0deaaa7dd63657adb6818f0a52362651), and also tested against speedscope itself.

To test against speedscope itself, I profiled loading a file in speedscope in Chrome, then dropped the resulting Chrome timeline profile into speedscope, and dropped speedscope's own sourcemap on top. Before dropping the source map, the symbols look like this:

![image](https://user-images.githubusercontent.com/150329/94977230-b2878f00-04cc-11eb-8907-02a1f1485653.png)

After dropping the source map, they look like this:

![image](https://user-images.githubusercontent.com/150329/94977253-d4811180-04cc-11eb-9f88-1e7a02149331.png)

I also added automated tests using a small JS bundle constructed with various different JS bundlers to make sure it was doing a sensible thing in each case.

# Background

Remapping symbols in profiles using source-maps proved to be more complex than I originally thought because of an idiosyncrasy of which line & column are referenced for stack frames in browsers. Rather than the line & column referencing the first character of the symbol, they instead reference the opening paren for the function definition.

Here's an example file where it's not immediately apparent which line & column is going to be referenced by each stack frame:

```
class Kludge {
  constructor() {
    alpha()
  }

  zap() {
    alpha()
  }
}

function alpha() {
  for (let i = 0; i < 1000; i++) {
    beta()
    delta()
  }
}

function beta() {
  for (let i = 0; i < 10; i++) {
    gamma()
  }
}

const delta = function () {
  for (let i = 0; i < 10; i++) {
    gamma()
  }
}

const gamma =
() => {
  let prod = 1
  for (let i = 1; i < 1000; i++) {
    prod *= i
  }
  return prod
}

const k = new Kludge()
k.zap()
```

The resulting profile looks like this:
![image](https://user-images.githubusercontent.com/150329/94976830-0db88200-04cb-11eb-86d7-934365a17c53.png)

The relevant line & column for each function are...

```
// Kludge: line 2, column 14
class Kludge {
  constructor() {
             ^
...
// zap: line 6, column 6
  zap() {
     ^
...
// alpha: line 11, column 15
function alpha() {
          ^
...
// delta: line 24, column 24
const delta = function () {
                       ^
...
// gamma: line 31, column 1
const gamma =
() => {
^
```

If we look up the source map entry that corresponds to the opening paren, we'll nearly always get nothing. Instead, we'll look at the entry *preceding* the one which contains the opening paren, and hope that has our symbol name. It seems this works at least some of the time.

Another complication is that some, but not all source maps include the original names of functions. For ones that don't, but do include the original source-code, we try to deduce it ourselves with varying amounts of success.

Supersedes #306
Fixes #139
2020-10-12 18:03:31 -07:00
Gabriele N. Tornetta 177696e359 Update link to Austin instructions (#319)
The Austin format conversion tools have been moved to the dedicated austin-python module. The README has been updated to point to the new instructions.
2020-10-11 12:05:20 -07:00
Jamie Wong 16e32dc08e Normalize line & column numbers to be 1-based in Chrome & Firefox imports (#318)
This also fixes a dumb bug in the Firefox import that just completely failed to import column numbers.
2020-10-02 14:56:22 -07:00
Jamie Wong 8a4f38a8cb 1.10.0 2020-09-29 18:51:49 -07:00
Jamie Wong 9361a6baf2 Switch from Travis CI to GitHub Actions for test runs (#316)
Switch from Travis CI to GitHub Actions for test runs
2020-09-29 16:39:18 -07:00
Jamie Wong ede9c74d50 Remove accidentally added/retained dependencies on react and react-redux (#315)
speedscope no longer relies upon react-redux, and never depended upon react. Let's clean these up.
2020-09-29 16:20:27 -07:00
Jamie Wong f758130455 Add support for imports of UTF-16 encoded text w/ Byte Order Mark (BOM) (#314)
Before this PR, we blindly assumed that all text imported into speedscope was UTF-8 encoded. This, unsurprisingly, is not always true. After this PR, we support text that's UTF-16 encoded, with either the little-endian or big-endian byte-order-mark.

Fixed #291
2020-09-29 15:40:49 -07:00
Jamie Wong f3a1c09c9b Add support for Safari profiles (#313)
Closes #294 

This adds import for Safari/webkit profiler. Well, for Safari 13.1 for sure, I haven't done any work to check if there's been changes to the syntax.

It seems to work OK, and is already a huge improvement over profiling in Safari (which doesn't even have a flame graph, let alone something like left heavy). Sadly, the sampler resolution is only 1kHz, which is not super useful for a lot of profiling work. I made a ticket on webkit bug tracker to ask for 10kHz/configurable sampling rate: https://bugs.webkit.org/show_bug.cgi?id=214866

Another thing that's missing is that I cut out all the idle time. We could also insert layout/paint samples into the timeline by parsing `events`. But I'll leave that for another time.

<img width="1280" alt="Captura de pantalla 2020-07-28 a las 11 02 06" src="https://user-images.githubusercontent.com/183747/88643560-20c16700-d0c2-11ea-9c73-d9159e68fab9.png">
2020-09-29 14:26:01 -07:00
Sebastian Wahl 069c0194a6 #168 Fix browser not opening on Windows when using the CLI (#307) 2020-09-14 11:53:36 -07:00
Jamie Wong 64fe369c42 1.9.0 2020-08-05 01:02:17 -07:00
Jamie Wong f55c53f699 Small followup tweaks to #305 2020-08-05 00:50:02 -07:00
E-Liang Tan a0b3fe8420 Add patch to fix accumulated negative deltas (#305)
## Context

Hi! I'm working on an experimental React [concurrent mode profiler](https://react-scheduling-profiler.vercel.app) in partnership with the React core team, and we're using a [custom build of Speedscope](https://github.com/taneliang/speedscope/compare/master...taneliang:fork-for-scheduling-profiler) that exposes Speedscope's internals to support our custom flamechart rendering. Specifically, Speedscope is used to import and process Chrome profiles, which are then fed to our rendering code that draws everything to a canvas.

Here's a screenshot of our app for context. The stuff above the thick gray bar is React data (some React Fiber lanes, React events, and other user timing marks), and a flamechart is drawn below.

![image](https://user-images.githubusercontent.com/12784593/89261576-e2e3b600-d660-11ea-9b90-6c6991d061d6.png)

## Problem

Early on, we had [an issue](https://github.com/MLH-Fellowship/scheduling-profiler-prototype/issues/42) where our flamechart was not aligned with the React data. The discrepancy between the flamechart frames and our React data grew over the time of the profile.

We tracked down the cause to https://github.com/jlfwong/speedscope/pull/80, which resolves https://github.com/jlfwong/speedscope/issues/70. It seems like zeroing out those negative time deltas resulted in the accumulation of errors over the time of these profiles, which resulted in the very visible misalignment in our profiler.

I am confident that the React data's timestamps are correct because they are obtained from User Timing marks, which have absolute timestamps and are thus independent of any `timeDelta` stuff. This would mean that Speedscope is likely displaying incorrect timestamps for Chrome profiles.

## Solution

This PR takes a different approach to solving the negative `timeDelta` problem: we add a `lastElapsed` variable as a sort of backstop, preventing `elapsed` from traveling backwards in time, while still ensuring that `elapsed` is always accurate.

We've been using this patch in our custom build for about a month now and it seems to work well.
2020-08-05 00:47:49 -07:00
Jamie Wong 9452aeae82 Provide prev/next buttons to cycle through search results, make search results more visually prominent (#304)
This PR addresses two key pieces of feedback provided on search in #38 

1. Make the search results more visually prominent
2. Make it easier to find the matches by having some way of jumping to next

For the visual prominence facet, I switched from yellow outlines to orange backgrounds.

|Before|After|
|-|-|
|![image](https://user-images.githubusercontent.com/150329/89276105-14746700-d5f8-11ea-9c9d-1dfdfc3bd6d7.png)|![image](https://user-images.githubusercontent.com/150329/89276070-045c8780-d5f8-11ea-8664-9da0af569cec.png)|

For the easy identification portion, I added prev/next buttons to each view, which can also be operated by hitting Enter for next or Shift+Enter for previous.

![Kapture 2020-08-04 at 2 16 57](https://user-images.githubusercontent.com/150329/89276542-a1b7bb80-d5f8-11ea-8642-a172a6561734.gif)
2020-08-04 02:20:26 -07:00
Gabriele N. Tornetta b26cdb5be4 Add link to Austin to README (#303)
Add a link to Austin's Speedscope section of the README to Speedscope's README.
2020-07-30 11:03:12 -07:00
Jamie Wong 1c5bdba36e Increase contrast for matching research results by fading text for unmatched frames (#298)
Before:
![image](https://user-images.githubusercontent.com/150329/88493052-ee99f300-cf63-11ea-9522-8de032e920ac.png)

After:
![image](https://user-images.githubusercontent.com/150329/88493062-f9548800-cf63-11ea-9e7e-5c87a1dba836.png)

Works towards #38
2020-07-26 17:21:38 -07:00
Jamie Wong c3b35d7b0f 1.8.0 2020-07-19 21:27:00 -07:00
Jamie Wong dfaefe54fd Implement search highlighting in time order & left heavy views (#297)
This implements the next step towards full featured search in speedscope: visual highlighting of matching search results in the time ordered & left heavy views. This doesn't yet add the ability to click prev/next to select the next matching element in the editor, but I'm still planning on doing something like that. I haven't figured out yet what I want the user experience to be like for that.

![speedscope-flamegraph-search](https://user-images.githubusercontent.com/150329/87898991-9ebba900-ca04-11ea-9bd9-31ad8d4c6d2a.gif)

This works towards fixing #38
2020-07-19 21:20:14 -07:00
Jamie Wong 7514f4c0c9 Fix performance issues for the caller/callee flamegraphs in the sandwich view (#296)
This fixes two unrelated problems which together caused performance issues in the sandwich view & made hover tooltips appear to be broken.

The first issue was caused by continuously priming the `requestAnimationFrame` loop when it should be a no-op, and the second issue was caused by using different cache keys when trying to access a memoized value in the caller & callee flamegraph components. This resulted in thrash, and especially bad performance because the cache miss was resulting in us re-allocating the WebGL framebuffer on every frame, which is unsurprisingly quite slow.

Fixes #212 
Fixes #155 
Fixes #74 (though this was maybe already fixed)
2020-07-18 22:37:15 -07:00
Jamie Wong ff447c2719 1.7.0 2020-07-13 22:10:28 -07:00
Jamie Wong 668bb032ba Introduce filtering via Ctrl+F/Cmd+F into the sandwich view (#293)
This is the first step towards fixing #38. 

I started with the easiest part from a UI-paradigm perspective, and also the place that's the most confusing that search doesn't work. Before this PR, browers' Cmd+F/Ctrl+F would *look* like it worked in the Sandwich view, but they wouldn't work fully because the view in the sandwich view is a virtualized table, meaning that it doesn't put all of the rows in the DOM. Instead, it only renders enough to fill the viewport to make rendering much faster.

Here's what the changes from this PR look like in action:

![Kapture 2020-07-12 at 23 17 33](https://user-images.githubusercontent.com/150329/87276802-ef2b8780-c495-11ea-9856-9c834ea7f028.gif)

Before closing #38, I'll be adding search functionality to the flamechart views too.
2020-07-13 22:04:19 -07:00
Jamie Wong 9ed1eb192c 1.6.0 2020-05-30 21:54:44 -07:00
Jamie Wong 8620432cbc Introduce a profile selector dropdown (#282)
This adds much better UI for selecting different profiles within a single import.

![Kapture 2020-05-30 at 21 34 06](https://user-images.githubusercontent.com/150329/83344564-595ce400-a2bd-11ea-8306-e5d8f647b65e.gif)

You can now hover over the middle of the toolbar or hit `t` on your keyboard to bring up the profile selector. From there, you can use fuzzy-find to switch to the profile you want, and hit "enter" to select it. The up and down arrow keys can be used while the profile selector filter input is focused to move through the list of profiles.

I think the "next" and "prev" buttons are now totally useless, so I removed them.

Fixes #167
2020-05-30 21:42:27 -07:00
Jamie Wong dead3f9ad9 Fix bug with bad caching of action creators (#281)
Profile switching was subtly broken because action creators weren't being correctly re-bound due to a missing dependency in a `useCallback` call.

I also tried to reduce boilerplate in this PR by adding additional exhaustive deps protection via eslint for `useSelector`, `useAppSelector`, and `useActionCreator`. The removes the need for using `useCallback` or each of those.

Fixes #280
2020-05-25 19:10:40 -07:00
Jamie Wong 80b747a55e Fix hot module reload issues caused by subtle bug in useSelector (#279)
To test this, load a profile, then save a `.tsx` file locally. Before this change, it would bring you back to the welcome screen after hot reload. After this change, application state is still displayed. This is because before the change, the `setGLCanvas` action wasn't resulting in a re-render because it occurred between the initial render and the `useLayoutEffect` callback.

Fixes #276
2020-05-25 15:42:19 -07:00
Jamie Wong 351994972d Upgrade to Preact X, partially convert to using hooks (#267)
I'd like to try writing new components using hooks, and to do that I need to upgrade from preact 8 to preact X.

For reasons that are... complicated, in order to upgrade without breaking part of my build process, I had to remove the dependency on `preact-redux` altogether. This led me to write my own implementation, and as part of that I realized I could remove `createContainer` in favour of some simple hooks that use redux.

Before landing:
- [x] Investigate performance issues in the sandwich views
- [x] Investigate es-lint checks for exhaustive hook dependencies
2020-05-23 16:42:31 -07:00
Jamie Wong ca1abfdd32 Fix schema generation in new TypeScript version (#274)
Fixes #268 

I fixed it by dropping the dependency on quicktype entirely, and using its dependency directly. I still don't understand why the version of typescript used in this repository affects what quicktype is doing, but it seems like the issue is in quicktype, not its dependency.

I validated this change was correct by diffing the output of `node scripts/generate-file-format-schema-json.js` with what's currently on http://speedscope.app/file-format-schema.json. There's no difference.

This PR also includes changes to the CI script to ensure that we can catch this before hitting master next time.
2020-05-23 16:07:38 -07:00
Jamie Wong dee9e5ade4 Fail loudly when profile is imported with unmatched open/close events (#273)
Before this change, profiles like those in #272 would import but would display misleading data. Let's fail hard instead.

Fixes #272
2020-05-23 15:56:17 -07:00
Jamie Wong 2077a905a9 Upgrade TypeScript from 3.2.4 to 3.9.2 (#266) 2020-05-16 17:02:51 -07:00
Jamie Wong e969178e65 More npm audit fixes 2020-05-16 16:46:01 -07:00
Justin Beckwith 56f6459af9 Bump parcel and audit fix (#264) 2020-05-16 16:44:45 -07:00
Jamie Wong 3f79e0fe96 Update README.md to include link for importing from ruby-prof
Fixes #265
2020-04-28 11:00:53 -07:00
Jamie Wong d30bb2ef7e Fix the build for node 13.x, make travis test 10, 12, 13, stable (#263)
@JustinBeckwith pointed out in #262 that `npm install` was broken in node 13.x, and @DanielRuf pointed in #254 that test fail for node 11+ because of a change to stability of sorting.

This PR seeks to address both of those.

The installation issue was fixed by just regenerating `package-lock.json` without needing to bump any of the direct dependency versions. The test failure issue requires manual intervention.

To fix the sort stability issue, I updated the tests to use the stable sort values (these were all the correct values, though some of the test values were incorrect).

To make the suite still pass for node 10, I added a hack where I override `Array.prototype.sort` with a stable implementation that's *only* used in tests (See comments in code for a justification for why)

## Test Plan

Before this PR: `npm install` on node 13.x fails & `npm run jest` results in test failures
After this PR: `npm install` on node 13.x passes & `npm run jest` passes for node 10, 12, and 13.
2020-04-20 08:26:59 -07:00
Jamie Wong fd4195da10 Update CHANGELOG.md 2020-01-16 00:17:47 -08:00
Jamie Wong 707462e9cf 1.5.3 2020-01-16 00:09:07 -08:00
Jamie Wong 375040e892 Bump dependency versions to unbreak build (#253)
I ended up in a horrible peer dependency hell and apparently needed to bump the versions of quicktype, typescript, ts-jest, *and* jest to get out of it. But I think I got out of it!

Local builds and deployment builds both seem to work after these changes.
2020-01-15 23:32:14 -08:00
Jamie Wong 5ae9abcf1d Trace event: Prevent event re-ordering from generating incorrect flamegraphs (#252)
The code to import trace formatted events intentionally re-orders events in order to make it easier at flamegraph construction time to order the pushes and pops of frames.

It turns out that this re-ordering results in incorrect flamegraphs being generated as shown in #251.

This PR fixes this by avoiding re-ordering in situations where it isn't necessary.
2020-01-15 22:03:23 -08:00
miso11 bdd9301c59 make tooltip width wider (#239)
Issue #191

It shouldn't be ellipsized, or at least it should be to the right, because I think it's more interesting the file name and function name than the system path where it is found.

Make max width bigger

Before: 
![before](https://user-images.githubusercontent.com/52132927/67621727-ff6dda80-f812-11e9-8c10-533542fe0302.png)

After:

![after](https://user-images.githubusercontent.com/52132927/67621730-04cb2500-f813-11e9-8d36-80e8c58a529e.png)
2019-10-28 11:36:15 -07:00
Jamie Wong cc9750923a Update README.md 2019-10-16 00:15:06 -07:00
Jonathan Chan c3074b7343 1.5.2 2019-10-10 18:27:28 -07:00
Jonathan Chan b15a08b3ff Support newer Emscripten .symbols with hex escapes (#233)
Apparently Emscripten now generates `.symbols` files where names are not mangled using Clang's mangling scheme, but rather hex-escaped! So 'a\20b' means 'a b'. Currently we can't import these symbol maps into Speedscope because a regex rejects them, and they look weird because we don't unescape.
2019-10-10 14:31:34 -07:00
Jamie Wong 68683aa054 Add pyspeedscope & flamescope to README 2019-10-06 15:10:00 -07:00
Jamie Wong eb0e1ce731 Add py-spy to README 2019-10-06 14:59:17 -07:00
Jamie Wong bd546ca893 1.5.1 2019-06-06 00:07:14 -07:00
Jamie Wong 0c1e477f35 Support import from trace event format event when there are too many "E" events. (#222)
Fixes #221
2019-06-06 00:03:08 -07:00
Jamie Wong 30ca6291ca 1.5.0 2019-02-17 18:38:17 -08:00
Jamie Wong 66a9e5d1cf Support importing unterminated JSON in simple cases (#208)
This PR introduces support for importing JSON based profiles that are missing a terminating `]` (and possibly have an extraneous `,`).

This is similar to #202, but takes a much more targeted and simple approach.

I'm confident that this approach is sufficient because this is exactly what `chrome://tracing` does: https://github.com/catapult-project/catapult/blob/27e047e0494df162022be6aa8a8862742a270232/tracing/tracing/extras/importer/trace_event_importer.html#L197-L208

Fixes #204
2019-02-17 18:32:26 -08:00
Jamie Wong a2022a07a2 Fix crash when importing from stackprof without raw_timestamp_deltas (#207)
Fixes #200
2019-02-17 18:30:02 -08:00
Jamie Wong b7806a1c5f Alert instead of crash when successfully importing a file containing no profiles (#205)
Fixes #169
2019-02-17 17:46:24 -08:00
Jamie Wong 7f19a13012 Support importing multithreaded profiles from Chrome 66 (#206)
In #194, I added code to support import of multithreaded profiles from Chrome 70. I'm now doing some profiling work on an older version of Android chrome, and it seems like the profile objects don't yet have `id` properties. Instead, we should try using the `pid/tid` pair to identify profiles when the `id` field is absent.

This was tested against a profile import from Android Chrome 66.
2019-02-17 17:46:09 -08:00
Archerlly abd74be9fa add default instruments selected run number (#203)
this's will lack `com.apple.xray.owner.template` in instruments archive data where run instruments with command line.
like:
1. run`instruments -t Template.tracetemplate -D demo.trace -l 10000 -w  test.app`
2. drag `demo.trace` into `https://www.speedscope.app`
3. alert `Unrecognized format! See documentation about supported formats`
2019-02-17 17:45:51 -08:00
Jamie Wong c706bdfe04 Revert "Support importing partial JSON files (#202)"
This reverts commit cfc8fe8f6e.
2019-02-08 18:33:30 -08:00
Marcin Kolny cfc8fe8f6e Support importing partial JSON files (#202)
Partial files are allowed in many specs, e.g. Trace Event Format,
so the viewer should be able to load partial files as well.
2019-02-08 18:08:51 -08:00
Jamie Wong ddc61302e8 1.4.1 2019-01-22 21:53:09 -08:00
Jamie Wong 864c065053 Fix importing of Trace Event Format files with no ts field on M events (#198)
The spec for the Trace Event Format technically requires that all entries have "ts" values, and they do in the profiles recorded using chrome://tracing. We don't actually use those values in the case of "M" (metadata) events, however, and they're semantically meaningless as far as I can tell, so let's stop requiring them.

This allows the files that @aras-p provided in #77 to import successfully.

Fixes #77
2019-01-22 21:51:23 -08:00
Jamie Wong 7cca1a76bc 1.4.0 2019-01-22 12:03:31 -08:00
Jamie Wong 8c574d1c92 Support basic import of profiles in the "Trace Event Format" (#197)
This PR implements basic import of profiles from the "Trace Event Format", which is used by `chrome://tracing`, but also which many other tools target as a convenient event tracing format. The spec can be found here: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.xqopa5m0e28f.

The standard supports a broad set of events, some of which don't yet have any practical way to visualize them in speedscope. This PR implements support for the `B`, `E`, and `X` events, as well as gathering process and thread names via some of the `M` events.

This work was motivated by a generous donation to /dev/color by @aras-p: https://github.com/jlfwong/speedscope/issues/77#issuecomment-455077014

Fixes #77
2019-01-21 20:49:25 -08:00
Jamie Wong fbc8946caa Update CHANGELOG.md 2018-12-04 12:05:59 -08:00
vmarchaud 8cddf3fe81 Import v8 cpu profile (old format) (#177)
As said on #170, i added the support for the old format used by https://github.com/hyj1991/v8-profiler-node8 (which is currently used for pm2.io).
2018-12-04 12:05:19 -08:00
Jamie Wong c15ca263d3 Update CHANGELOG.md 2018-12-03 19:29:25 -08:00
Jamie Wong 519847b489 1.3.2 2018-12-03 19:25:54 -08:00
Jamie Wong 6d4f3499da Fix import of multithreaded Chrome profiles (#194)
In #160, I wrote code which incorrectly assumed that at most one profile would be active at a time. It turns out this assumption is incorrect because of webworkers! This PR introduces a fix which correctly separates samples taken on the main thread from samples taken on worker threads, and allows viewing both in speedscope.

Fixes #171
2018-12-03 19:21:59 -08:00
Jamie Wong ad49dacb29 1.3.1 2018-11-08 10:05:52 -08:00
Jamie Wong 6562fec7a7 Use TextDecoder if available for converting from an ArrayBuffer for speed (#188)
#165 introduced a performance regression by using a really inefficient method for converting from array buffers into string. This should ix it by using `TextDecoder` instead.
2018-11-08 10:01:05 -08:00
Jamie Wong 23d4042e04 1.3.0 2018-10-29 09:56:06 -07:00
Vincent Rischmann 9961ed8295 Make the wasd keymappings work on azerty keyboards (#184)
Instead of using `key`, use `code` which according to [this](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code) should work consistently for different layouts.

I tested the modification on a french AZERTY keyboard and it works fine.
2018-10-29 09:43:10 -07:00
Tristan Hume e35335fe3c Haskell GHC JSON format support (fixes #182) (#183)
Fixes #182 by adding support for importing the JSON profiling format created by GHC's built in profiling support when the executable is passed the `-pj` option. Produces a profile group containing both a time and allocation profile.

Unfortunately, GHC doesn't provide the raw sample information to get the time view to be useful, so only left heavy and sandwich are useful.

Includes a test profile, and I've also tested it on a more real large 2MB profile file in the UI and it works great.

I also modified the Readme to link to a wiki page I'm unable to create, but that should have something like this content copy-pasted into it:

# Importing from Haskell

GHC provides built in profiling support that can export a JSON file.
In order to do this you need to compile your executable with profiling
support and then pass the `-pj` RTS flag to the executable.

This will produce a `my-binary.prof` file in the current directory which
you can import into speedscope.

## Using GHC

See the [GHC manual page on profiling](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html)
for more extensive information on the command line flags available.

```
$ ghc -prof -fprof-auto -rtsopts Main.hs
$ ./Main +RTS -pj -RTS
```

## Using Stack

### With executables

```
$ stack build --profile
$ stack exec -- my-executable +RTS -pj -RTS
```

### With tests

```
stack test --profile --test-arguments "+RTS -pj -RTS"
```
2018-10-29 09:37:11 -07:00
Florian Hermouet-Joscht 86f4ba636d Use arrayBuffer instead of text for profileURL (#179)
When using #profileURL, some binary characters cannot be read if we use `fetch text`. So I changed that to use `arrayBuffer`.

Now we can read pprof protobuf files and normal JSON files instead of only text files.
2018-10-12 17:22:45 -07:00
Jamie Wong 0fe0c454d3 1.2.0 2018-10-08 09:49:15 -07:00
vmarchaud 4b292b2acf Add import of v8 heap allocation profile (#170)
This adds support for importing heap profiles from Chrome: https://developers.google.com/web/tools/chrome-devtools/memory-problems/#allocation-profile
2018-10-08 09:15:39 -07:00
Jamie Wong d78d20e005 Update README.md 2018-09-26 13:38:36 -07:00
Jamie Wong 7d0a3a2c59 1.1.0 2018-09-26 11:46:41 -07:00
Jamie Wong 3f205ec3e9 Add go tool pprof import support (#165)
This PR adds support for importing from Google's pprof format, which is a gzipped, protobuf encoded file format (that's incredibly well documented!) The [pprof http library](https://golang.org/pkg/net/http/pprof/) also offers an output of the trace file format, which continues to not be supported in speedscope to date (See #77). This will allow importing of profiles generated by the standard library go profiler for analysis of profiles containing heap allocation information, CPU profile information, and a few other things like coroutine creation information.

In order to add support for that a number of dependent bits of functionality were added, which should each provide an easier path for future binary input sources

- A protobuf decoding library was included ([protobufjs](https://www.npmjs.com/package/protobufjs)) which includes both a protobuf parser generator based on a .proto file & TypeScript definition generation from the resulting generated JavaScript file
- More generic binary file import. Before this PR, all supported sources were plaintext, with the exception of Instruments 10 support, which takes a totally different codepath. Now binary file import should work when files are dropped, opened via file browsing, or opened via invocation of the speedscope CLI.
- Transparent gzip decoding of imported files (this means that if you were to gzip compress another JSON file, then importing it should still work fine)

Fixes #60.

--

This is a [donation motivated](https://github.com/jlfwong/speedscope/issues/60#issuecomment-419660710) PR motivated by donations by @davecheney & @jmoiron to [/dev/color](https://www.devcolor.org/welcome) 🎉
2018-09-26 11:33:34 -07:00
Jamie Wong c70171836c 1.0.4 2018-09-12 18:22:59 -07:00
Jamie Wong ee0c2c5025 Fix import from Chrome < 69 when there are multiple profiles
It seems like #160 accidentally broken import of profiles in some circumstances from Chrome < 69. Before #160, we always took the first profile in the list *but* the profiles were not sorted chronologically. After #160 but before this PR, we were taking the chronologically first.

After this PR, we always take the chronologically last `CpuProfile` event in the trace.
2018-09-12 18:21:04 -07:00
Jamie Wong 3ba60a424d Update CHANGELOG.md 2018-09-10 14:40:18 -07:00
Jamie Wong c9ba143eb6 1.0.3 2018-09-10 13:54:32 -07:00
Jamie Wong 802fc2d358 Add test for Chrome 69 import 2018-09-09 18:03:49 -07:00
Jamie Wong b910a2069b Fix import for Chrome 69, support leading idle time before first call (#160)
This PR fixes #159, and also fixes various small things about how profiles were imported for previous versions of Chrome & for Firefox.

The Chrome 69 format splits profiles across several [Trace Event Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview) events. There are two relevant events: "Profile" and "ProfileChunk". At first read through a profile, it seems like profiles are incorrectly terminated, but it seems like the cause of that is that, for whatever reason, events in the event log are not always sorted in chronological order. If sorted chronologically, then the event sequence can be parsed sensibly.

In the process of looking at this information, I also discovered that speedscope's chrome importer was incorrectly interpreting the value of the first element in `timeDeltas` array. It's intended to be the elapsed time since the start of the profile, not the time between the first pair of samples. This changes the weight attributed to the first sample.
2018-09-09 18:00:30 -07:00
William Martin Stewart a1f9755f9c Pretty print JSON (#158) 2018-09-05 09:21:26 -07:00
Jamie Wong 2686a3ccc0 1.0.2 2018-09-04 20:55:25 -07:00
Jamie Wong 789f296c9c Run unit tests as part of release build 2018-09-04 20:53:58 -07:00
Jamie Wong 64e290c9fc Change deploy script to use assets from npm 2018-09-04 20:50:30 -07:00
Jamie Wong a0eba8d434 Update CHANGELOG.md 2018-09-04 20:13:29 -07:00
januszn 281d9f9033 Allow optional CR before LF when probing collapsed stacks files (#154)
This fixes #152, in that it allows "collapsed stacks" files generated with
tools using Windows line endings to be imported into the tool verbatim.
2018-09-04 20:12:27 -07:00
Jamie Wong 44a1f520fe Update CHANGELOG.md 2018-09-04 17:04:35 -07:00
Jonathan Chan b6190362b4 Match more Firefox-internal locations (#156)
Looks like Firefox also generates locations with names like
`bound (self-hosted:951:0)`. We check for `self-hosted`, but not for
`self-hosted` with stuff after it following a colon. We should ignore
these too, otherwise we can end up with stuff on our stack that we don't
expect. This was causing Firefox profiles not to load because we
completed building the profile with a non-empty stack.

Attached is a profile that errors without this patch and successfully renders
with this patch.

[copy.json.zip](https://github.com/jlfwong/speedscope/files/2350583/copy.json.zip)
2018-09-04 17:03:55 -07:00
Jamie Wong a09f27d816 Update CHANGELOG.md 2018-09-04 16:14:41 -07:00
Alex Dukhno 944a6cb126 Change time formatting for minutes from 1.50min to 1:30 (#153) 2018-09-04 13:30:02 -07:00
Jamie Wong 828beb7ccf Update README-ADMINS.md 2018-08-23 10:04:42 -07:00
Jamie Wong 82867ab234 1.0.1 2018-08-23 10:01:13 -07:00
Jamie Wong 6116371ffb Fix flamechart bleeding (#151)
Fixes #150
2018-08-23 09:59:16 -07:00
Jamie Wong da2de64d97 1.0.0 2018-08-23 09:38:56 -07:00
Jamie Wong 9c6f88a9f2 Update README.md 2018-08-23 09:22:24 -07:00
Jamie Wong 48ae79a6a7 Revert "Update hero GIF in README"
This reverts commit 11585fed92.
2018-08-23 08:44:12 -07:00
Jamie Wong 11585fed92 Update hero GIF in README 2018-08-23 08:42:36 -07:00
Jamie Wong f7279e088e Update README.md 2018-08-23 08:15:59 -07:00
Jamie Wong 3fc631cf79 Fix a regression in resize behavior from #147 (#149)
The problem was that I was using `canvas.getBoundingClientRect()` to get the size to resize to, but that was changing as the result of CSS properties set on the canvas! Instead, we take the measurements of its container now which is set to fill the screen, and the canvas has its size entirely managed by `graphics.ts`.
2018-08-23 08:09:22 -07:00
Jamie Wong 5ab320b4cf Update README.md 2018-08-23 08:07:03 -07:00
Jamie Wong f60ab630be Fix rendering bugs when device pixel ratio changes (#147)
Fixes #102
2018-08-22 20:36:09 -07:00
Jamie Wong 453f793042 Update instructions to push tags with release 2018-08-22 18:50:25 -07:00
Jamie Wong a5c3184880 Add a way of generating a self-contained zip-file 2018-08-22 18:50:25 -07:00
Jamie Wong 3193b34c46 Update README.md 2018-08-21 10:20:08 -07:00
Jamie Wong 2df69b6713 Update README.md 2018-08-21 09:55:27 -07:00
Jamie Wong 777e605c7b Update README.md to link to wiki pages for import instructions
Fixes #115
2018-08-21 09:55:06 -07:00
Jamie Wong 100578c536 Add contributor guidelines & documentation (#144)
Fixes #4
2018-08-20 09:42:44 -07:00
Jamie Wong 03578ea7a4 0.7.1 2018-08-20 08:46:13 -07:00
Jamie Wong 3210f8fc08 Fix text culling of ellipses along the left side of the viewport (#143)
Before:
![image](https://user-images.githubusercontent.com/150329/44312631-2c716280-a3b0-11e8-8834-2574b3a4a627.png)

After:
![image](https://user-images.githubusercontent.com/150329/44312639-48750400-a3b0-11e8-8017-41640fe56a22.png)

Fixes #134
2018-08-19 13:12:28 -07:00
Jamie Wong 2c89cefcdc Replace regl with GPU apis ported from evanw/sky (#140)
Fixes #101 
Fixes #137
2018-08-19 11:37:47 -07:00
Jamie Wong 853164ebbf 0.7.0 2018-08-16 11:56:17 -07:00
Jamie Wong 729d7c771b Add support for importing linux "perf script" output (#135)
Fixes #119
2018-08-16 10:24:12 -07:00
Jamie Wong 9d13d95f8d Add a section about verifying the publish 2018-08-14 10:38:42 -07:00
Jamie Wong 085d6298ec 0.6.0 2018-08-14 10:34:34 -07:00
Jamie Wong aa35b17d20 Downgrade to TypeScript 2.8.1 to fix JSON schema generation (#133)
Fixes #132
2018-08-14 09:37:42 -07:00
Jamie Wong a22ab9301f Add tests for redux store (#131)
This adds some baseline tests for the redux store, and also fixes some bugs I found along the way.

Bugs fixed:
- Changing selection after something has been selected within the sandwich view now works
- Table sort state is now preserved when switching between profiles

Fixes #124
2018-08-13 10:25:01 -07:00
Jamie Wong e404053837 Add support for profiles w/ multiples processes & threads (#130)
More broadly, this just supports multiple profiles loaded into the editor in the same time, which supports import from profiles which are multithreaded by importing each thread as a different profile.

For now, the only two file formats that support multiprocess import are Instruments .trace files and speedscope's own file format

In the process of doing this, I refactored the container code considerably and extracted all the dispatch calls into containers rather than them being part of the non-container view code. This is nice because it means that views don't have to be aware of which Flamechart they are or which profile index is being operated upon.

Fixes #66
Fixes #82
Fixes #91
2018-08-11 22:06:53 -07:00
Jamie Wong 558e98d24d 0.5.1 2018-08-11 22:05:39 -07:00
Jamie Wong 7368e15396 0.5.0 2018-08-09 09:38:55 -07:00
Jamie Wong 1bbe3de944 Update CHANGELOG.md 2018-08-09 09:27:08 -07:00
Jamie Wong 8e09be7f7f Update CHANGELOG.md 2018-08-09 09:26:26 -07:00
Jamie Wong 5ee94ec092 Support emscripten symbols containing dashes (#129)
Apparently emscripten symbols are allowed to contain dashes?

e.g. here's a line from a mapping that failed to import before this PR: `527:i32s-div`
2018-08-09 09:25:27 -07:00
Jamie Wong 4d23f1cdee Update CHANGELOG.md 2018-08-08 19:20:58 -07:00
Jamie Wong fc9260ba1d More firefox import fixes (#128) 2018-08-08 17:15:33 -07:00
Jamie Wong 182563dc7c Scroll selected node into sandwich view on mount (#126) 2018-08-08 08:37:54 -07:00
Jamie Wong e6d9994801 Update CHANGELOG.md 2018-08-07 18:42:56 -07:00
Jamie Wong 29c55c3921 Split CallTreeNodes that are non-contiguous (#123)
This PR exposed some bugs in the Firefox importer, which is also fixed in this PR.

Fixes #86
2018-08-07 18:41:56 -07:00
Jamie Wong 0b1050034f Update CHANGELOG.md 2018-08-05 14:12:31 -07:00
Jamie Wong a79beaa731 Ignore click event following a drag (#122) 2018-08-05 14:10:15 -07:00
Jamie Wong bca9c52ac9 Clamp zoom to prevent floating point issues (#121) 2018-08-05 13:57:29 -07:00
Jamie Wong 970f1b2107 Fix use of incorrect viewport size (#120) 2018-08-05 11:08:43 -07:00
Jamie Wong 72c05fe6ba Backfill some more tests (#112)
* Add tests for getHashParams

* Add tests for Color

* Cover a few more lines
2018-08-01 11:42:55 -07:00
Jamie Wong ee157c4139 Add a simple test for demangleCpp (#111) 2018-08-01 09:55:40 -07:00
Jamie Wong 94d0879417 Upgrade to TypeScript 3.0.1 (#110)
Fixes #103
2018-08-01 01:23:21 -07:00
Jamie Wong 608006232f Reorganize directory structure (#104)
While it was kind of nice having everything at the top level, the number of files is now getting a bit unwieldy and hard to understand, so I took a stab at organizing the directories without introducing too much nesting.

Test Plan:
- Ran `npm run serve` to ensure that local builds still work
- Ran `npm run prepack` then `open dist/release/index.html` to ensure that release builds still work
- Ran `scripts/deploy.sh` to ensure that the deployed version of the site will still work when I eventually redeploy
- Ran `npm run jest` to ensure that tests still work correctly
2018-08-01 00:41:45 -07:00
Jamie Wong 11a3a67dce Switch to redux for global state management (#100)
This should allow state to be more easily retained globally when switching views, and should make implementation of cross-view features like search easier too.

It also removes the need for `ReloadableComponent`

Fixes #78

Test Plan:
This changes a lot of how the app works, and a lot of stuff that isn't currently covered by tests, so here's a rough manual test plan:

1. Loaded up http://localhost:1234/, click to load the example profile
2. Switch between views, see that viewport & selection position is now retained when switching views
3. See that clicking on nodes selects them in Time Order & Left Heavy views
4. See that hitting Cmd+S saves a profile
5. See that dropping a profile in works
6. See that dropping a profile + a symbol map works
7. See that visiting localhost:1234/#profileURL=https://raw.githubusercontent.com/jlfwong/speedscope/master/sample/profiles/speedscope/0.1.2/simple-sampled.speedscope.json works
8. See that hitting "r" to toggle recursion flattening works
2018-07-31 23:53:56 -07:00
292 changed files with 98346 additions and 13860 deletions
+11 -4
View File
@@ -1,13 +1,20 @@
module.exports = {
parser: 'typescript-eslint-parser',
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
plugins: ['prettier'],
plugins: ['prettier', '@typescript-eslint', 'react-hooks'],
rules: {
'prettier/prettier': 'error',
'@typescript-eslint/explicit-function-return-type': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': [
'error',
{
additionalHooks: '(useSelector|useAppSelector|useActionCreator)',
},
],
},
};
}
+43
View File
@@ -0,0 +1,43 @@
name: Node.js CI
on:
push:
branches:
- main
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x, 14.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
env:
CI: true
- name: Coveralls Parallel
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
flag-name: run-${{ matrix.node-version }}
parallel: true
finish:
needs: test
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
parallel-finished: true
+2 -1
View File
@@ -2,4 +2,5 @@ node_modules
.cache
dist
.idea
coverage
coverage
.vscode
-3
View File
@@ -1,3 +0,0 @@
language: node_js
node_js:
- '9'
-3
View File
@@ -1,3 +0,0 @@
{
"editor.formatOnSave": true,
}
+271 -4
View File
@@ -1,14 +1,281 @@
## [Unreleased]
## [1.15.1] - 2023-06-04
### Fixed
- Fix import from Chrome Devtools performance tab in Chrome >= 114 [[#422](https://github.com/jlfwong/speedscope/pull/422)]
- Callgrind: Subposition compression and weight correction [[#423](https://github.com/jlfwong/speedscope/pull/423)]
## [1.15.0] - 2022-10-22
### Fixed
- Replace fuzzy matching with exact substring matching for finding matching frames [[#407](https://github.com/jlfwong/speedscope/pull/407)]
## [1.14.0] - 2022-05-19
### Added
- File and line information is now displayed in hover tips [[#365](https://github.com/jlfwong/speedscope/pull/365)] (by [@sokra](https://github.com/sokra))
- Support for stackprof object mode [[#391](https://github.com/jlfwong/speedscope/pull/391)] (by [@alexcoco](https://github.com/alexcoco))
- Support for hash params to control view-mode [[#362](https://github.com/jlfwong/speedscope/pull/362)] (by [@djudd](https://github.com/djudd))
- Support for profiles over 512MB now works [[#385](https://github.com/jlfwong/speedscope/pull/385)] (by [@jlfwong](https://github.com/jlfwong))
- Support for relative URLs in profileURL hashParam [[#357](https://github.com/jlfwong/speedscope/pull/357)] (by [@danvk](https://github.com/danvk))
### Fixed
- Allow collapsed stacks with invalid lines for the Brenden Gregg stack format [[#336](https://github.com/jlfwong/speedscope/pull/336)] (by [@P403n1x87](https://github.com/P403n1x87))
- Allow pasting into the search box [[#338](https://github.com/jlfwong/speedscope/pull/338)] (by [@P403n1x87](https://github.com/P403n1x87))
- Prevent hover tips from getting unnecessarily clipped outside container bounds [[#395](https://github.com/jlfwong/speedscope/pull/395)] (by [@jlfwong](https://github.com/jlfwong))
## [1.13.0] - 2021-02-14
### Added
- Support for importing callgrind profiles [[#331](https://github.com/jlfwong/speedscope/pull/331)]
## [1.12.1] - 2020-11-12
### Fixed
- Fixed for retina displays [[#327](https://github.com/jlfwong/speedscope/issues/327)]
## [1.12.0] - 2020-11-12
### Added
- Dark mode! [[#323](https://github.com/jlfwong/speedscope/pull/323)]
### Fixed
- Fixed incorrect highlighting when search result overlaps "…" [[#326](https://github.com/jlfwong/speedscope/pull/326)]
## [1.11.1] - 2020-10-25
### Fixed
- Fix trace-event import for many cases where there are 'ts' collisions [[#322](https://github.com/jlfwong/speedscope/pull/322)]
- Fix import of trace event files where B/E events' args don't match [[#321](https://github.com/jlfwong/speedscope/pull/321)]
## [1.11.0] - 2020-10-13
### Added
- Support remapping profiles using source maps [[#317](https://github.com/jlfwong/speedscope/pull/317)]
### Fixed
- Fix line & column numbers in imports from Chrome & Firefox [[#318](https://github.com/jlfwong/speedscope/pull/318)]
## [1.10.0] - 2020-09-29
### Added
- Support for importing profiles from Safari [[#300](https://github.com/jlfwong/speedscope/pull/300)] (by [@radex](https://github.com/radex))
### Fixed
- Fixed browser not opening on Windows when using the CLI [[#307](https://github.com/jlfwong/speedscope/pull/307)] (by [@spillerrec](https://github.com/spillerrec))
- Fixed import of UTF-16 encoded files w/ BOM [[#314](https://github.com/jlfwong/speedscope/pull/314)]
- Removed accidental dependency on React [[#315](https://github.com/jlfwong/speedscope/pull/315)]
## [1.9.0] - 2020-08-05
### Added
- Provide prev/next buttons to cycle through search results, make search results more visually prominen [[#304](https://github.com/jlfwong/speedscope/pull/304)]
### Fixed
- Fix accumulated errors in Chrome profile imports caused by zeroed negative timeDeltas [[#305](https://github.com/jlfwong/speedscope/pull/305)] (by [@taneliang](https://github.com/taneliang))
## [1.8.0] - 2020-07-19
### Added
- Added search highlighting in time order & left heavy views [[#297](https://github.com/jlfwong/speedscope/pull/297)]
### Fixed
- Fix performance issues for the caller/callee flamegraphs in the sandwich view [[#296](https://github.com/jlfwong/speedscope/pull/296)]
## [1.7.0] - 2020-07-13
### Added
- Introduced filtering via Ctrl+F/Cmd+F into the sandwich view [[#293](https://github.com/jlfwong/speedscope/pull/293)]
## [1.6.0] - 2020-05-30
### Added
- Improved profile/thread selection UI [[#282](https://github.com/jlfwong/speedscope/pull/282)]
### Fixed
- Crash instead of incorrectly interpreting profiles with incorrectly ordered events [[#273](https://github.com/jlfwong/speedscope/pull/273)]
- A large refactor to upgrade to Preact X was performed [[#267](https://github.com/jlfwong/speedscope/pull/267)]
## [1.5.3] - 2020-01-16
### Fixed
- Bump dependency versions to unbreak build [[#253](https://github.com/jlfwong/speedscope/pull/253)] (by [@jlfwong](https://github.com/jlfwong), with changes from [@Archerlly](https://github.com/Archerlly)'s [#215](https://github.com/jlfwong/speedscope/pull/215))
- Trace event: Prevent event re-ordering from generating incorrect flamegraphs ([#252](https://github.com/jlfwong/speedscope/pull/252), with changes from [@hwajaywang](https://github.com/hwajaywang)'s [#249](https://github.com/jlfwong/speedscope/pull/249))
- Make tooltip width wider [[#239](https://github.com/jlfwong/speedscope/pull/239)] (by [@miso11](https://github.com/miso11))
## [1.5.2] - 2019-10-10
### Fixed
- Fix emscripten remapping when symbols are hex-escaped, like `a\20b` [[#233](https://github.com/jlfwong/speedscope/pull/233)] (by [@jyc](https://github.com/jyc))
## [1.5.1] - 2019-06-06
### Fixed
- Fixed import of trace event files which contain unmatched "E" events ([#222](https://github.com/jlfwong/speedscope/pull/222)) (by [@jlfwong](https://github.com/jlfwong))
## [1.5.0] - 2019-02-17
### Added
- Support importing unterminated JSON in simple cases ([#208](https://github.com/jlfwong/speedscope/pull/208)) (by [@jlfwong](https://github.com/jlfwong))
### Fixed
- Fix crash when importing from stackprof without raw_timestamp_deltas ([#207](https://github.com/jlfwong/speedscope/pull/207)) (by [@jlfwong](https://github.com/jlfwong))
- Alert instead of crash when importing a file containing no profiles ([#205](https://github.com/jlfwong/speedscope/pull/205)) (by [@jlfwong](https://github.com/jlfwong))
- Fixed import of multithreaded profiles from Chrome 66 ([#206](https://github.com/jlfwong/speedscope/pull/206)) (by [@jlfwong](https://github.com/jlfwong))
- Fixed import of instruments trace files with missing run number ([#203](https://github.com/jlfwong/speedscope/pull/203)) (by [@Archerlly](https://github.com/Archerlly))
## [1.4.1] - 2019-01-22
### Fixed
- Fix importing of Trace Event Format files with no ts field on M events [[#198](https://github.com/jlfwong/speedscope/pull/198)] (by [@jlfwong](https://github.com/jlfwong))
## [1.4.0] - 2019-01-22
### Added
- Import v8 cpu profile (old format) [[#177](https://github.com/jlfwong/speedscope/pull/177)] (by [@vmarchaud](https://github.com/vmarchaud))
- Import basic "Trace Event Format" profiles [[#197](https://github.com/jlfwong/speedscope/pull/197)] (by [@jlfwong](https://github.com/jlfwong))
## [1.3.2] - 2018-12-03
### Fixed
- Fixed import of multithreaded Chrome profiles [[#19](https://github.com/jlfwong/speedscope/pull/19)] (by [@jlfwong](https://github.com/jlfwong))
## [1.3.1] - 2018-11-08
### Fixed
- Fixed a file import performance regression by using TextDecoder [[#188](https://github.com/jlfwong/speedscope/pull/188)] (by [@jlfwong](https://github.com/jlfwong))
## [1.3.0] - 2018-10-29
### Added
- Support import from Haskell GHC JSON format support [[#183](https://github.com/jlfwong/speedscope/pull/183)] (by [@trishume](https://github.com/trishume))
### Fixed
- Make the wasd keymappings work on azerty keyboards [[#184](https://github.com/jlfwong/speedscope/pull/184)] (by [@vrischmann](https://github.com/vrischmann))
- Fix import of binary formats via profileURL [[#179](https://github.com/jlfwong/speedscope/pull/179)] (by [@f](https://github.com/f)-hj)
## [1.2.0] - 2018-10-08
### Added
- Add import of v8 heap allocation profile [[#170](https://github.com/jlfwong/speedscope/pull/170)] (by [@vmarchaud](https://github.com/vmarchaud))
## [1.1.0] - 2018-09-26
### Added
- Add go tool pprof import support [[#165](https://github.com/jlfwong/speedscope/pull/165)]
## [1.0.4] - 2018-09-12
### Fixed
- Fix import from Chrome < 69 when there are multiple profiles [[#161](https://github.com/jlfwong/speedscope/pull/161)]
## [1.0.3] - 2018-09-10
### Fixed
- Fix import for Chrome 69, support leading idle time before first call [[#160](https://github.com/jlfwong/speedscope/pull/160)]
## [1.0.2] - 2018-09-04
### Fixed
- Allow optional CR before LF when probing collapsed stacks files [[#154](https://github.com/jlfwong/speedscope/pull/154)]
- Fix import for Firefox 63 [[#156](https://github.com/jlfwong/speedscope/pull/156)]
- Change time formatting for minutes from 1.50min to 1:30 [[#153](https://github.com/jlfwong/speedscope/pull/153)] (by [@Alex](https://github.com/Alex)-Diez)
## [1.0.1] - 2018-08-23
- Fixed an issue where flamegraph bounds were not always being cleared correctly, leading to visual artifacts [[#150](https://github.com/jlfwong/speedscope/pull/150)]
## [1.0.0] - 2018-08-23
### Fixed
- Fixed rendering issues when switching between screens w/ different `devicePixelRatios` [[#147](https://github.com/jlfwong/speedscope/pull/147)]
## [0.7.1] - 2018-08-20
### Fixed
- Removed dependency on regl in order to allow speedscope to run in strict content-security-policy environments [[#140](https://github.com/jlfwong/speedscope/pull/140)]
- Fixed text culling bug [[#143](https://github.com/jlfwong/speedscope/pull/143)]
## [0.7.0] - 2018-08-16
### Added
- Added support to import from linux `perf script` [[#135](https://github.com/jlfwong/speedscope/pull/135)]
## [0.6.0] - 2018-08-14
### Added
- Added support for multiple threads/processes [[#130](https://github.com/jlfwong/speedscope/pull/130)]
- Import all runs & threads from Instruments .trace files instead of just main thread from selected run [[#130](https://github.com/jlfwong/speedscope/pull/130)]
### Fixed
- Ensure the JSON schema has actual contents [[#133](https://github.com/jlfwong/speedscope/pull/133)]
## [0.5.1] - 2018-08-09
### Fixed
- Fixed broken CLI
## [0.5.0] - 2018-08-09
### Fixed
- Fix emscripten remapping when symbols contain dashes, like `527:i32s-div` [[#129](https://github.com/jlfwong/speedscope/pull/129)]
- Improved firefox import speed and fixed bugs in it [[#128](https://github.com/jlfwong/speedscope/pull/128)]
- Prevent non-contiguous blocks in the time ordered flamechart from appearing as a single node for selection [[#123](https://github.com/jlfwong/speedscope/pull/123)]
- Prevent dragging from changing selection [[#122](https://github.com/jlfwong/speedscope/pull/122)]
- Clamp zoom to prevent floating point issues [[#121](https://github.com/jlfwong/speedscope/pull/121)]
- Preserve view state when switching tabs [[#100](https://github.com/jlfwong/speedscope/pull/100)]
## [0.4.0] - 2018-07-21
### Added
* Support for importing v8 logs from node [#98]
* Optionally read from stdin via cli [#99]
- Support for importing v8 logs from node [[#98](https://github.com/jlfwong/speedscope/pull/98)]
- Optionally read from stdin via cli [[#99](https://github.com/jlfwong/speedscope/pull/99)]
## [0.3.0] - 2018-07-18
### Added
* Support for remapping profiles using a wasm symbol file [#93]
- Support for remapping profiles using a wasm symbol file [[#93](https://github.com/jlfwong/speedscope/pull/93)]
+73
View File
@@ -0,0 +1,73 @@
# Contributor Covenant Code of Conduct:
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project
and our community a harassment-free experience for everyone, regardless of
age, body size, disability, ethnicity, gender identity and expression, level
of experience, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of
acceptable behavior and are expected to take appropriate and fair corrective
action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an
appointed representative at an online or offline event. Representation of a
project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting
[jamie.lf.wong@gmail.com](mailto:jamie.lf.wong@gmail.com). All complaints
will be reviewed and investigated and will result in a response that is
deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an
incident. Further details of specific enforcement policies may be posted
separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor-Covenant][homepage],
version 1.4, available at
[https://contributor-covenant.org/version/1/4][version]
[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/4/
+70
View File
@@ -0,0 +1,70 @@
# Contributing to speedscope
Hi! This is a short guide & set of guidelines for contributing to speedscope.
Contributors of all skill levels are welcome to submit pull requests.
This project adheres to the Contributor Covenant [code of conduct](./CODE_OF_CONDUCT.md).
All contributors are expected to uphold this code of conduct.
## Setting up for development
To start running speedscope locally, run the following:
git clone https://github.com/jlfwong/speedscope.git
cd speedscope
npm install
npm run serve
This should open up a running version of speedscope in your default browser.
In your terminal, you should see something like this:
$ npm run serve
> speedscope@0.7.1 serve /Users/jlfwong/code/speedscope
> parcel assets/index.html --open --no-autoinstall
Server running at http://localhost:1234
✨ Built in 7.30s.
Most of speedscope is written in TypeScript. If you're unfamiliar with
TypeScript, then you can either just try to learn it as you go, then the
[official TypeScript
documentation](https://www.typescriptlang.org/docs/home.html) may be of use
to you!
If you're not sure where the code you want to modify lives, the [`README.md`
in the `src/` directory](./src/README.md) might be helpful.
## Code formatting
All TypeScript code in speedscope is automatically formatted with
[Prettier](https://prettier.io/). This means that while you're writing your code,
you don't have to worry about following a formatting guide, because a program will
format your code for you!
The easiest way to use Prettier is via an editor integration. See the [Editor
Integration](https://prettier.io/docs/en/editors.html) page from Prettier's
documentation for help with that.
If you don't want to do that, you can alternatively run the autoformatter by
running `npm run prettier`.
## Running tests
All TypeScript tests are written use [Jest](https://jestjs.io/). To run the
tests, run `npm run jest`.
## Contributing new features
Before contributing code to implement a new feature, please open an issue to
discuss it first. Large pull requests that are submitted without first getting
maintainer buy-in are unlikely to be reviewed or merged.
For features that will cause a visual change, please include visual mockups of
the change you're planning on making.
## Contributing bug fixes
If you discover a bug, please file an issue. If the code change required to
fix it is small (< ~20 lines), then feel free to just open a PR to fix the
issue without trying to get buy-in ahead of time.
+93
View File
@@ -0,0 +1,93 @@
This document describes processes needed by admins of this repository.
# Publishing
Publishing speedscope is a multi-step process:
1. Test the release
2. Prepare the release
3. Publish to npm
4. Deploy the website
5. Upload a release to GitHub
At time of writing, deployment assumes you're running macOS. It probably
works if you're on a linux, and almost definitely does not work on Windows.
## Test the release
Speedscope is tested in CI, so all the automated tests should be passing. We'll
just be doing a few sanity checks to make sure the build & deployment machinery is working correctly.
Run `scripts/prepare-test-installation.sh`. This will do a mock publish &
installation to ensure that the version we're about to publish is going to
work. At the end of this command, it should echo a `cd` command to run in your shell
to switch to the installation directory. Something like this:
```
Run the following command to switch into the test directory
cd /var/folders/l0/qtd9z14973s2tw81vmzwkyp00000gp/T/speedscope-test-installation.9Ssdd2PZ/package
```
Run this command, to switch to the test directory.
Inside of here, run `bin/cli.js`. This should open a copy of speedscope in browser.
Try importing a profile from disk via the browse button and make sure it works.
Next, try running `bin/cli.js dist/release/perf-vertx*`. This should immediately open
speedscope in browser, and the perf-vertx file should load immediately.
If everything looks good, proceed to "Prepare the release".
## Prepare the release
1. Update the version manually in package.json (we intentionally don't use the `npm version` command)
2. Update CHANGELOG.md to indicate the changes that were made as part of this release
3. Commit the changes with the version name as the commit message, e.g. `git commit -m 0.6.0`
4. `git tag` the release. We use tags like `v0.6.0`, e.g. `git tag v0.6.0`
5. `git push && git push --tags`
## Publish to npm
Assuming everything went well in the previous two phases, publishing should just be
a matter of running `npm publish`.
### Verifying the publish
To verify that the publish was successful, run `npm install -g speedscope`.
Try `speedscope`, which should open speedscope in browser.
Try `speedscope sample/profiles/stackcollapse/simple.txt`, which should immediately load the profile.
## Deploying the website
This step must follow the "Publish to npm" step, since it uses assets from
the npm publish.
https://www.speedscope.app/ is hosted on GitHub pages, and is published via pushing
to the `gh-pages` branch. The `gh-pages` branch has totally different contents than
other branches of this repository: https://github.com/jlfwong/speedscope/tree/gh-pages.
It's populated by a deploy script which is invoked by running `npm run deploy` script. This populate a directory with assets pulled from npm, and
boot a local server for you to test the compiled assets. Please do not skip
the manual testing in this step.
If everything looks good, you should be able to hit Ctrl+C, and you should see this prompt:
```
Commit release? [yes/no]:
```
If everything looks good, type `yes` then enter. This will commit to the `gh-pages` branch, and the site should automatically deploy shortly after.
To check if a deploy has happened, you can check https://www.speedscope.app/release.txt
which includes the version, the date, and the commit of the deploy.
## Upload a release to GitHub
This step must follow the "Publish to npm" step, since it uses assets from
the npm publish.
To make a zipfile suitable for uploading to GitHub as a release, run `scripts/prepare-zip-file.sh`.
Once that's done, you should have a zip file in `dist/release/`
Upload that file along with changelog notes to https://github.com/jlfwong/speedscope/releases/new
+126
View File
@@ -0,0 +1,126 @@
简体中文 | [English](./README.md)
# 🔬speedscope
一个快速,交互式,基于网络的性能分析工具。 [FlameGraphs][1](火焰图)的另一个替代品。它可以轻松显示数兆的配置文件并且不会使浏览器崩溃。
给定原始分析数据,你就可以交互式的探索数据,了解应用程序中什么部分速度较慢,或者分配所有内存,或者对任何数据进行分析。
![Example Profile](https://user-images.githubusercontent.com/150329/40900669-86eced80-6781-11e8-92c1-dc667b651e72.gif)
[0]: https://en.wikipedia.org/wiki/Profiling_(computer_programming)#Statistical_profilers
[1]: https://github.com/brendangregg/FlameGraph
# 使用
访问https://www.speedscope.app,上传文件或者拖拽到页面上。配置文件不会上传到任何地方——应用程序完全在浏览器中。
## 命令行中使用
为了方便在不联网的情况下或者在终端中使用, 你可以使用npm下载speedscope:
npm install -g speedscope
调用`speedscope /path/to/profile` 就可以在默认浏览器中加载speedscope。
## 独立使用
如果你不想使用npm或者node下载,你也可以在这里下载独立的版本https://github.com/jlfwong/speedscope/releases.
下载完一个版本的压缩文件之后,解压并在谷歌或者火狐浏览器中打开`index.html`文件即可。
## 支持的文件格式
Speedscope可以不同编程语言和环境的各种不同探查器中摄取概要文件。单击下面的链接获取从特定源导入的文档。
- JavaScript
- [从 Chrome 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-Chrome)
- [从 Firefox 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-Firefox)
- [从 Safari 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-Safari)
- [从 Node.js 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-Node.js)
- Ruby
- [从 stackprof 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-stackprof-(ruby))
- [从 rbspy 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-rbspy-(ruby))
- [从 ruby-prof 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-ruby-prof)
- Python
- [从 py-spy 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-py-spy-(python))
- [pyspeedscope](https://github.com/windelbouwman/pyspeedscope)
- [从 Austin 导入](https://github.com/P403n1x87/austin-python#format-conversion)
- [从 pyinstrument 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-pyinstrument-(python))
- PHP
- [从 phpspy 或者 sj-i/php-profiler 导入](https://github.com/sj-i/php-profiler/pull/101)
- Go
- [从 pprof 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-pprof-(go))
- Rust
- [flamescope](https://github.com/coolreader18/flamescope)
- Native code
- [从 Instruments.app 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-Instruments.app) (macOS)
- [从 `perf` 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-perf-(linux)) (linux)
- [从 .NET Core 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-.NET-Core)
- [从 GHC (Haskell) 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-Haskell)
- [从 custom sources 导入](https://github.com/jlfwong/speedscope/wiki/Importing-from-custom-sources)
极力欢迎贡献添加对其他格式的支持!查看 issues ["import source" tag](https://github.com/jlfwong/speedscope/issues?q=is%3Aissue+is%3Aopen+label%3A%22import+source%22).
## 通过URL导入
要通过URL加载特定的配置文件,你可以添加一个这样的hash片段 `#profileURL=[URL-encoded profile URL]&title=[URL-encoded custom title]`. 注意:托管配置文件的服务器必须配置CORS以允许来自speedscope的AJAX请求。
## 页面
### 🕰Time Order
![Detail View](https://user-images.githubusercontent.com/150329/42108613-e6ef6d3a-7b8f-11e8-93d4-541b2cb93fe5.png)
在 "Time Order" 页面 (默认),调用堆栈按照它们在输入文件中出现的顺序从左到右排列,这通常是安排它们被记录的时间顺序。这个视图对于理解应用程序随时间变化的行为非常有帮助,比如 "首次从数据库获取到数据,然后为序列化准备数据,数据被序列化为JSON"。
水平轴表示每个堆栈的“权重”(最常见的是CPU时间),垂直轴显示在运行期间处于活动状态的堆栈。如果你点击其中一个框,你将能够看到关于它的统计摘要。
### ⬅️Left Heavy
![Left Heavy View](https://user-images.githubusercontent.com/150329/44534434-a05f8380-a6ac-11e8-86ac-e3e05e577c52.png)
在 "Left Heavy" 页面,将相同的堆栈分组在一,不管它们是否按顺序记录。然后,对堆栈进行排序,使每个父堆栈中最重的堆栈位于左侧——因此称为“左权重”。 这个视图对于理解在其他调用栈之间有成百上千个函数交错调用的情况下,时间都花费在了哪里很有用。
### 🥪 Sandwich
![Sandwich View](https://user-images.githubusercontent.com/150329/42108467-76a57baa-7b8f-11e8-815f-1df7b6ac3ede.png)
Sandwich 是一个表格视图,你可以在其中找到所有函数及其相关时间的列表。您可以按自己的时间或总时间排序。
之所以称为"Sandwich"视图,是因为如果你选择表中的某一行,就可以看到所选对象的所有调用者和被调用者的火焰图
## 导航
一旦配置文件被加载,主视图就会被分成两部分:顶部区域是“迷你地图”,底部区域是“堆栈视图”。
### 迷你地图导航
* 在任意一个轴上滚动以进行平移
* 单击并拖动可将视图缩小到特定范围
### 堆栈视图
* 在任意一个轴上滚动以进行平移
* 缩放
* 按住 Cmd+Scroll 进行缩放
* 双击一帧以使视口适应
* 点击一个框以查看关于它的摘要统计
### 键盘导航
* `+`: 放大
* `-`: 缩小
* `0`: 缩小以看到整体情况
* `w`/`a`/`s`/`d` 或者箭头键: pan around the profile
* `1`: 切换到 "Time Order" 视图
* `2`: 切换到 "Left Heavy" 视图
* `3`: 切换到 "Sandwich" 视图
* `r`: 在火焰图中折叠递归
* `Cmd+S`/`Ctrl+S` 保存现有文件
* `Cmd+O`/`Ctrl+O` 打开一个新文件
* `n`: 跳转到下一个文件/如果下一个文件存在
* `p`: 跳转到上一个文件/如果上一个文件存在
* `t`: 打开一个新文件/如果新文件存在
* `Cmd+F`/`Ctrl+F`: 打开搜索。打开时,按下 `Enter` and `Shift+Enter` 查看结果
## 参与贡献
你想成为 speedscope 的贡献者吗? 查看 [CONTRIBUTING.md](./CONTRIBUTING.md) 关于设置开发环境的说明。
+56 -47
View File
@@ -1,6 +1,7 @@
# 🔬speedscope
English | [简体中文](./README-zh_CN.md)
# 🔬speedscope
A fast, interactive web-based viewer for [sampling profiles][0]. An alternative viewer for [FlameGraphs][1]. Will happily display multi-megabyte profiles without crashing your browser.
A fast, interactive web-based viewer for performance profiles. An alternative viewer for [FlameGraphs][1]. Will happily display multi-megabyte profiles without crashing your browser.
Given raw profiling data, speedscope allows you to interactively explore the data to get insight into what's slow in your application, or allocating all the memory, or whatever data is represented in the profiling data.
@@ -13,6 +14,8 @@ Given raw profiling data, speedscope allows you to interactively explore the dat
Visit https://www.speedscope.app, then either browse to find a profile file or drag-and-drop one onto the page. The profiles are not uploaded anywhere -- the application is totally in-browser.
## Command line usage
For offline use, or convenience in the terminal, you can also install speedscope
via npm:
@@ -20,46 +23,45 @@ via npm:
Invoking `speedscope /path/to/profile` will load speedscope in your default browser.
## Self-contained directory
If you don't have npm or node installed, you can also download a
self-contained version from https://github.com/jlfwong/speedscope/releases.
After you download the zip file from a release, simply unzip it and open the
contained `index.html` in Chrome or Firefox.
## Supported file formats
### Chrome
speedscope is designed to ingest profiles from a variety of different profilers for different programming languages & environments. Click the links below for documentation on how to import from a specific source.
Both the timeline format output by Chrome developers tools (https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference#save) and the `.cpuprofile` format output are supported. The `.cpuprofile` format is useful for viewing flamecharts generated by Node.js applications:
https://medium.com/@paul_irish/debugging-node-js-nightlies-with-chrome-devtools-7c4a1b95ae27
- JavaScript
- [Importing from Chrome](https://github.com/jlfwong/speedscope/wiki/Importing-from-Chrome)
- [Importing from Firefox](https://github.com/jlfwong/speedscope/wiki/Importing-from-Firefox)
- [Importing from Safari](https://github.com/jlfwong/speedscope/wiki/Importing-from-Safari)
- [Importing from Node.js](https://github.com/jlfwong/speedscope/wiki/Importing-from-Node.js)
- Ruby
- [Importing from stackprof](https://github.com/jlfwong/speedscope/wiki/Importing-from-stackprof-(ruby))
- [Importing from rbspy](https://github.com/jlfwong/speedscope/wiki/Importing-from-rbspy-(ruby))
- [Importing from ruby-prof](https://github.com/jlfwong/speedscope/wiki/Importing-from-ruby-prof)
- Python
- [Importing from py-spy](https://github.com/jlfwong/speedscope/wiki/Importing-from-py-spy-(python))
- [pyspeedscope](https://github.com/windelbouwman/pyspeedscope)
- [Importing from Austin](https://github.com/P403n1x87/austin-python#format-conversion)
- [Importing from pyinstrument](https://github.com/jlfwong/speedscope/wiki/Importing-from-pyinstrument-(python))
- PHP
- [Importing from phpspy or sj-i/php-profiler](https://github.com/sj-i/php-profiler/pull/101)
- Go
- [Importing from pprof](https://github.com/jlfwong/speedscope/wiki/Importing-from-pprof-(go))
- Rust
- [flamescope](https://github.com/coolreader18/flamescope)
- Native code
- [Importing from Instruments.app](https://github.com/jlfwong/speedscope/wiki/Importing-from-Instruments.app) (macOS)
- [Importing from `perf`](https://github.com/jlfwong/speedscope/wiki/Importing-from-perf-(linux)) (linux)
- [Importing from .NET Core](https://github.com/jlfwong/speedscope/wiki/Importing-from-.NET-Core)
- [Importing from GHC (Haskell)](https://github.com/jlfwong/speedscope/wiki/Importing-from-Haskell)
- [Importing from custom sources](https://github.com/jlfwong/speedscope/wiki/Importing-from-custom-sources)
### Firefox
The `profile.json` file format output by Firefox can be saved and import into speedscope: https://developer.mozilla.org/en-US/docs/Tools/Performance
### Node
If you record profiling information like so:
node --prof /path/to/my/script.js
Then this will generate one or more `isolate*.log` files. You can open
the resulting profile in speedscope by running the following command:
node --prof-process --preprocess -j isolate*.log | speedscope -
### Instruments.app
You can import call trees from OSX Instruments.app into speedscope by
selecting a row in the "Profile" view and select "Edit -> Deep Copy" from the
menu then pasting directly into speedscope. This data contains only aggregate
statistics, so the "Time Order" view and the "Left Heavy" view will look very
similar.
You can also import `.trace` files for time profiles by dragging them directly
into the browser from Chrome.
### `stackprof` Ruby profiler
If the `raw: true` flag is set when recording a dump, the resulting json dump can be imported into speedscope.
### `perf` and `DTrace`
If you process the output of `perf` or `DTrace` first with Brendan Gregg's `stackcollapse-*.pl` scripts (https://github.com/brendangregg/FlameGraph#2-fold-stacks), the result can be imported into speedscope.
Contributions to add support for additional formats are welcome! See issues with the ["import source" tag](https://github.com/jlfwong/speedscope/issues?q=is%3Aissue+is%3Aopen+label%3A%22import+source%22).
## Importing via URL
@@ -68,26 +70,25 @@ To load a specific profile by URL, you can append a hash fragment like `#profile
## Views
### 🕰Time Order
In the "Time Order" view (the default), the stacks are ordered left-to-right in the same order as the occurred in the input file, which is usually going to be the chronological order they were recorded in. This view is most helpful for understand the behavior of an application over time, e.g. "first the data is fetched from the database, then the data is prepared for serialization, then the data is serialized to JSON". This is the only flame graph order supported by Chrome developer tools.
In all flamegraph views, the horizontal axis represents the "weight" of each stack (most commonly CPU time), and the vertical axis shows you the stack active at the time of the sample.
If you click on one of the frames, you'll be able to see summary statistics about it.
![Detail View](https://user-images.githubusercontent.com/150329/42108613-e6ef6d3a-7b8f-11e8-93d4-541b2cb93fe5.png)
In the "Time Order" view (the default), call stacks are ordered left-to-right in the same order as they occurred in the input file, which is usually going to be the chronological order they were recorded in. This view is most helpful for understanding the behavior of an application over time, e.g. "first the data is fetched from the database, then the data is prepared for serialization, then the data is serialized to JSON".
The horizontal axis represents the "weight" of each stack (most commonly CPU time), and the vertical axis shows you the stack active at the time of the sample. If you click on one of the frames, you'll be able to see summary statistics about it.
### ⬅️Left Heavy
![Left Heavy View](https://user-images.githubusercontent.com/150329/44534434-a05f8380-a6ac-11e8-86ac-e3e05e577c52.png)
In the "Left Heavy" view, identical stacks are grouped together, regardless of whether they were recorded sequentially. Then, the stacks are sorted so that the heaviest stack for each parent is on the left -- hence "left heavy". This view is useful for understanding where all the time is going in situations where there are hundreds or thousands of function calls interleaved between other call stacks.
### 🥪 Sandwich
![Sandwich View](https://user-images.githubusercontent.com/150329/42108467-76a57baa-7b8f-11e8-815f-1df7b6ac3ede.png)
The Sandwich view is a table view in which you can find a list of all functions an their associated times. You can sort by self time or total time.
The Sandwich view is a table view in which you can find a list of all functions and their associated times. You can sort by self time or total time.
It's called "Sandwich" view because if you select one of the rows in the table, you can see flamegraphs for all the callers and callees of the selected
row.
![Sandwich View](https://user-images.githubusercontent.com/150329/42108467-76a57baa-7b8f-11e8-815f-1df7b6ac3ede.png)
## Navigation
@@ -118,3 +119,11 @@ Once a profile has loaded, the main view is split into two: the top area is the
* `r`: Collapse recursion in the flamegraphs
* `Cmd+S`/`Ctrl+S` to save the current profile
* `Cmd+O`/`Ctrl+O` to open a new profile
* `n`: Go to next profile/thread if one is available
* `p`: Go to previous profile/thread if one is available
* `t`: Open the profile/thread selector if available
* `Cmd+F`/`Ctrl+F`: to open search. While open, `Enter` and `Shift+Enter` cycle through results
## Contributing
Do you want to contribute to speedscope? Sweeeeet. Check out [CONTRIBUTING.md](./CONTRIBUTING.md) for instructions on setting up your dev environment.
-99
View File
@@ -1,99 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`importSpeedscopeProfiles 0.0.1 evented profile 1`] = `
Object {
"frames": Array [
Frame {
"col": undefined,
"file": undefined,
"key": 0,
"line": undefined,
"name": "a",
"selfWeight": 0,
"totalWeight": 14,
},
Frame {
"col": undefined,
"file": undefined,
"key": 1,
"line": undefined,
"name": "b",
"selfWeight": 5,
"totalWeight": 14,
},
Frame {
"col": undefined,
"file": undefined,
"key": 2,
"line": undefined,
"name": "c",
"selfWeight": 5,
"totalWeight": 5,
},
Frame {
"col": undefined,
"file": undefined,
"key": 3,
"line": undefined,
"name": "d",
"selfWeight": 4,
"totalWeight": 4,
},
],
"stacks": Array [
"a;b;c 2",
"a;b;d 4",
"a;b;c 3",
"a;b 5",
],
}
`;
exports[`importSpeedscopeProfiles 0.1.2 sampled profile 1`] = `
Object {
"frames": Array [
Frame {
"col": undefined,
"file": undefined,
"key": 0,
"line": undefined,
"name": "a",
"selfWeight": 0,
"totalWeight": 14,
},
Frame {
"col": undefined,
"file": undefined,
"key": 1,
"line": undefined,
"name": "b",
"selfWeight": 5,
"totalWeight": 14,
},
Frame {
"col": undefined,
"file": undefined,
"key": 2,
"line": undefined,
"name": "c",
"selfWeight": 5,
"totalWeight": 5,
},
Frame {
"col": undefined,
"file": undefined,
"key": 3,
"line": undefined,
"name": "d",
"selfWeight": 4,
"totalWeight": 4,
},
],
"stacks": Array [
"a;b;c 2.00s",
"a;b;d 4.00s",
"a;b;c 3.00s",
"a;b 5.00s",
],
}
`;
-933
View File
@@ -1,933 +0,0 @@
import {h} from 'preact'
import {StyleSheet, css} from 'aphrodite'
import {ReloadableComponent, SerializedComponent} from './reloadable'
import {FileSystemDirectoryEntry} from './import/file-system-entry'
import {FlamechartRenderer, FlamechartRowAtlasKey} from './flamechart-renderer'
import {CanvasContext} from './canvas-context'
import {Profile, Frame} from './profile'
import {Flamechart} from './flamechart'
import {FlamechartView} from './flamechart-view'
import {FontFamily, FontSize, Colors, Sizes, Duration} from './style'
import {getHashParams, HashParams} from './hash-params'
import {SortMethod, SortField, SortDirection} from './profile-table-view'
import {triangle} from './utils'
import {Color} from './color'
import {RowAtlas} from './row-atlas'
import {importEmscriptenSymbolMap} from './emscripten'
import {SandwichView} from './sandwich-view'
import {saveToFile} from './file-format'
const importModule = import('./import')
// Force eager loading of the module
importModule.then(() => {})
async function importProfile(fileName: string, contents: string): Promise<Profile | null> {
return (await importModule).importProfile(fileName, contents)
}
async function importFromFileSystemDirectoryEntry(entry: FileSystemDirectoryEntry) {
return (await importModule).importFromFileSystemDirectoryEntry(entry)
}
const protocol = window.location.protocol
const canUseXHR = protocol === 'http:' || protocol === 'https:'
declare function require(x: string): any
const exampleProfileURL = require('./sample/profiles/stackcollapse/perf-vertx-stacks-01-collapsed-all.txt')
const enum ViewMode {
CHRONO_FLAME_CHART,
LEFT_HEAVY_FLAME_GRAPH,
SANDWICH_VIEW,
}
interface ApplicationState {
profile: Profile | null
activeProfile: Profile | null
flattenRecursion: boolean
chronoFlamechart: Flamechart | null
chronoFlamechartRenderer: FlamechartRenderer | null
leftHeavyFlamegraph: Flamechart | null
leftHeavyFlamegraphRenderer: FlamechartRenderer | null
tableSortMethod: SortMethod
viewMode: ViewMode
dragActive: boolean
loading: boolean
error: boolean
}
interface ToolbarProps extends ApplicationState {
setViewMode(order: ViewMode): void
browseForFile(): void
saveFile(): void
}
export class Toolbar extends ReloadableComponent<ToolbarProps, void> {
setTimeOrder = () => {
this.props.setViewMode(ViewMode.CHRONO_FLAME_CHART)
}
setLeftHeavyOrder = () => {
this.props.setViewMode(ViewMode.LEFT_HEAVY_FLAME_GRAPH)
}
setSandwichView = () => {
this.props.setViewMode(ViewMode.SANDWICH_VIEW)
}
render() {
const importFile = (
<div className={css(style.toolbarTab)} onClick={this.props.browseForFile}>
<span className={css(style.emoji)}></span>Import
</div>
)
const help = (
<div className={css(style.toolbarTab)}>
<a
href="https://github.com/jlfwong/speedscope#usage"
className={css(style.noLinkStyle)}
target="_blank"
>
<span className={css(style.emoji)}></span>Help
</a>
</div>
)
if (!this.props.profile) {
return (
<div className={css(style.toolbar)}>
🔬speedscope
<div className={css(style.toolbarRight)}>
{importFile}
{help}
</div>
</div>
)
}
return (
<div className={css(style.toolbar)}>
<div className={css(style.toolbarLeft)}>
<div
className={css(
style.toolbarTab,
this.props.viewMode === ViewMode.CHRONO_FLAME_CHART && style.toolbarTabActive,
)}
onClick={this.setTimeOrder}
>
<span className={css(style.emoji)}>🕰</span>Time Order
</div>
<div
className={css(
style.toolbarTab,
this.props.viewMode === ViewMode.LEFT_HEAVY_FLAME_GRAPH && style.toolbarTabActive,
)}
onClick={this.setLeftHeavyOrder}
>
<span className={css(style.emoji)}></span>Left Heavy
</div>
<div
className={css(
style.toolbarTab,
this.props.viewMode === ViewMode.SANDWICH_VIEW && style.toolbarTabActive,
)}
onClick={this.setSandwichView}
>
<span className={css(style.emoji)}>🥪</span>Sandwich
</div>
</div>
{this.props.profile.getName()}
<div className={css(style.toolbarRight)}>
<div className={css(style.toolbarTab)} onClick={this.props.saveFile}>
<span className={css(style.emoji)}></span>Export
</div>
{importFile}
{help}
</div>
</div>
)
}
}
interface GLCanvasProps {
setCanvasContext(canvasContext: CanvasContext | null): void
}
export class GLCanvas extends ReloadableComponent<GLCanvasProps, void> {
private canvas: HTMLCanvasElement | null = null
private canvasContext: CanvasContext | null = null
private ref = (canvas?: Element) => {
if (canvas instanceof HTMLCanvasElement) {
this.canvas = canvas
this.canvasContext = new CanvasContext(canvas)
} else {
this.canvas = null
this.canvasContext = null
}
this.props.setCanvasContext(this.canvasContext)
}
private maybeResize() {
if (!this.canvas) return
let {width, height} = this.canvas.getBoundingClientRect()
width = Math.floor(width) * window.devicePixelRatio
height = Math.floor(height) * window.devicePixelRatio
// Still initializing: don't resize yet
if (width < 4 || height < 4) return
const oldWidth = this.canvas.width
const oldHeight = this.canvas.height
// Already at the right size
if (width === oldWidth && height === oldHeight) return
this.canvas.width = width
this.canvas.height = height
}
onWindowResize = () => {
this.maybeResize()
window.addEventListener('resize', this.onWindowResize)
}
componentDidMount() {
window.addEventListener('resize', this.onWindowResize)
requestAnimationFrame(() => this.maybeResize())
}
componentWillUnmount() {
window.removeEventListener('resize', this.onWindowResize)
}
render() {
return <canvas className={css(style.glCanvasView)} ref={this.ref} width={1} height={1} />
}
}
export class Application extends ReloadableComponent<{}, ApplicationState> {
hashParams: HashParams
constructor() {
super()
this.hashParams = getHashParams()
this.state = {
// Start out at a loading state if we know that we'll immediately be fetching a profile to
// view.
loading:
(canUseXHR && this.hashParams.profileURL != null) ||
this.hashParams.localProfilePath != null,
dragActive: false,
error: false,
profile: null,
activeProfile: null,
flattenRecursion: false,
chronoFlamechart: null,
chronoFlamechartRenderer: null,
leftHeavyFlamegraph: null,
leftHeavyFlamegraphRenderer: null,
tableSortMethod: {
field: SortField.SELF,
direction: SortDirection.DESCENDING,
},
viewMode: ViewMode.CHRONO_FLAME_CHART,
}
}
serialize() {
const result = super.serialize()
delete result.state.chronoFlamechartRenderer
delete result.state.leftHeavyFlamegraphRenderer
return result
}
rehydrate(serialized: SerializedComponent<ApplicationState>) {
super.rehydrate(serialized)
const {chronoFlamechart, leftHeavyFlamegraph} = serialized.state
if (this.canvasContext && this.rowAtlas && chronoFlamechart && leftHeavyFlamegraph) {
this.setState({
chronoFlamechartRenderer: new FlamechartRenderer(
this.canvasContext,
this.rowAtlas,
chronoFlamechart,
),
leftHeavyFlamegraphRenderer: new FlamechartRenderer(
this.canvasContext,
this.rowAtlas,
leftHeavyFlamegraph,
),
})
}
}
async loadProfile(loader: () => Promise<Profile | null>) {
await new Promise(resolve => this.setState({loading: true}, resolve))
await new Promise(resolve => setTimeout(resolve, 0))
if (!this.canvasContext || !this.rowAtlas) return
console.time('import')
let profile: Profile | null = null
try {
profile = await loader()
} catch (e) {
console.log('Failed to load format', e)
this.setState({error: true})
return
}
if (profile == null) {
// TODO(jlfwong): Make this a nicer overlay
alert('Unrecognized format! See documentation about supported formats.')
await new Promise(resolve => this.setState({loading: false}, resolve))
return
}
await profile.demangle()
const title = this.hashParams.title || profile.getName()
profile.setName(title)
await this.setActiveProfile(profile)
console.timeEnd('import')
this.setState({profile})
}
async setActiveProfile(profile: Profile) {
if (!this.canvasContext || !this.rowAtlas) return
document.title = `${profile.getName()} - speedscope`
const frames: Frame[] = []
profile.forEachFrame(f => frames.push(f))
function key(f: Frame) {
return (f.file || '') + f.name
}
function compare(a: Frame, b: Frame) {
return key(a) > key(b) ? 1 : -1
}
frames.sort(compare)
const frameToColorBucket = new Map<string | number, number>()
for (let i = 0; i < frames.length; i++) {
frameToColorBucket.set(frames[i].key, Math.floor(255 * i / frames.length))
}
function getColorBucketForFrame(frame: Frame) {
return frameToColorBucket.get(frame.key) || 0
}
const chronoFlamechart = new Flamechart({
getTotalWeight: profile.getTotalWeight.bind(profile),
forEachCall: profile.forEachCall.bind(profile),
formatValue: profile.formatValue.bind(profile),
getColorBucketForFrame,
})
const chronoFlamechartRenderer = new FlamechartRenderer(
this.canvasContext,
this.rowAtlas,
chronoFlamechart,
)
const leftHeavyFlamegraph = new Flamechart({
getTotalWeight: profile.getTotalNonIdleWeight.bind(profile),
forEachCall: profile.forEachCallGrouped.bind(profile),
formatValue: profile.formatValue.bind(profile),
getColorBucketForFrame,
})
const leftHeavyFlamegraphRenderer = new FlamechartRenderer(
this.canvasContext,
this.rowAtlas,
leftHeavyFlamegraph,
)
await new Promise(resolve => {
this.setState(
{
activeProfile: profile,
chronoFlamechart,
chronoFlamechartRenderer,
leftHeavyFlamegraph,
leftHeavyFlamegraphRenderer,
loading: false,
},
resolve,
)
})
}
loadFromFile(file: File) {
this.loadProfile(async () => {
const reader = new FileReader()
const loadPromise = new Promise(resolve => reader.addEventListener('loadend', resolve))
reader.readAsText(file)
await loadPromise
const profile = await importProfile(file.name, reader.result)
if (profile) {
if (!profile.getName()) {
profile.setName(file.name)
}
return profile
}
if (this.state.profile) {
// If a profile is already loaded, it's possible the file being imported is
// a symbol map. If that's the case, we want to parse it, and apply the symbol
// mapping to the already loaded profile. This can be use to take an opaque
// profile and make it readable.
const map = importEmscriptenSymbolMap(reader.result)
if (map) {
console.log('Importing as emscripten symbol map')
let profile = this.state.profile
profile.remapNames(name => map.get(name) || name)
return profile
}
}
return null
})
}
loadExample = () => {
this.loadProfile(async () => {
const filename = 'perf-vertx-stacks-01-collapsed-all.txt'
const data = await fetch(exampleProfileURL).then(resp => resp.text())
const profile = await importProfile(filename, data)
if (profile && !profile.getName()) {
profile.setName(filename)
}
return profile
})
}
onDrop = (ev: DragEvent) => {
this.setState({dragActive: false})
ev.preventDefault()
const firstItem = ev.dataTransfer.items[0]
if ('webkitGetAsEntry' in firstItem) {
const webkitEntry: FileSystemDirectoryEntry = firstItem.webkitGetAsEntry()
// Instrument.app file format is actually a directory.
if (webkitEntry.isDirectory && webkitEntry.name.endsWith('.trace')) {
console.log('Importing as Instruments.app .trace file')
this.loadProfile(async () => await importFromFileSystemDirectoryEntry(webkitEntry))
return
}
}
let file: File | null = ev.dataTransfer.files.item(0)
if (file) {
this.loadFromFile(file)
}
}
onDragOver = (ev: DragEvent) => {
this.setState({dragActive: true})
ev.preventDefault()
}
onDragLeave = (ev: DragEvent) => {
this.setState({dragActive: false})
ev.preventDefault()
}
onWindowKeyPress = async (ev: KeyboardEvent) => {
if (ev.key === '1') {
this.setState({
viewMode: ViewMode.CHRONO_FLAME_CHART,
})
} else if (ev.key === '2') {
this.setState({
viewMode: ViewMode.LEFT_HEAVY_FLAME_GRAPH,
})
} else if (ev.key === '3') {
this.setState({
viewMode: ViewMode.SANDWICH_VIEW,
})
} else if (ev.key === 'r') {
const {flattenRecursion, profile} = this.state
if (!profile) return
if (flattenRecursion) {
await this.setActiveProfile(profile)
this.setState({flattenRecursion: false})
} else {
await this.setActiveProfile(profile.getProfileWithRecursionFlattened())
this.setState({flattenRecursion: true})
}
}
}
private saveFile = () => {
if (this.state.profile) {
saveToFile(this.state.profile)
}
}
private browseForFile = () => {
const input = document.createElement('input')
input.type = 'file'
input.addEventListener('change', this.onFileSelect)
input.click()
}
private onWindowKeyDown = async (ev: KeyboardEvent) => {
// This has to be handled on key down in order to prevent the default
// page save action.
if (ev.key === 's' && (ev.ctrlKey || ev.metaKey)) {
ev.preventDefault()
this.saveFile()
} else if (ev.key === 'o' && (ev.ctrlKey || ev.metaKey)) {
ev.preventDefault()
this.browseForFile()
}
}
onDocumentPaste = (ev: Event) => {
ev.preventDefault()
ev.stopPropagation()
const pasted = (ev as ClipboardEvent).clipboardData.getData('text')
this.loadProfile(async () => importProfile('From Clipboard', pasted))
}
componentDidMount() {
window.addEventListener('keydown', this.onWindowKeyDown)
window.addEventListener('keypress', this.onWindowKeyPress)
document.addEventListener('paste', this.onDocumentPaste)
this.maybeLoadHashParamProfile()
}
componentWillUnmount() {
window.removeEventListener('keydown', this.onWindowKeyDown)
window.removeEventListener('keypress', this.onWindowKeyPress)
document.removeEventListener('paste', this.onDocumentPaste)
}
async maybeLoadHashParamProfile() {
if (this.hashParams.profileURL) {
if (!canUseXHR) {
alert(`Cannot load a profile URL when loading from "${protocol}" URL protocol`)
return
}
this.loadProfile(async () => {
const response = await fetch(this.hashParams.profileURL!)
let filename = new URL(this.hashParams.profileURL!).pathname
if (filename.includes('/')) {
filename = filename.slice(filename.lastIndexOf('/') + 1)
}
return await importProfile(filename, await response.text())
})
} else if (this.hashParams.localProfilePath) {
// There isn't good cross-browser support for XHR of local files, even from
// other local files. To work around this restriction, we load the local profile
// as a JavaScript file which will invoke a global function.
;(window as any)['speedscope'] = {
loadFileFromBase64: (filename: string, base64source: string) => {
const source = atob(base64source)
this.loadProfile(() => importProfile(filename, source))
},
}
const script = document.createElement('script')
script.src = `file:///${this.hashParams.localProfilePath}`
document.head.appendChild(script)
}
}
flamechartView: FlamechartView | null = null
flamechartRef = (view: FlamechartView | null) => (this.flamechartView = view)
subcomponents() {
return {
flamechart: this.flamechartView,
}
}
onFileSelect = (ev: Event) => {
const file = (ev.target as HTMLInputElement).files!.item(0)
if (file) {
this.loadFromFile(file)
}
}
renderLanding() {
return (
<div className={css(style.landingContainer)}>
<div className={css(style.landingMessage)}>
<p className={css(style.landingP)}>
👋 Hi there! Welcome to 🔬speedscope, an interactive{' '}
<a
className={css(style.link)}
href="http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html"
>
flamegraph
</a>{' '}
visualizer. Use it to help you make your software faster.
</p>
{canUseXHR ? (
<p className={css(style.landingP)}>
Drag and drop a profile file onto this window to get started, click the big blue
button below to browse for a profile to explore, or{' '}
<a tabIndex={0} className={css(style.link)} onClick={this.loadExample}>
click here
</a>{' '}
to load an example profile.
</p>
) : (
<p className={css(style.landingP)}>
Drag and drop a profile file onto this window to get started, or click the big blue
button below to browse for a profile to explore.
</p>
)}
<div className={css(style.browseButtonContainer)}>
<input
type="file"
name="file"
id="file"
onChange={this.onFileSelect}
className={css(style.hide)}
/>
<label for="file" className={css(style.browseButton)} tabIndex={0}>
Browse
</label>
</div>
<p className={css(style.landingP)}>
See the{' '}
<a
className={css(style.link)}
href="https://github.com/jlfwong/speedscope#usage"
target="_blank"
>
documentation
</a>{' '}
for information about supported file formats, keyboard shortcuts, and how to navigate
around the profile.
</p>
<p className={css(style.landingP)}>
speedscope is open source. Please{' '}
<a
className={css(style.link)}
target="_blank"
href="https://github.com/jlfwong/speedscope/issues"
>
report any issues on GitHub
</a>.
</p>
</div>
</div>
)
}
renderError() {
return (
<div className={css(style.error)}>
<div>😿 Something went wrong.</div>
<div>Check the JS console for more details.</div>
</div>
)
}
renderLoadingBar() {
return <div className={css(style.loading)} />
}
setViewMode = (viewMode: ViewMode) => {
this.setState({viewMode})
}
setTableSortMethod = (tableSortMethod: SortMethod) => {
this.setState({tableSortMethod})
}
private canvasContext: CanvasContext | null = null
private rowAtlas: RowAtlas<FlamechartRowAtlasKey> | null = null
private setCanvasContext = (canvasContext: CanvasContext | null) => {
this.canvasContext = canvasContext
if (canvasContext) {
this.rowAtlas = new RowAtlas(canvasContext)
} else {
this.rowAtlas = null
}
}
getColorBucketForFrame = (frame: Frame): number => {
const {chronoFlamechart} = this.state
if (!chronoFlamechart) return 0
return chronoFlamechart.getColorBucketForFrame(frame)
}
getCSSColorForFrame = (frame: Frame): string => {
const {chronoFlamechart} = this.state
if (!chronoFlamechart) return '#FFFFFF'
const t = chronoFlamechart.getColorBucketForFrame(frame) / 255
const x = triangle(30.0 * t)
const H = 360.0 * (0.9 * t)
const C = 0.25 + 0.2 * x
const L = 0.8 - 0.15 * x
return Color.fromLumaChromaHue(L, C, H).toCSS()
}
renderContent() {
const {viewMode} = this.state
if (this.state.error) {
return this.renderError()
}
if (this.state.loading) {
return this.renderLoadingBar()
}
if (!this.state.activeProfile) {
return this.renderLanding()
}
if (!this.canvasContext) {
throw new Error('Missing canvas context')
}
switch (viewMode) {
case ViewMode.CHRONO_FLAME_CHART: {
const {chronoFlamechart, chronoFlamechartRenderer} = this.state
if (!chronoFlamechart || !chronoFlamechartRenderer)
throw new Error('Missing dependencies for chrono flame chart')
return (
<FlamechartView
canvasContext={this.canvasContext}
flamechartRenderer={chronoFlamechartRenderer}
ref={this.flamechartRef}
flamechart={chronoFlamechart}
getCSSColorForFrame={this.getCSSColorForFrame}
/>
)
}
case ViewMode.LEFT_HEAVY_FLAME_GRAPH: {
const {leftHeavyFlamegraph, leftHeavyFlamegraphRenderer} = this.state
if (!leftHeavyFlamegraph || !leftHeavyFlamegraphRenderer)
throw new Error('Missing dependencies for left heavy flame graph')
return (
<FlamechartView
canvasContext={this.canvasContext}
flamechartRenderer={leftHeavyFlamegraphRenderer}
ref={this.flamechartRef}
flamechart={leftHeavyFlamegraph}
getCSSColorForFrame={this.getCSSColorForFrame}
/>
)
}
case ViewMode.SANDWICH_VIEW: {
if (!this.rowAtlas || !this.state.profile) return null
return (
<SandwichView
profile={this.state.profile}
flattenRecursion={this.state.flattenRecursion}
getColorBucketForFrame={this.getColorBucketForFrame}
getCSSColorForFrame={this.getCSSColorForFrame}
sortMethod={this.state.tableSortMethod}
setSortMethod={this.setTableSortMethod}
canvasContext={this.canvasContext}
rowAtlas={this.rowAtlas}
/>
)
}
}
}
render() {
return (
<div
onDrop={this.onDrop}
onDragOver={this.onDragOver}
onDragLeave={this.onDragLeave}
className={css(style.root, this.state.dragActive && style.dragTargetRoot)}
>
<GLCanvas setCanvasContext={this.setCanvasContext} />
<Toolbar
setViewMode={this.setViewMode}
saveFile={this.saveFile}
browseForFile={this.browseForFile}
{...this.state}
/>
<div className={css(style.contentContainer)}>{this.renderContent()}</div>
{this.state.dragActive && <div className={css(style.dragTarget)} />}
</div>
)
}
}
const style = StyleSheet.create({
glCanvasView: {
position: 'absolute',
width: '100vw',
height: '100vh',
zIndex: -1,
pointerEvents: 'none',
},
error: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
},
loading: {
height: 3,
marginBottom: -3,
background: Colors.DARK_BLUE,
transformOrigin: '0% 50%',
animationName: [
{
from: {
transform: `scaleX(0)`,
},
to: {
transform: `scaleX(1)`,
},
},
],
animationTimingFunction: 'cubic-bezier(0, 1, 0, 1)',
animationDuration: '30s',
},
root: {
width: '100vw',
height: '100vh',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
position: 'relative',
fontFamily: FontFamily.MONOSPACE,
lineHeight: '20px',
},
dragTargetRoot: {
cursor: 'copy',
},
dragTarget: {
boxSizing: 'border-box',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
border: `5px dashed ${Colors.DARK_BLUE}`,
pointerEvents: 'none',
},
contentContainer: {
position: 'relative',
display: 'flex',
overflow: 'hidden',
flexDirection: 'column',
flex: 1,
},
landingContainer: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
},
landingMessage: {
maxWidth: 600,
},
landingP: {
marginBottom: 16,
},
hide: {
display: 'none',
},
browseButtonContainer: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
browseButton: {
marginBottom: 16,
height: 72,
flex: 1,
maxWidth: 256,
textAlign: 'center',
fontSize: FontSize.BIG_BUTTON,
lineHeight: '72px',
background: Colors.DARK_BLUE,
color: Colors.WHITE,
transition: `all ${Duration.HOVER_CHANGE} ease-in`,
':hover': {
background: Colors.BRIGHT_BLUE,
},
},
link: {
color: Colors.BRIGHT_BLUE,
cursor: 'pointer',
textDecoration: 'none',
},
toolbar: {
height: Sizes.TOOLBAR_HEIGHT,
flexShrink: 0,
background: Colors.BLACK,
color: Colors.WHITE,
textAlign: 'center',
fontFamily: FontFamily.MONOSPACE,
fontSize: FontSize.TITLE,
lineHeight: `${Sizes.TOOLBAR_TAB_HEIGHT}px`,
userSelect: 'none',
},
toolbarLeft: {
position: 'absolute',
height: Sizes.TOOLBAR_HEIGHT,
overflow: 'hidden',
top: 0,
left: 0,
marginRight: 2,
textAlign: 'left',
},
toolbarRight: {
height: Sizes.TOOLBAR_HEIGHT,
overflow: 'hidden',
position: 'absolute',
top: 0,
right: 0,
marginRight: 2,
textAlign: 'right',
},
toolbarTab: {
background: Colors.DARK_GRAY,
marginTop: Sizes.SEPARATOR_HEIGHT,
height: Sizes.TOOLBAR_TAB_HEIGHT,
lineHeight: `${Sizes.TOOLBAR_TAB_HEIGHT}px`,
paddingLeft: 2,
paddingRight: 8,
display: 'inline-block',
marginLeft: 2,
transition: `all ${Duration.HOVER_CHANGE} ease-in`,
':hover': {
background: Colors.GRAY,
},
},
toolbarTabActive: {
background: Colors.BRIGHT_BLUE,
':hover': {
background: Colors.BRIGHT_BLUE,
},
},
noLinkStyle: {
textDecoration: 'none',
color: 'inherit',
},
emoji: {
display: 'inline-block',
verticalAlign: 'middle',
paddingTop: '0px',
marginRight: '0.3em',
},
})
View File
+1 -2
View File
@@ -166,8 +166,7 @@
</head>
<body>
<div id="root"></div>
<script src="./speedscope.tsx"></script>
<script src="../src/speedscope.tsx"></script>
</body>
</html>
View File
+22 -8
View File
@@ -4,7 +4,7 @@ const fs = require('fs')
const os = require('os')
const stream = require('stream')
const opn = require('opn')
const open = require('open')
const helpString = `Usage: speedscope [filepath]
@@ -52,7 +52,7 @@ async function main() {
}
if (process.argv.includes('--version') || process.argv.includes('-v')) {
console.log('v' + require('./package.json').version)
console.log('v' + require('../package.json').version)
return
}
@@ -60,16 +60,26 @@ async function main() {
throw new Error('At most one argument expected')
}
let urlToOpen = 'file://' + path.resolve(__dirname, './dist/release/index.html')
let urlToOpen = 'file://' + path.resolve(__dirname, '../dist/release/index.html')
if (process.argv.length === 3) {
const relPath = process.argv[2]
const sourceBuffer = await getProfileBuffer(relPath)
const filename = path.basename(relPath)
const sourceBase64 = sourceBuffer.toString('base64')
const jsSource = `speedscope.loadFileFromBase64(${JSON.stringify(filename)}, ${JSON.stringify(
sourceBase64,
)})`
let jsSource
try {
const sourceBase64 = sourceBuffer.toString('base64')
jsSource = `speedscope.loadFileFromBase64(${JSON.stringify(filename)}, ${JSON.stringify(
sourceBase64,
)})`
} catch(e) {
if (e && e.message && /Cannot create a string longer than/.exec(e.message)) {
jsSource = `alert("Sorry, ${filename} is too large to be loaded via command-line argument! Try dragging it into speedscope instead.")`
} else {
throw e
}
}
const filePrefix = `speedscope-${+new Date()}-${process.pid}`
const jsPath = path.join(os.tmpdir(), `${filePrefix}.js`)
@@ -89,7 +99,11 @@ async function main() {
console.log('Opening', urlToOpen, 'in your default browser')
await opn(urlToOpen, {wait: false})
// We'd like to avoid blocking the terminal on the browsing closing,
// but for some reason this doesn't work at all on Windows if we
// don't use wait: true.
const wait = process.platform === "win32";
await open(urlToOpen, {wait})
}
main()
-192
View File
@@ -1,192 +0,0 @@
import regl from 'regl'
import {
RectangleBatchRenderer,
RectangleBatch,
RectangleBatchRendererProps,
} from './rectangle-batch-renderer'
import {
ViewportRectangleRenderer,
ViewportRectangleRendererProps,
} from './overlay-rectangle-renderer'
import {
TextureCachedRenderer,
TextureRenderer,
TextureRendererProps,
} from './texture-cached-renderer'
import {StatsPanel} from './stats'
import {Vec2, Rect} from './math'
import {
FlamechartColorPassRenderer,
FlamechartColorPassRenderProps,
} from './flamechart-color-pass-renderer'
type FrameCallback = () => void
interface SetViewportScopeProps {
physicalBounds: Rect
}
export class CanvasContext {
public gl: regl.Instance
private rectangleBatchRenderer: RectangleBatchRenderer
private viewportRectangleRenderer: ViewportRectangleRenderer
private textureRenderer: TextureRenderer
private flamechartColorPassRenderer: FlamechartColorPassRenderer
private setViewportScope: regl.Command<{physicalBounds: Rect}>
private setScissor: regl.Command<{}>
constructor(canvas: HTMLCanvasElement) {
this.gl = regl({
canvas: canvas,
attributes: {
antialias: false,
},
extensions: ['ANGLE_instanced_arrays', 'WEBGL_depth_texture'],
optionalExtensions: ['EXT_disjoint_timer_query'],
profile: true,
})
console.log(
`WebGL initialized. renderer: ${this.gl.limits.renderer}, vendor: ${
this.gl.limits.vendor
}, version: ${this.gl.limits.version}`,
)
;(window as any)['CanvasContext'] = this
this.rectangleBatchRenderer = new RectangleBatchRenderer(this.gl)
this.viewportRectangleRenderer = new ViewportRectangleRenderer(this.gl)
this.textureRenderer = new TextureRenderer(this.gl)
this.flamechartColorPassRenderer = new FlamechartColorPassRenderer(this.gl)
this.setScissor = this.gl({scissor: {enable: true}})
this.setViewportScope = this.gl<SetViewportScopeProps>({
context: {
viewportX: (context: regl.Context, props: SetViewportScopeProps) => {
return props.physicalBounds.left()
},
viewportY: (context: regl.Context, props: SetViewportScopeProps) => {
return props.physicalBounds.top()
},
},
viewport: (context, props) => {
const {physicalBounds} = props
return {
x: physicalBounds.left(),
y:
window.devicePixelRatio * window.innerHeight -
physicalBounds.top() -
physicalBounds.height(),
width: physicalBounds.width(),
height: physicalBounds.height(),
}
},
scissor: (context, props) => {
const {physicalBounds} = props
return {
enable: true,
box: {
x: physicalBounds.left(),
y:
window.devicePixelRatio * window.innerHeight -
physicalBounds.top() -
physicalBounds.height(),
width: physicalBounds.width(),
height: physicalBounds.height(),
},
}
},
})
}
private tick: regl.Tick | null = null
private tickNeeded: boolean = false
private beforeFrameHandlers = new Set<FrameCallback>()
addBeforeFrameHandler(callback: FrameCallback) {
this.beforeFrameHandlers.add(callback)
}
removeBeforeFrameHandler(callback: FrameCallback) {
this.beforeFrameHandlers.delete(callback)
}
requestFrame() {
this.tickNeeded = true
if (!this.tick) {
this.tick = this.gl.frame(this.onBeforeFrame)
}
}
private perfDebug = window.location.href.indexOf('perf-debug=1') !== -1
private statsPanel: StatsPanel | null = this.perfDebug ? new StatsPanel() : null
private onBeforeFrame = (context: regl.Context) => {
this.setScissor(() => {
this.gl.clear({color: [0, 0, 0, 0]})
})
this.tickNeeded = false
this.statsPanel && this.statsPanel.begin()
for (const handler of this.beforeFrameHandlers) {
handler()
}
this.statsPanel && this.statsPanel.end()
if (this.tick && !this.tickNeeded) {
if (!this.perfDebug) {
this.tick.cancel()
this.tick = null
}
}
// TODO(jlfwong): It would be really nice to have GPU
// stats here, but I can't figure out how to interpret
// the gpuTime. I suspect this is caused by executing the same
// program multiple times without flushing.
// I'll investigate this at some point and report a bug to regl.
}
drawRectangleBatch(props: RectangleBatchRendererProps) {
this.rectangleBatchRenderer.render(props)
}
drawTexture(props: TextureRendererProps) {
this.textureRenderer.render(props)
}
drawFlamechartColorPass(props: FlamechartColorPassRenderProps) {
this.flamechartColorPassRenderer.render(props)
}
createRectangleBatch(): RectangleBatch {
return new RectangleBatch(this.gl)
}
createTextureCachedRenderer<T>(options: {
render(t: T): void
shouldUpdate(oldProps: T, newProps: T): boolean
}): TextureCachedRenderer<T> {
return new TextureCachedRenderer(this.gl, {
...options,
textureRenderer: this.textureRenderer,
})
}
drawViewportRectangle(props: ViewportRectangleRendererProps) {
this.viewportRectangleRenderer.render(props)
}
renderInto(el: Element, cb: (context: regl.Context) => void) {
const bounds = el.getBoundingClientRect()
const physicalBounds = new Rect(
new Vec2(bounds.left * window.devicePixelRatio, bounds.top * window.devicePixelRatio),
new Vec2(bounds.width * window.devicePixelRatio, bounds.height * window.devicePixelRatio),
)
this.setViewportScope({physicalBounds}, cb)
}
setViewport(physicalBounds: Rect, cb: (context: regl.Context) => void) {
this.setViewportScope({physicalBounds}, cb)
}
getMaxTextureSize() {
return this.gl.limits.maxTextureSize
}
}
-26
View File
@@ -1,26 +0,0 @@
import {h, Component} from 'preact'
import {StyleSheet, css} from 'aphrodite'
import {Colors, FontSize} from './style'
interface ColorChitProps {
color: string
}
export class ColorChit extends Component<ColorChitProps, {}> {
render() {
return <span className={css(style.stackChit)} style={{backgroundColor: this.props.color}} />
}
}
const style = StyleSheet.create({
stackChit: {
position: 'relative',
top: -1,
display: 'inline-block',
verticalAlign: 'middle',
marginRight: '0.5em',
border: `1px solid ${Colors.LIGHT_GRAY}`,
width: FontSize.LABEL - 2,
height: FontSize.LABEL - 2,
},
})
-37
View File
@@ -1,37 +0,0 @@
export class Color {
constructor(
readonly r: number = 0,
readonly g: number = 0,
readonly b: number = 0,
readonly a: number = 1,
) {}
static fromLumaChromaHue(L: number, C: number, H: number) {
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_luma/chroma/hue
const hPrime = H / 60
const X = C * (1 - Math.abs(hPrime % 2 - 1))
const [R1, G1, B1] =
hPrime < 1
? [C, X, 0]
: hPrime < 2
? [X, C, 0]
: hPrime < 3
? [0, C, X]
: hPrime < 4
? [0, X, C]
: hPrime < 5
? [X, 0, C]
: [C, 0, X]
const m = L - (0.3 * R1 + 0.59 * G1 + 0.11 * B1)
return new Color(R1 + m, G1 + m, B1 + m, 1.0)
}
toCSS(): string {
return `rgba(${(255 * this.r).toFixed()}, ${(255 * this.g).toFixed()}, ${(
255 * this.b
).toFixed()}, ${this.a.toFixed(2)})`
}
}
-76
View File
@@ -1,76 +0,0 @@
import {importEmscriptenSymbolMap} from './emscripten'
test('importEmscriptenSymbolMap', () => {
// Valid symbol map
expect(
importEmscriptenSymbolMap(
[
/* prettier: ignore */
'a:A',
'b:B',
'c:C',
].join('\n'),
),
).toEqual(new Map([['a', 'A'], ['b', 'B'], ['c', 'C']]))
// Valid symbol map with trailing newline
expect(
importEmscriptenSymbolMap(
[
/* prettier: ignore */
'a:A',
'b:B',
'c:C',
'',
].join('\n'),
),
).toEqual(new Map([['a', 'A'], ['b', 'B'], ['c', 'C']]))
// Valid symbol map with non-alpha characters
expect(importEmscriptenSymbolMap('u6:__ZN8tinyxml210XMLCommentD0Ev\n')).toEqual(
new Map([['u6', '__ZN8tinyxml210XMLCommentD0Ev']]),
)
// WebAssembly symbol map
expect(
importEmscriptenSymbolMap(
[
/* prettier: ignore */
'0:A',
'1:B',
'2:C',
].join('\n'),
),
).toEqual(
new Map([['wasm-function[0]', 'A'], ['wasm-function[1]', 'B'], ['wasm-function[2]', 'C']]),
)
// Invalid symbol map
expect(
importEmscriptenSymbolMap(
[
/* prettier: ignore */
'a:A',
'b:B',
'c',
'',
].join('\n'),
),
).toEqual(null)
// Collapsed stack format should not be imported as an asm.js symbol map
expect(
importEmscriptenSymbolMap(
[
/* prettier: ignore */
'a;b 1',
'a;c 3',
'',
].join('\n'),
),
).toEqual(null)
// Unrelated files
expect(importEmscriptenSymbolMap('')).toEqual(null)
expect(importEmscriptenSymbolMap('\n')).toEqual(null)
})
-11
View File
@@ -1,11 +0,0 @@
import {checkProfileSnapshot} from './test-utils'
describe('importSpeedscopeProfiles', async () => {
test('0.0.1 evented profile', async () => {
await checkProfileSnapshot('./sample/profiles/speedscope/0.0.1/simple.speedscope.json')
})
test('0.1.2 sampled profile', async () => {
await checkProfileSnapshot('./sample/profiles/speedscope/0.1.2/simple-sampled.speedscope.json')
})
})
-165
View File
@@ -1,165 +0,0 @@
import regl from 'regl'
import {Vec2, Rect, AffineTransform} from './math'
export interface FlamechartColorPassRenderProps {
rectInfoTexture: regl.Texture
renderOutlines: boolean
srcRect: Rect
dstRect: Rect
}
export class FlamechartColorPassRenderer {
private command: regl.Command<FlamechartColorPassRenderProps>
constructor(gl: regl.Instance) {
this.command = gl({
vert: `
uniform mat3 uvTransform;
uniform mat3 positionTransform;
attribute vec2 position;
attribute vec2 uv;
varying vec2 vUv;
void main() {
vUv = (uvTransform * vec3(uv, 1)).xy;
gl_Position = vec4((positionTransform * vec3(position, 1)).xy, 0, 1);
}
`,
frag: `
precision mediump float;
uniform vec2 uvSpacePixelSize;
uniform float renderOutlines;
varying vec2 vUv;
uniform sampler2D colorTexture;
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_luma/chroma/hue
vec3 hcl2rgb(float H, float C, float L) {
float hPrime = H / 60.0;
float X = C * (1.0 - abs(mod(hPrime, 2.0) - 1.0));
vec3 RGB =
hPrime < 1.0 ? vec3(C, X, 0) :
hPrime < 2.0 ? vec3(X, C, 0) :
hPrime < 3.0 ? vec3(0, C, X) :
hPrime < 4.0 ? vec3(0, X, C) :
hPrime < 5.0 ? vec3(X, 0, C) :
vec3(C, 0, X);
float m = L - dot(RGB, vec3(0.30, 0.59, 0.11));
return RGB + vec3(m, m, m);
}
float triangle(float x) {
return 2.0 * abs(fract(x) - 0.5) - 1.0;
}
vec3 colorForBucket(float t) {
float x = triangle(30.0 * t);
float H = 360.0 * (0.9 * t);
float C = 0.25 + 0.2 * x;
float L = 0.80 - 0.15 * x;
return hcl2rgb(H, C, L);
}
void main() {
vec4 here = texture2D(colorTexture, vUv);
if (here.z == 0.0) {
// Background color
gl_FragColor = vec4(0, 0, 0, 0);
return;
}
// Sample the 4 surrounding pixels in the depth texture to determine
// if we should draw a boundary here or not.
vec4 N = texture2D(colorTexture, vUv + vec2(0, uvSpacePixelSize.y));
vec4 E = texture2D(colorTexture, vUv + vec2(uvSpacePixelSize.x, 0));
vec4 S = texture2D(colorTexture, vUv + vec2(0, -uvSpacePixelSize.y));
vec4 W = texture2D(colorTexture, vUv + vec2(-uvSpacePixelSize.x, 0));
// NOTE: For outline checks, we intentionally check both the right
// and the left to determine if we're an edge. If a rectangle is a single
// pixel wide, we don't want to render it as an outline, so this method
// of checking ensures that we don't outline single physical-space
// pixel width rectangles.
if (
renderOutlines > 0.0 &&
(
here.y == N.y && here.y != S.y || // Top edge
here.y == S.y && here.y != N.y || // Bottom edge
here.x == E.x && here.x != W.x || // Left edge
here.x == W.x && here.x != E.x
)
) {
// We're on an edge! Draw transparent.
gl_FragColor = vec4(0, 0, 0, 0);
} else {
// Not on an edge. Draw the appropriate color;
gl_FragColor = vec4(colorForBucket(here.z), here.a);
}
}
`,
depth: {
enable: false,
},
attributes: {
// Cover full canvas with a rectangle
// with 2 triangles using a triangle
// strip.
//
// 0 +--+ 1
// | /|
// |/ |
// 2 +--+ 3
position: gl.buffer([[-1, 1], [1, 1], [-1, -1], [1, -1]]),
uv: gl.buffer([[0, 1], [1, 1], [0, 0], [1, 0]]),
},
count: 4,
primitive: 'triangle strip',
uniforms: {
colorTexture: (context, props) => props.rectInfoTexture,
uvTransform: (context, props) => {
const {srcRect, rectInfoTexture} = props
const physicalToUV = AffineTransform.withTranslation(new Vec2(0, 1))
.times(AffineTransform.withScale(new Vec2(1, -1)))
.times(
AffineTransform.betweenRects(
new Rect(Vec2.zero, new Vec2(rectInfoTexture.width, rectInfoTexture.height)),
Rect.unit,
),
)
const uvRect = physicalToUV.transformRect(srcRect)
return AffineTransform.betweenRects(Rect.unit, uvRect).flatten()
},
renderOutlines: (context, props) => {
return props.renderOutlines ? 1.0 : 0.0
},
uvSpacePixelSize: (context, props) => {
return Vec2.unit
.dividedByPointwise(new Vec2(props.rectInfoTexture.width, props.rectInfoTexture.height))
.flatten()
},
positionTransform: (context, props) => {
const {dstRect} = props
const viewportSize = new Vec2(context.viewportWidth, context.viewportHeight)
const physicalToNDC = AffineTransform.withScale(new Vec2(1, -1)).times(
AffineTransform.betweenRects(new Rect(Vec2.zero, viewportSize), Rect.NDC),
)
const ndcRect = physicalToNDC.transformRect(dstRect)
return AffineTransform.betweenRects(Rect.NDC, ndcRect).flatten()
},
},
})
}
render(props: FlamechartColorPassRenderProps) {
this.command(props)
}
}
-123
View File
@@ -1,123 +0,0 @@
import {StyleDeclarationValue, css} from 'aphrodite'
import {ReloadableComponent} from './reloadable'
import {h} from 'preact'
import {style} from './flamechart-style'
import {formatPercent} from './utils'
import {Frame, CallTreeNode} from './profile'
import {ColorChit} from './color-chit'
import {Flamechart} from './flamechart'
interface StatisticsTableProps {
title: string
grandTotal: number
selectedTotal: number
selectedSelf: number
cellStyle: StyleDeclarationValue
formatter: (v: number) => string
}
class StatisticsTable extends ReloadableComponent<StatisticsTableProps, {}> {
render() {
const total = this.props.formatter(this.props.selectedTotal)
const self = this.props.formatter(this.props.selectedSelf)
const totalPerc = 100.0 * this.props.selectedTotal / this.props.grandTotal
const selfPerc = 100.0 * this.props.selectedSelf / this.props.grandTotal
return (
<div className={css(style.statsTable)}>
<div className={css(this.props.cellStyle, style.statsTableCell, style.statsTableHeader)}>
{this.props.title}
</div>
<div className={css(this.props.cellStyle, style.statsTableCell)}>Total</div>
<div className={css(this.props.cellStyle, style.statsTableCell)}>Self</div>
<div className={css(this.props.cellStyle, style.statsTableCell)}>{total}</div>
<div className={css(this.props.cellStyle, style.statsTableCell)}>{self}</div>
<div className={css(this.props.cellStyle, style.statsTableCell)}>
{formatPercent(totalPerc)}
<div className={css(style.barDisplay)} style={{height: `${totalPerc}%`}} />
</div>
<div className={css(this.props.cellStyle, style.statsTableCell)}>
{formatPercent(selfPerc)}
<div className={css(style.barDisplay)} style={{height: `${selfPerc}%`}} />
</div>
</div>
)
}
}
interface StackTraceViewProps {
getFrameColor: (frame: Frame) => string
node: CallTreeNode
}
class StackTraceView extends ReloadableComponent<StackTraceViewProps, {}> {
render() {
const rows: JSX.Element[] = []
let node: CallTreeNode | null = this.props.node
for (; node && !node.isRoot(); node = node.parent) {
const row: (JSX.Element | string)[] = []
const {frame} = node
row.push(<ColorChit color={this.props.getFrameColor(frame)} />)
if (rows.length) {
row.push(<span className={css(style.stackFileLine)}>> </span>)
}
row.push(frame.name)
if (frame.file) {
let pos = frame.file
if (frame.line) {
pos += `:${frame.line}`
if (frame.col) {
pos += `:${frame.col}`
}
}
row.push(<span className={css(style.stackFileLine)}> ({pos})</span>)
}
rows.push(<div className={css(style.stackLine)}>{row}</div>)
}
return (
<div className={css(style.stackTraceView)}>
<div className={css(style.stackTraceViewPadding)}>{rows}</div>
</div>
)
}
}
interface FlamechartDetailViewProps {
flamechart: Flamechart
getCSSColorForFrame: (frame: Frame) => string
selectedNode: CallTreeNode
}
export class FlamechartDetailView extends ReloadableComponent<FlamechartDetailViewProps, {}> {
render() {
const {flamechart, selectedNode} = this.props
const {frame} = selectedNode
return (
<div className={css(style.detailView)}>
<StatisticsTable
title={'This Instance'}
cellStyle={style.thisInstanceCell}
grandTotal={flamechart.getTotalWeight()}
selectedTotal={selectedNode.getTotalWeight()}
selectedSelf={selectedNode.getSelfWeight()}
formatter={flamechart.formatValue.bind(flamechart)}
/>
<StatisticsTable
title={'All Instances'}
cellStyle={style.allInstancesCell}
grandTotal={flamechart.getTotalWeight()}
selectedTotal={frame.getTotalWeight()}
selectedSelf={frame.getSelfWeight()}
formatter={flamechart.formatValue.bind(flamechart)}
/>
<StackTraceView node={selectedNode} getFrameColor={this.props.getCSSColorForFrame} />
</div>
)
}
}
-82
View File
@@ -1,82 +0,0 @@
import {StyleSheet} from 'aphrodite'
import {FontSize, Colors, Sizes} from './style'
export const style = StyleSheet.create({
hoverCount: {
color: Colors.GREEN,
},
fill: {
width: '100%',
height: '100%',
position: 'absolute',
left: 0,
top: 0,
},
minimap: {
height: Sizes.MINIMAP_HEIGHT,
borderBottom: `${Sizes.SEPARATOR_HEIGHT}px solid ${Colors.LIGHT_GRAY}`,
},
panZoomView: {
flex: 1,
},
detailView: {
display: 'grid',
height: Sizes.DETAIL_VIEW_HEIGHT,
overflow: 'hidden',
gridTemplateColumns: '120px 120px 1fr',
gridTemplateRows: 'repeat(4, 1fr)',
borderTop: `${Sizes.SEPARATOR_HEIGHT}px solid ${Colors.LIGHT_GRAY}`,
fontSize: FontSize.LABEL,
position: 'absolute',
background: Colors.WHITE,
width: '100vw',
bottom: 0,
},
stackTraceViewPadding: {
padding: 5,
},
stackTraceView: {
height: Sizes.DETAIL_VIEW_HEIGHT,
lineHeight: `${FontSize.LABEL + 2}px`,
overflow: 'auto',
},
stackLine: {
whiteSpace: 'nowrap',
},
stackFileLine: {
color: Colors.LIGHT_GRAY,
},
statsTable: {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gridTemplateRows: `repeat(3, ${FontSize.LABEL + 10}px)`,
gridGap: '1px 1px',
textAlign: 'center',
paddingRight: 1,
},
statsTableHeader: {
gridColumn: '1 / 3',
},
statsTableCell: {
position: 'relative',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
thisInstanceCell: {
background: Colors.DARK_BLUE,
color: Colors.WHITE,
},
allInstancesCell: {
background: Colors.PALE_DARK_BLUE,
color: Colors.WHITE,
},
barDisplay: {
position: 'absolute',
top: 0,
left: 0,
background: 'rgba(0, 0, 0, 0.2)',
width: '100%',
},
})
-170
View File
@@ -1,170 +0,0 @@
import {h} from 'preact'
import {css} from 'aphrodite'
import {ReloadableComponent} from './reloadable'
import {CallTreeNode, Frame} from './profile'
import {Flamechart} from './flamechart'
import {Rect, Vec2, AffineTransform, clamp} from './math'
import {formatPercent} from './utils'
import {FlamechartMinimapView} from './flamechart-minimap-view'
import {style} from './flamechart-style'
import {Sizes, commonStyle} from './style'
import {CanvasContext} from './canvas-context'
import {FlamechartRenderer} from './flamechart-renderer'
import {FlamechartDetailView} from './flamechart-detail-view'
import {FlamechartPanZoomView} from './flamechart-pan-zoom-view'
import {Hovertip} from './hovertip'
interface FlamechartViewProps {
flamechart: Flamechart
canvasContext: CanvasContext
flamechartRenderer: FlamechartRenderer
getCSSColorForFrame: (frame: Frame) => string
}
interface FlamechartViewState {
hover: {
node: CallTreeNode
event: MouseEvent
} | null
selectedNode: CallTreeNode | null
configSpaceViewportRect: Rect
}
export class FlamechartView extends ReloadableComponent<FlamechartViewProps, FlamechartViewState> {
constructor() {
super()
this.state = {
hover: null,
selectedNode: null,
configSpaceViewportRect: Rect.empty,
}
}
private configSpaceSize() {
return new Vec2(
this.props.flamechart.getTotalWeight(),
this.props.flamechart.getLayers().length,
)
}
private setConfigSpaceViewportRect = (viewportRect: Rect): void => {
const configSpaceDetailViewHeight = Sizes.DETAIL_VIEW_HEIGHT / Sizes.FRAME_HEIGHT
const configSpaceSize = this.configSpaceSize()
const width = clamp(
viewportRect.size.x,
Math.min(configSpaceSize.x, 3 * this.props.flamechart.getMinFrameWidth()),
configSpaceSize.x,
)
const size = viewportRect.size.withX(width)
const origin = Vec2.clamp(
viewportRect.origin,
new Vec2(0, -1),
Vec2.max(
Vec2.zero,
configSpaceSize.minus(size).plus(new Vec2(0, configSpaceDetailViewHeight + 1)),
),
)
this.setState({
configSpaceViewportRect: new Rect(origin, viewportRect.size.withX(width)),
})
}
private transformViewport = (transform: AffineTransform): void => {
const viewportRect = transform.transformRect(this.state.configSpaceViewportRect)
this.setConfigSpaceViewportRect(viewportRect)
}
onNodeHover = (hover: {node: CallTreeNode; event: MouseEvent} | null) => {
this.setState({hover})
}
onNodeClick = (node: CallTreeNode | null) => {
this.setState({
selectedNode: node,
})
}
formatValue(weight: number) {
const totalWeight = this.props.flamechart.getTotalWeight()
const percent = 100 * weight / totalWeight
const formattedPercent = formatPercent(percent)
return `${this.props.flamechart.formatValue(weight)} (${formattedPercent})`
}
renderTooltip() {
if (!this.container) return null
const {hover} = this.state
if (!hover) return null
const {width, height, left, top} = this.container.getBoundingClientRect()
const offset = new Vec2(hover.event.clientX - left, hover.event.clientY - top)
return (
<Hovertip containerSize={new Vec2(width, height)} offset={offset}>
<span className={css(style.hoverCount)}>
{this.formatValue(hover.node.getTotalWeight())}
</span>{' '}
{hover.node.frame.name}
</Hovertip>
)
}
container: HTMLDivElement | null = null
containerRef = (container?: Element) => {
this.container = (container as HTMLDivElement) || null
}
panZoomView: FlamechartPanZoomView | null = null
panZoomRef = (view: FlamechartPanZoomView | null) => {
this.panZoomView = view
}
subcomponents() {
return {
panZoom: this.panZoomView,
}
}
render() {
return (
<div className={css(style.fill, commonStyle.vbox)} ref={this.containerRef}>
<FlamechartMinimapView
configSpaceViewportRect={this.state.configSpaceViewportRect}
transformViewport={this.transformViewport}
flamechart={this.props.flamechart}
flamechartRenderer={this.props.flamechartRenderer}
canvasContext={this.props.canvasContext}
setConfigSpaceViewportRect={this.setConfigSpaceViewportRect}
/>
<FlamechartPanZoomView
ref={this.panZoomRef}
canvasContext={this.props.canvasContext}
flamechart={this.props.flamechart}
flamechartRenderer={this.props.flamechartRenderer}
renderInverted={false}
onNodeHover={this.onNodeHover}
onNodeSelect={this.onNodeClick}
selectedNode={this.state.selectedNode}
transformViewport={this.transformViewport}
configSpaceViewportRect={this.state.configSpaceViewportRect}
setConfigSpaceViewportRect={this.setConfigSpaceViewportRect}
/>
{this.renderTooltip()}
{this.state.selectedNode && (
<FlamechartDetailView
flamechart={this.props.flamechart}
getCSSColorForFrame={this.props.getCSSColorForFrame}
selectedNode={this.state.selectedNode}
/>
)}
</div>
)
}
}
-84
View File
@@ -1,84 +0,0 @@
import {Frame, CallTreeNode} from './profile'
import {lastOf} from './utils'
export interface FlamechartFrame {
node: CallTreeNode
start: number
end: number
parent: FlamechartFrame | null
children: FlamechartFrame[]
}
type StackLayer = FlamechartFrame[]
interface FlamechartDataSource {
getTotalWeight(): number
formatValue(v: number): string
forEachCall(
openFrame: (node: CallTreeNode, value: number) => void,
closeFrame: (node: CallTreeNode, value: number) => void,
): void
getColorBucketForFrame(f: Frame): number
}
export class Flamechart {
// Bottom to top
private layers: StackLayer[] = []
private totalWeight: number = 0
private minFrameWidth: number = 1
getTotalWeight() {
return this.totalWeight
}
getLayers() {
return this.layers
}
getColorBucketForFrame(frame: Frame) {
return this.source.getColorBucketForFrame(frame)
}
getMinFrameWidth() {
return this.minFrameWidth
}
formatValue(v: number) {
return this.source.formatValue(v)
}
constructor(private source: FlamechartDataSource) {
const stack: FlamechartFrame[] = []
const openFrame = (node: CallTreeNode, value: number) => {
const parent = lastOf(stack)
const frame: FlamechartFrame = {
node,
parent,
children: [],
start: value,
end: value,
}
if (parent) {
parent.children.push(frame)
}
stack.push(frame)
}
this.minFrameWidth = Infinity
const closeFrame = (node: CallTreeNode, value: number) => {
console.assert(stack.length > 0)
const stackTop = stack.pop()!
stackTop.end = value
if (stackTop.end - stackTop.start === 0) return
const layerIndex = stack.length
while (this.layers.length <= layerIndex) this.layers.push([])
this.layers[layerIndex].push(stackTop)
this.minFrameWidth = Math.min(this.minFrameWidth, stackTop.end - stackTop.start)
}
this.totalWeight = source.getTotalWeight()
source.forEachCall(openFrame, closeFrame)
if (!isFinite(this.minFrameWidth)) this.minFrameWidth = 1
}
}
-31
View File
@@ -1,31 +0,0 @@
export interface HashParams {
profileURL?: string
title?: string
localProfilePath?: string
}
export function getHashParams(): HashParams {
try {
const hashContents = window.location.hash
if (!hashContents.startsWith('#')) {
return {}
}
const components = hashContents.substr(1).split('&')
const result: HashParams = {}
for (const component of components) {
const [key, value] = component.split('=')
if (key === 'profileURL') {
result.profileURL = decodeURIComponent(value)
} else if (key === 'title') {
result.title = decodeURIComponent(value)
} else if (key === 'localProfilePath') {
result.localProfilePath = decodeURIComponent(value)
}
}
return result
} catch (e) {
console.error(`Error when loading hash fragment.`)
console.error(e)
return {}
}
}
-70
View File
@@ -1,70 +0,0 @@
import {ReloadableComponent} from './reloadable'
import {Vec2} from './math'
import {Sizes, Colors, FontSize, FontFamily, ZIndex} from './style'
import {css, StyleSheet} from 'aphrodite'
import {h} from 'preact'
interface HovertipProps {
containerSize: Vec2
offset: Vec2
}
export class Hovertip extends ReloadableComponent<HovertipProps, {}> {
render() {
const {containerSize, offset} = this.props
const width = containerSize.x
const height = containerSize.y
const positionStyle: {
left?: number
right?: number
top?: number
bottom?: number
} = {}
const OFFSET_FROM_MOUSE = 7
if (offset.x + OFFSET_FROM_MOUSE + Sizes.TOOLTIP_WIDTH_MAX < width) {
positionStyle.left = offset.x + OFFSET_FROM_MOUSE
} else {
positionStyle.right = width - offset.x + 1
}
if (offset.y + OFFSET_FROM_MOUSE + Sizes.TOOLTIP_HEIGHT_MAX < height) {
positionStyle.top = offset.y + OFFSET_FROM_MOUSE
} else {
positionStyle.bottom = height - offset.y + 1
}
return (
<div className={css(style.hoverTip)} style={positionStyle}>
<div className={css(style.hoverTipRow)}>{this.props.children}</div>
</div>
)
}
}
const HOVERTIP_PADDING = 2
const style = StyleSheet.create({
hoverTip: {
position: 'absolute',
background: Colors.WHITE,
border: '1px solid black',
maxWidth: Sizes.TOOLTIP_WIDTH_MAX,
paddingTop: HOVERTIP_PADDING,
paddingBottom: HOVERTIP_PADDING,
pointerEvents: 'none',
userSelect: 'none',
fontSize: FontSize.LABEL,
fontFamily: FontFamily.MONOSPACE,
zIndex: ZIndex.HOVERTIP,
},
hoverTipRow: {
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflowX: 'hidden',
paddingLeft: HOVERTIP_PADDING,
paddingRight: HOVERTIP_PADDING,
maxWidth: Sizes.TOOLTIP_WIDTH_MAX,
},
})
@@ -1,50 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`importFromBGFlameGraph 1`] = `
Object {
"frames": Array [
Frame {
"col": undefined,
"file": undefined,
"key": "a",
"line": undefined,
"name": "a",
"selfWeight": 0,
"totalWeight": 14,
},
Frame {
"col": undefined,
"file": undefined,
"key": "b",
"line": undefined,
"name": "b",
"selfWeight": 5,
"totalWeight": 14,
},
Frame {
"col": undefined,
"file": undefined,
"key": "c",
"line": undefined,
"name": "c",
"selfWeight": 5,
"totalWeight": 5,
},
Frame {
"col": undefined,
"file": undefined,
"key": "d",
"line": undefined,
"name": "d",
"selfWeight": 4,
"totalWeight": 4,
},
],
"stacks": Array [
"a;b;c 2",
"a;b;d 4",
"a;b;c 3",
"a;b 5",
],
}
`;
-257
View File
@@ -1,257 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`importFromChromeCPUProfile 1`] = `
Object {
"frames": Array [
Frame {
"col": 0,
"file": "",
"key": "(anonymous)::0:0",
"line": 0,
"name": "(anonymous)",
"selfWeight": 11575,
"totalWeight": 45920,
},
Frame {
"col": 10,
"file": "",
"key": "a::0:10",
"line": 0,
"name": "a",
"selfWeight": 0,
"totalWeight": 34345,
},
Frame {
"col": 10,
"file": "",
"key": "b::5:10",
"line": 5,
"name": "b",
"selfWeight": 0,
"totalWeight": 16788,
},
Frame {
"col": 10,
"file": "",
"key": "d::13:10",
"line": 13,
"name": "d",
"selfWeight": 34345,
"totalWeight": 34345,
},
Frame {
"col": 10,
"file": "",
"key": "c::9:10",
"line": 9,
"name": "c",
"selfWeight": 0,
"totalWeight": 17557,
},
],
"stacks": Array [
"(anonymous) 11.57ms",
"(anonymous);a;b;d 16.79ms",
"(anonymous);a;c;d 17.56ms",
],
}
`;
exports[`importFromChromeTimeline 1`] = `
Object {
"frames": Array [
Frame {
"col": -1,
"file": "",
"key": "(program)::-1:-1",
"line": -1,
"name": "(program)",
"selfWeight": 12244,
"totalWeight": 12244,
},
Frame {
"col": 10,
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
"key": "a:file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:0:10",
"line": 0,
"name": "a",
"selfWeight": 0,
"totalWeight": 33184,
},
Frame {
"col": 10,
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
"key": "c:file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:13:10",
"line": 13,
"name": "c",
"selfWeight": 16197,
"totalWeight": 16197,
},
Frame {
"col": 10,
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
"key": "b:file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:7:10",
"line": 7,
"name": "b",
"selfWeight": 16987,
"totalWeight": 16987,
},
],
"stacks": Array [
"(program) 10.16ms",
" 1.99ms",
"(program) 926.00µs",
" 85.95ms",
"(program) 133.00µs",
" 8.40ms",
"(program) 134.00µs",
"a;c 257.00µs",
"a;b 534.00µs",
"a;c 513.00µs",
"a;b 513.00µs",
"a;c 257.00µs",
"a;b 518.00µs",
"a;c 514.00µs",
"a;b 261.00µs",
"a;c 517.00µs",
"a;b 258.00µs",
"a;c 145.00µs",
"a;b 134.00µs",
"a;c 292.00µs",
"a;b 272.00µs",
"a;c 129.00µs",
"a;b 145.00µs",
"a;c 265.00µs",
"a;b 142.00µs",
"a;c 141.00µs",
"a;b 139.00µs",
"a;c 397.00µs",
"a;b 126.00µs",
"a;c 131.00µs",
"a;b 126.00µs",
"a;c 521.00µs",
"a;b 128.00µs",
"a;c 261.00µs",
"a;b 127.00µs",
"a;c 130.00µs",
"a;b 128.00µs",
"a;c 136.00µs",
"a;b 272.00µs",
"a;c 146.00µs",
"a;b 661.00µs",
"a;c 113.00µs",
"a;b 135.00µs",
"a;c 585.00µs",
"a;b 294.00µs",
"a;c 274.00µs",
"a;b 129.00µs",
"a;c 127.00µs",
"a;b 128.00µs",
"a;c 247.00µs",
"a;b 526.00µs",
"a;c 125.00µs",
"a;b 129.00µs",
"a;c 131.00µs",
"a;b 253.00µs",
"a;c 135.00µs",
"a;b 123.00µs",
"a;c 128.00µs",
"a;b 257.00µs",
"a;c 137.00µs",
"a;b 256.00µs",
"a;c 411.00µs",
"a;b 892.00µs",
"a;c 146.00µs",
"a;b 148.00µs",
"a;c 309.00µs",
"a;b 140.00µs",
"a;c 151.00µs",
"a;b 458.00µs",
"a;c 156.00µs",
"a;b 170.00µs",
"a;c 139.00µs",
"a;b 290.00µs",
"a;c 115.00µs",
"a;b 281.00µs",
"a;c 270.00µs",
"a;b 283.00µs",
"a;c 144.00µs",
"a;b 146.00µs",
"a;c 410.00µs",
"a;b 146.00µs",
"a;c 147.00µs",
"a;b 312.00µs",
"a;c 146.00µs",
"a;b 907.00µs",
"a;c 231.00µs",
"a;b 138.00µs",
"a;c 280.00µs",
"a;b 255.00µs",
"a;c 257.00µs",
"a;b 130.00µs",
"a;c 255.00µs",
"a;b 128.00µs",
"a;c 526.00µs",
"a;b 128.00µs",
"a;c 384.00µs",
"a;b 398.00µs",
"a;c 260.00µs",
"a;b 664.00µs",
"a;c 150.00µs",
"a;b 147.00µs",
"a;c 156.00µs",
"a;b 137.00µs",
"a;c 141.00µs",
"a;b 140.00µs",
"a;c 141.00µs",
"a;b 141.00µs",
"a;c 140.00µs",
"a;b 140.00µs",
"a;c 139.00µs",
"a;b 129.00µs",
"a;c 269.00µs",
"a;b 293.00µs",
"a;c 148.00µs",
"a;b 293.00µs",
"a;c 292.00µs",
"a;b 296.00µs",
"a;c 147.00µs",
"a;b 140.00µs",
"a;c 139.00µs",
"a;b 139.00µs",
"a;c 511.00µs",
"a;b 515.00µs",
"a;c 386.00µs",
"a;b 514.00µs",
"a;c 272.00µs",
"a;b 242.00µs",
"a;c 128.00µs",
"a;b 134.00µs",
"a;c 112.00µs",
"a;b 288.00µs",
"a;c 451.00µs",
"a;b 138.00µs",
"a;c 292.00µs",
"a;b 145.00µs",
"a;c 259.00µs",
"a;b 148.00µs",
"a;c 293.00µs",
"a;b 140.00µs",
"a;c 140.00µs",
" 61.61ms",
"(program) 118.00µs",
" 134.00µs",
"(program) 128.00µs",
" 16.40ms",
"(program) 125.00µs",
" 16.64ms",
"(program) 129.00µs",
" 16.72ms",
"(program) 130.00µs",
" 294.15ms",
"(program) 129.00µs",
" 7.68ms",
"(program) 131.00µs",
],
}
`;
-59
View File
@@ -1,59 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`importFromFirefox 1`] = `
Object {
"frames": Array [
Frame {
"col": undefined,
"file": "file:///Users/jlfwong/code/speedscope/sample/simple.js",
"key": "a (file:///Users/jlfwong/code/speedscope/sample/simple.js:1)",
"line": 1,
"name": "a",
"selfWeight": 0,
"totalWeight": 31.992820999992546,
},
Frame {
"col": undefined,
"file": "file:///Users/jlfwong/code/speedscope/sample/simple.js",
"key": "b (file:///Users/jlfwong/code/speedscope/sample/simple.js:8)",
"line": 8,
"name": "b",
"selfWeight": 0,
"totalWeight": 20.971447000018088,
},
Frame {
"col": undefined,
"file": "file:///Users/jlfwong/code/speedscope/sample/simple.js",
"key": "d (file:///Users/jlfwong/code/speedscope/sample/simple.js:20)",
"line": 20,
"name": "d",
"selfWeight": 31.992820999992546,
"totalWeight": 31.992820999992546,
},
Frame {
"col": undefined,
"file": "file:///Users/jlfwong/code/speedscope/sample/simple.js",
"key": "c (file:///Users/jlfwong/code/speedscope/sample/simple.js:14)",
"line": 14,
"name": "c",
"selfWeight": 0,
"totalWeight": 11.021373999974458,
},
],
"stacks": Array [
"a;b;d 989.53µs",
"a;c;d 1.02ms",
"a;b;d 982.04µs",
"a;c;d 1.02ms",
"a;b;d 7.00ms",
"a;c;d 2.00ms",
"a;b;d 981.44µs",
"a;c;d 2.00ms",
"a;b;d 2.00ms",
"a;c;d 3.02ms",
"a;b;d 4.03ms",
"a;c;d 1.96ms",
"a;b;d 4.99ms",
],
}
`;
-5
View File
@@ -1,5 +0,0 @@
import {checkProfileSnapshot} from '../test-utils'
test('importFromBGFlameGraph', async () => {
await checkProfileSnapshot('./sample/profiles/stackcollapse/simple.txt')
})
-9
View File
@@ -1,9 +0,0 @@
import {checkProfileSnapshot} from '../test-utils'
test('importFromChromeCPUProfile', async () => {
await checkProfileSnapshot('./sample/profiles/Chrome/65/simple.cpuprofile')
})
test('importFromChromeTimeline', async () => {
await checkProfileSnapshot('./sample/profiles/Chrome/65/simple-timeline.json')
})
-189
View File
@@ -1,189 +0,0 @@
import {Profile, FrameInfo, CallTreeProfileBuilder} from '../profile'
import {getOrInsert, lastOf} from '../utils'
import {TimeFormatter} from '../value-formatters'
interface TimelineEvent {
pid: number
tid: number
ts: number
ph: string
cat: string
name: string
dur: number
tdur: number
tts: number
args: {[key: string]: any}
}
interface PositionTickInfo {
line: number
ticks: number
}
interface CPUProfileCallFrame {
columnNumber: number
functionName: string
lineNumber: number
scriptId: string
url: string
}
interface CPUProfileNode {
callFrame: CPUProfileCallFrame
hitCount: number
id: number
children?: number[]
positionTicks?: PositionTickInfo[]
parent?: CPUProfileNode
}
interface CPUProfile {
startTime: number
endTime: number
nodes: CPUProfileNode[]
samples: number[]
timeDeltas: number[]
}
export function importFromChromeTimeline(events: TimelineEvent[]): Profile {
// It seems like sometimes Chrome timeline files contain multiple CpuProfiles?
// For now, choose the first one in the list.
for (let event of events) {
if (event.name == 'CpuProfile') {
const chromeProfile = event.args.data.cpuProfile as CPUProfile
return importFromChromeCPUProfile(chromeProfile)
}
}
throw new Error('Could not find CPU profile in Timeline')
}
const callFrameToFrameInfo = new Map<CPUProfileCallFrame, FrameInfo>()
function frameInfoForCallFrame(callFrame: CPUProfileCallFrame) {
return getOrInsert(callFrameToFrameInfo, callFrame, callFrame => {
const name = callFrame.functionName || '(anonymous)'
const file = callFrame.url
const line = callFrame.lineNumber
const col = callFrame.columnNumber
return {
key: `${name}:${file}:${line}:${col}`,
name,
file,
line,
col,
}
})
}
function shouldIgnoreFunction(functionName: string) {
return functionName === '(root)' || functionName === '(idle)'
}
function shouldPlaceOnTopOfPreviousStack(functionName: string) {
return functionName === '(garbage collector)' || functionName === '(program)'
}
export function importFromChromeCPUProfile(chromeProfile: CPUProfile): Profile {
const profile = new CallTreeProfileBuilder(chromeProfile.endTime - chromeProfile.startTime)
const nodeById = new Map<number, CPUProfileNode>()
for (let node of chromeProfile.nodes) {
nodeById.set(node.id, node)
}
for (let node of chromeProfile.nodes) {
if (!node.children) continue
for (let childId of node.children) {
const child = nodeById.get(childId)
if (!child) continue
child.parent = node
}
}
const samples: number[] = []
const timeDeltas: number[] = []
let elapsed = 0
let lastNodeId = NaN
// The chrome CPU profile format doesn't collapse identical samples. We'll do that
// here to save a ton of work later doing mergers.
for (let i = 0; i < chromeProfile.samples.length; i++) {
const nodeId = chromeProfile.samples[i]
if (nodeId != lastNodeId) {
samples.push(nodeId)
timeDeltas.push(elapsed)
elapsed = 0
}
let timeDelta = chromeProfile.timeDeltas[i]
if (timeDelta < 0) {
console.warn('Substituting zero for unexpected time delta:', timeDelta, 'at index', i)
timeDelta = 0
}
elapsed += timeDelta
lastNodeId = nodeId
}
if (!isNaN(lastNodeId)) {
samples.push(lastNodeId)
timeDeltas.push(elapsed)
}
let prevStack: CPUProfileNode[] = []
let value = 0
for (let i = 0; i < samples.length; i++) {
const timeDelta = timeDeltas[i + 1] || 0
const nodeId = samples[i]
let stackTop = nodeById.get(nodeId)
if (!stackTop) continue
// Find lowest common ancestor of the current stack and the previous one
let lca: CPUProfileNode | null = null
// This is O(n^2), but n should be relatively small here (stack height),
// so hopefully this isn't much of a problem
for (
lca = stackTop;
lca && prevStack.indexOf(lca) === -1;
lca = shouldPlaceOnTopOfPreviousStack(lca.callFrame.functionName)
? lastOf(prevStack)
: lca.parent || null
) {}
// Close frames that are no longer open
while (prevStack.length > 0 && lastOf(prevStack) != lca) {
const closingNode = prevStack.pop()!
const frame = frameInfoForCallFrame(closingNode.callFrame)
profile.leaveFrame(frame, value)
}
// Open frames that are now becoming open
const toOpen: CPUProfileNode[] = []
for (
let node: CPUProfileNode | null = stackTop;
node && node != lca && !shouldIgnoreFunction(node.callFrame.functionName);
// Place Chrome internal functions on top of the previous call stack
node = shouldPlaceOnTopOfPreviousStack(node.callFrame.functionName)
? lastOf(prevStack)
: node.parent || null
) {
toOpen.push(node)
}
toOpen.reverse()
for (let node of toOpen) {
profile.enterFrame(frameInfoForCallFrame(node.callFrame), value)
}
prevStack = prevStack.concat(toOpen)
value += timeDelta
}
// Close frames that are open at the end of the trace
for (let i = prevStack.length - 1; i >= 0; i--) {
profile.leaveFrame(frameInfoForCallFrame(prevStack[i].callFrame), value)
}
profile.setValueFormatter(new TimeFormatter('microseconds'))
return profile.build()
}
-5
View File
@@ -1,5 +0,0 @@
import {checkProfileSnapshot} from '../test-utils'
test('importFromFirefox', async () => {
await checkProfileSnapshot('./sample/profiles/Firefox/59/simple-firefox.json')
})
-104
View File
@@ -1,104 +0,0 @@
import {Profile} from '../profile'
import {FileSystemDirectoryEntry} from './file-system-entry'
import {importFromChromeCPUProfile, importFromChromeTimeline} from './chrome'
import {importFromStackprof} from './stackprof'
import {importFromInstrumentsDeepCopy, importFromInstrumentsTrace} from './instruments'
import {importFromBGFlameGraph} from './bg-flamegraph'
import {importFromFirefox} from './firefox'
import {importSpeedscopeProfiles} from '../file-format'
import {FileFormat} from '../file-format-spec'
import {importFromV8ProfLog} from './v8proflog'
export async function importProfile(fileName: string, contents: string): Promise<Profile | null> {
const profile = await _importProfile(fileName, contents)
if (profile && !profile.getName()) {
profile.setName(fileName)
}
return profile
}
function importSingleSpeedscopeProfile(serialized: FileFormat.File) {
const profiles = importSpeedscopeProfiles(serialized)
if (profiles.length === 0) {
throw new Error('Failed to extract any profiles from the imported speedscope profile')
}
return profiles[0]
}
async function _importProfile(fileName: string, contents: string): Promise<Profile | null> {
// First pass: Check known file format names to infer the file type
if (fileName.endsWith('.speedscope.json')) {
console.log('Importing as speedscope json file')
return importSingleSpeedscopeProfile(JSON.parse(contents))
} else if (fileName.endsWith('.cpuprofile')) {
console.log('Importing as Chrome CPU Profile')
return importFromChromeCPUProfile(JSON.parse(contents))
} else if (fileName.endsWith('.chrome.json') || /Profile-\d{8}T\d{6}/.exec(fileName)) {
console.log('Importing as Chrome Timeline')
return importFromChromeTimeline(JSON.parse(contents))
} else if (fileName.endsWith('.stackprof.json')) {
console.log('Importing as stackprof profile')
return importFromStackprof(JSON.parse(contents))
} else if (fileName.endsWith('.instruments.txt')) {
console.log('Importing as Instruments.app deep copy')
return importFromInstrumentsDeepCopy(contents)
} else if (fileName.endsWith('.collapsedstack.txt')) {
console.log('Importing as collapsed stack format')
return importFromBGFlameGraph(contents)
} else if (fileName.endsWith('.v8log.json')) {
console.log('Importing as --prof-process v8 log')
return importFromV8ProfLog(JSON.parse(contents))
}
// Second pass: Try to guess what file format it is based on structure
let parsed: any
try {
parsed = JSON.parse(contents)
} catch (e) {}
if (parsed) {
if (parsed['$schema'] === 'https://www.speedscope.app/file-format-schema.json') {
console.log('Importing as speedscope json file')
return importSingleSpeedscopeProfile(parsed)
} else if (parsed['systemHost'] && parsed['systemHost']['name'] == 'Firefox') {
console.log('Importing as Firefox profile')
return importFromFirefox(parsed)
} else if (Array.isArray(parsed) && parsed[parsed.length - 1].name === 'CpuProfile') {
console.log('Importing as Chrome CPU Profile')
return importFromChromeTimeline(parsed)
} else if ('nodes' in parsed && 'samples' in parsed && 'timeDeltas' in parsed) {
console.log('Importing as Chrome Timeline')
return importFromChromeCPUProfile(parsed)
} else if ('mode' in parsed && 'frames' in parsed) {
console.log('Importing as stackprof profile')
return importFromStackprof(parsed)
} else if ('code' in parsed && 'functions' in parsed && 'ticks' in parsed) {
console.log('Importing as --prof-process v8 log')
return importFromV8ProfLog(parsed)
}
} else {
// Format is not JSON
// If the first line contains "Symbol Name", preceded by a tab, it's probably
// a deep copy from OS X Instruments.app
if (/^[\w \t\(\)]*\tSymbol Name/.exec(contents)) {
console.log('Importing as Instruments.app deep copy')
return importFromInstrumentsDeepCopy(contents)
}
// If every line ends with a space followed by a number, it's probably
// the collapsed stack format.
const lineCount = contents.split(/\n/).length
if (lineCount >= 1 && lineCount === contents.split(/ \d+\n/).length) {
console.log('Importing as collapsed stack format')
return importFromBGFlameGraph(contents)
}
}
// Unrecognized format
return null
}
export async function importFromFileSystemDirectoryEntry(entry: FileSystemDirectoryEntry) {
return importFromInstrumentsTrace(entry)
}
-5
View File
@@ -1,5 +0,0 @@
import {checkProfileSnapshot} from '../test-utils'
test('importFromStackprof', async () => {
await checkProfileSnapshot('./sample/profiles/stackprof/simple-stackprof.json')
})
-126
View File
@@ -1,126 +0,0 @@
import regl from 'regl'
import {AffineTransform, Rect} from './math'
export interface ViewportRectangleRendererProps {
configSpaceToPhysicalViewSpace: AffineTransform
configSpaceViewportRect: Rect
}
export class ViewportRectangleRenderer {
private command: regl.Command<ViewportRectangleRendererProps>
constructor(regl: regl.Instance) {
this.command = regl<ViewportRectangleRendererProps>({
vert: `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0, 1);
}
`,
frag: `
precision mediump float;
uniform mat3 configSpaceToPhysicalViewSpace;
uniform vec2 physicalSize;
uniform vec2 physicalOrigin;
uniform vec2 configSpaceViewportOrigin;
uniform vec2 configSpaceViewportSize;
uniform float framebufferHeight;
void main() {
vec2 origin = (configSpaceToPhysicalViewSpace * vec3(configSpaceViewportOrigin, 1.0)).xy;
vec2 size = (configSpaceToPhysicalViewSpace * vec3(configSpaceViewportSize, 0.0)).xy;
vec2 halfSize = physicalSize / 2.0;
float borderWidth = 2.0;
origin = floor(origin * halfSize) / halfSize + borderWidth * vec2(1.0, 1.0);
size = floor(size * halfSize) / halfSize - 2.0 * borderWidth * vec2(1.0, 1.0);
vec2 coord = gl_FragCoord.xy;
coord.x = coord.x - physicalOrigin.x;
coord.y = framebufferHeight - coord.y - physicalOrigin.y;
vec2 clamped = clamp(coord, origin, origin + size);
vec2 gap = clamped - coord;
float maxdist = max(abs(gap.x), abs(gap.y));
// TOOD(jlfwong): Could probably optimize this to use mix somehow.
if (maxdist == 0.0) {
// Inside viewport rectangle
gl_FragColor = vec4(0, 0, 0, 0);
} else if (maxdist < borderWidth) {
// Inside viewport rectangle at border
gl_FragColor = vec4(0.7, 0.7, 0.7, 0.8);
} else {
// Outside viewport rectangle
gl_FragColor = vec4(0.7, 0.7, 0.7, 0.5);
}
}
`,
blend: {
enable: true,
func: {
srcRGB: 'src alpha',
srcAlpha: 'one',
dstRGB: 'one minus src alpha',
dstAlpha: 'one',
},
},
depth: {
enable: false,
},
attributes: {
// Cover full canvas with a rectangle
// with 2 triangles using a triangle
// strip.
//
// 0 +--+ 1
// | /|
// |/ |
// 2 +--+ 3
position: [[-1, 1], [1, 1], [-1, -1], [1, -1]],
},
uniforms: {
configSpaceToPhysicalViewSpace: (context, props) => {
return props.configSpaceToPhysicalViewSpace.flatten()
},
configSpaceViewportOrigin: (context, props) => {
return props.configSpaceViewportRect.origin.flatten()
},
configSpaceViewportSize: (context, props) => {
return props.configSpaceViewportRect.size.flatten()
},
physicalSize: (context, props) => {
return [context.viewportWidth, context.viewportHeight]
},
physicalOrigin: (context, props) => {
return [context.viewportX, context.viewportY]
},
framebufferHeight: (context, props) => {
return context.framebufferHeight
},
},
primitive: 'triangle strip',
count: 4,
})
}
render(props: ViewportRectangleRendererProps) {
this.command(props)
}
resetStats() {
return Object.assign(this.command.stats, {cpuTime: 0, gpuTime: 0, count: 0})
}
stats() {
return this.command.stats
}
}
+21681 -8029
View File
File diff suppressed because it is too large Load Diff
+53 -28
View File
@@ -1,57 +1,82 @@
{
"name": "speedscope",
"version": "0.4.0",
"version": "1.15.1",
"description": "",
"repository": "jlfwong/speedscope",
"main": "index.js",
"bin": {
"speedscope": "./cli.js"
"speedscope": "./bin/cli.js"
},
"scripts": {
"deploy": "./deploy.sh",
"prepack": "./build-release.sh",
"prettier": "prettier --write './**/*.ts' './**/*.tsx'",
"lint": "eslint './**/*.ts' './**/*.tsx'",
"jest": "./test-setup.sh && jest",
"coverage": "npm run jest -- --coverage && coveralls < coverage/lcov.info",
"test": "tsc --noEmit && npm run lint && npm run coverage",
"serve": "parcel index.html --open --no-autoinstall"
"deploy": "./scripts/deploy.sh",
"prepack": "./scripts/build-release.sh",
"prettier": "prettier --write 'src/**/*.ts' 'src/**/*.tsx'",
"lint": "eslint 'src/**/*.ts' 'src/**/*.tsx'",
"jest": "./scripts/test-setup.sh && jest --runInBand",
"coverage": "npm run jest -- --coverage",
"typecheck": "tsc --noEmit",
"test": "./scripts/ci.sh",
"serve": "parcel assets/index.html --open --no-autoinstall"
},
"files": ["cli.js", "dist/release/**", "!*.map"],
"browserslist": ["last 2 Chrome versions", "last 2 Firefox versions"],
"files": [
"bin/cli.js",
"dist/release/**",
"!*.map"
],
"browserslist": [
"last 2 Chrome versions",
"last 2 Firefox versions"
],
"author": "",
"license": "MIT",
"devDependencies": {
"@types/jest": "22.2.3",
"@types/jszip": "3.1.4",
"@types/node": "10.1.4",
"@types/node": "14.0.1",
"@types/pako": "1.0.0",
"@typescript-eslint/eslint-plugin": "4.19.0",
"@typescript-eslint/parser": "4.19.0",
"acorn": "7.2.0",
"aphrodite": "2.1.0",
"coveralls": "3.0.1",
"eslint": "4.19.1",
"eslint": "6.0.0",
"eslint-plugin-prettier": "2.6.0",
"jest": "23.0.1",
"eslint-plugin-react-hooks": "4.0.2",
"jest": "24.3.0",
"jsverify": "0.8.3",
"jszip": "3.1.5",
"pako": "1.0.6",
"parcel-bundler": "1.9.2",
"preact": "8.2.7",
"prettier": "1.12.0",
"quicktype": "15.0.45",
"regl": "1.3.1",
"ts-jest": "22.4.6",
"typescript": "2.8.1",
"typescript-eslint-parser": "14.0.0",
"uglify-es": "3.2.2"
"parcel-bundler": "1.12.4",
"preact": "10.4.1",
"prettier": "2.0.4",
"protobufjs": "6.8.8",
"source-map": "0.6.1",
"ts-jest": "24.3.0",
"typescript": "4.2.3",
"typescript-json-schema": "0.42.0",
"uglify-es": "3.2.2",
"uint8array-json-parser": "0.0.2"
},
"jest": {
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"setupFilesAfterEnv": [
"./src/jest-setup.js"
],
"testRegex": "\\.test\\.tsx?$",
"collectCoverageFrom": ["**/*.{ts,tsx}", "!**/*.d.{ts,tsx}"],
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json"]
"collectCoverageFrom": [
"**/*.{ts,tsx}",
"!**/*.d.{ts,tsx}"
],
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json"
]
},
"dependencies": {
"opn": "5.3.0"
"open": "7.2.0"
}
}
+2 -1
View File
@@ -4,4 +4,5 @@ module.exports = {
semi: false,
singleQuote: true,
trailingComma: 'all',
};
arrowParens: 'avoid'
}
-307
View File
@@ -1,307 +0,0 @@
import {h, Component} from 'preact'
import {StyleSheet, css} from 'aphrodite'
import {ReloadableComponent} from './reloadable'
import {Profile, Frame} from './profile'
import {sortBy, formatPercent} from './utils'
import {FontSize, Colors, Sizes, commonStyle} from './style'
import {ColorChit} from './color-chit'
import {ScrollableListView, ListItem} from './scrollable-list-view'
export enum SortField {
SYMBOL_NAME,
SELF,
TOTAL,
}
export enum SortDirection {
ASCENDING,
DESCENDING,
}
export interface SortMethod {
field: SortField
direction: SortDirection
}
interface HBarProps {
perc: number
}
class HBarDisplay extends Component<HBarProps, {}> {
render() {
return (
<div className={css(style.hBarDisplay)}>
<div className={css(style.hBarDisplayFilled)} style={{width: `${this.props.perc}%`}} />
</div>
)
}
}
interface SortIconProps {
activeDirection: SortDirection | null
}
class SortIcon extends Component<SortIconProps, {}> {
render() {
const {activeDirection} = this.props
const upFill = activeDirection === SortDirection.ASCENDING ? Colors.GRAY : Colors.LIGHT_GRAY
const downFill = activeDirection === SortDirection.DESCENDING ? Colors.GRAY : Colors.LIGHT_GRAY
return (
<svg
width="8"
height="10"
viewBox="0 0 8 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={css(style.sortIcon)}
>
<path d="M0 4L4 0L8 4H0Z" fill={upFill} />
<path d="M0 4L4 0L8 4H0Z" transform="translate(0 10) scale(1 -1)" fill={downFill} />
</svg>
)
}
}
interface ProfileTableViewProps {
profile: Profile
selectedFrame: Frame | null
setSelectedFrame: (frame: Frame | null) => void
getCSSColorForFrame: (frame: Frame) => string
sortMethod: SortMethod
setSortMethod: (sortMethod: SortMethod) => void
}
export class ProfileTableView extends ReloadableComponent<ProfileTableViewProps, void> {
setSelectedFrame = (frame: Frame | null) => {
this.props.setSelectedFrame(frame)
}
renderRow(frame: Frame, index: number) {
const {profile, selectedFrame} = this.props
const totalWeight = frame.getTotalWeight()
const selfWeight = frame.getSelfWeight()
const totalPerc = 100.0 * totalWeight / profile.getTotalNonIdleWeight()
const selfPerc = 100.0 * selfWeight / profile.getTotalNonIdleWeight()
const selected = frame === selectedFrame
// We intentionally use index rather than frame.key here as the tr key
// in order to re-use rows when sorting rather than creating all new elements.
return (
<tr
key={`${index}`}
onClick={this.setSelectedFrame.bind(null, frame)}
className={css(
style.tableRow,
index % 2 == 0 && style.tableRowEven,
selected && style.tableRowSelected,
)}
>
<td className={css(style.numericCell)}>
{profile.formatValue(totalWeight)} ({formatPercent(totalPerc)})
<HBarDisplay perc={totalPerc} />
</td>
<td className={css(style.numericCell)}>
{profile.formatValue(selfWeight)} ({formatPercent(selfPerc)})
<HBarDisplay perc={selfPerc} />
</td>
<td title={frame.file} className={css(style.textCell)}>
<ColorChit color={this.props.getCSSColorForFrame(frame)} />
{frame.name}
</td>
</tr>
)
}
onSortClick = (field: SortField, ev: MouseEvent) => {
ev.preventDefault()
const {sortMethod} = this.props
if (sortMethod.field == field) {
// Toggle
this.props.setSortMethod({
field,
direction:
sortMethod.direction === SortDirection.ASCENDING
? SortDirection.DESCENDING
: SortDirection.ASCENDING,
})
} else {
// Set a sane default
switch (field) {
case SortField.SYMBOL_NAME: {
this.props.setSortMethod({field, direction: SortDirection.ASCENDING})
break
}
case SortField.SELF: {
this.props.setSortMethod({field, direction: SortDirection.DESCENDING})
break
}
case SortField.TOTAL: {
this.props.setSortMethod({field, direction: SortDirection.DESCENDING})
break
}
}
}
}
render() {
const {profile, sortMethod} = this.props
const frameList: Frame[] = []
profile.forEachFrame(f => frameList.push(f))
// TODO(jlfwong): This is pretty inefficient to do this on every render, but doesn't
// seem to be a bottleneck, so we'll leave it alone.
switch (sortMethod.field) {
case SortField.SYMBOL_NAME: {
sortBy(frameList, f => f.name.toLowerCase())
break
}
case SortField.SELF: {
sortBy(frameList, f => f.getSelfWeight())
break
}
case SortField.TOTAL: {
sortBy(frameList, f => f.getTotalWeight())
break
}
}
if (sortMethod.direction === SortDirection.DESCENDING) {
frameList.reverse()
}
const renderItems = (firstIndex: number, lastIndex: number) => {
const rows: JSX.Element[] = []
for (let i = firstIndex; i <= lastIndex; i++) {
rows.push(this.renderRow(frameList[i], i))
}
return <table className={css(style.tableView)}>{rows}</table>
}
const listItems: ListItem[] = frameList.map(f => ({size: Sizes.FRAME_HEIGHT}))
return (
<div className={css(commonStyle.vbox, style.profileTableView)}>
<table className={css(style.tableView)}>
<thead className={css(style.tableHeader)}>
<tr>
<th
className={css(style.numericCell)}
onClick={ev => this.onSortClick(SortField.TOTAL, ev)}
>
<SortIcon
activeDirection={
sortMethod.field === SortField.TOTAL ? sortMethod.direction : null
}
/>
Total
</th>
<th
className={css(style.numericCell)}
onClick={ev => this.onSortClick(SortField.SELF, ev)}
>
<SortIcon
activeDirection={
sortMethod.field === SortField.SELF ? sortMethod.direction : null
}
/>
Self
</th>
<th
className={css(style.textCell)}
onClick={ev => this.onSortClick(SortField.SYMBOL_NAME, ev)}
>
<SortIcon
activeDirection={
sortMethod.field === SortField.SYMBOL_NAME ? sortMethod.direction : null
}
/>
Symbol Name
</th>
</tr>
</thead>
</table>
<ScrollableListView
items={listItems}
className={css(style.scrollView)}
renderItems={renderItems}
/>
</div>
)
}
}
const style = StyleSheet.create({
profileTableView: {
background: Colors.WHITE,
height: '100%',
},
scrollView: {
overflowY: 'auto',
overflowX: 'hidden',
},
tableView: {
width: '100%',
fontSize: FontSize.LABEL,
background: Colors.WHITE,
},
tableHeader: {
borderBottom: `2px solid ${Colors.LIGHT_GRAY}`,
textAlign: 'left',
color: Colors.GRAY,
userSelect: 'none',
},
sortIcon: {
position: 'relative',
top: 1,
marginRight: Sizes.FRAME_HEIGHT / 4,
},
tableRow: {
height: Sizes.FRAME_HEIGHT,
},
tableRowEven: {
background: Colors.OFF_WHITE,
},
tableRowSelected: {
background: Colors.DARK_BLUE,
color: Colors.WHITE,
},
numericCell: {
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
position: 'relative',
textAlign: 'right',
paddingRight: Sizes.FRAME_HEIGHT,
width: 6 * Sizes.FRAME_HEIGHT,
minWidth: 6 * Sizes.FRAME_HEIGHT,
},
textCell: {
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
width: '100%',
maxWidth: 0,
},
hBarDisplay: {
position: 'absolute',
background: Colors.TRANSPARENT_GREEN,
bottom: 2,
height: 2,
width: `calc(100% - ${2 * Sizes.FRAME_HEIGHT}px)`,
right: Sizes.FRAME_HEIGHT,
},
hBarDisplayFilled: {
height: '100%',
position: 'absolute',
background: Colors.GREEN,
right: 0,
},
})
-205
View File
@@ -1,205 +0,0 @@
import regl from 'regl'
import {Rect, Vec2, AffineTransform} from './math'
import {Color} from './color'
export class RectangleBatch {
private rectCapacity = 1000
private rectCount = 0
private configSpaceOffsets = new Float32Array(this.rectCapacity * 2)
private configSpaceSizes = new Float32Array(this.rectCapacity * 2)
private colors = new Float32Array(this.rectCapacity * 3)
constructor(private gl: regl.Instance) {}
getRectCount() {
return this.rectCount
}
private configSpaceOffsetBuffer: regl.Buffer | null = null
getConfigSpaceOffsetBuffer() {
if (!this.configSpaceOffsetBuffer)
this.configSpaceOffsetBuffer = this.gl.buffer(this.configSpaceOffsets)
return this.configSpaceOffsetBuffer
}
private configSpaceSizeBuffer: regl.Buffer | null = null
getConfigSpaceSizeBuffer() {
if (!this.configSpaceSizeBuffer)
this.configSpaceSizeBuffer = this.gl.buffer(this.configSpaceSizes)
return this.configSpaceSizeBuffer
}
private colorBuffer: regl.Buffer | null = null
getColorBuffer() {
if (!this.colorBuffer) this.colorBuffer = this.gl.buffer(this.colors)
return this.colorBuffer
}
uploadToGPU() {
this.getConfigSpaceOffsetBuffer()
this.getConfigSpaceSizeBuffer()
this.getColorBuffer()
}
addRect(rect: Rect, color: Color) {
const index = this.rectCount++
if (index >= this.rectCapacity) {
// Not enough capacity, time to resize! We'll double the capacity each time.
this.rectCapacity *= 2
const configSpaceOffsets = new Float32Array(this.rectCapacity * 2)
const configSpaceSizes = new Float32Array(this.rectCapacity * 2)
const colors = new Float32Array(this.rectCapacity * 3)
configSpaceOffsets.set(this.configSpaceOffsets)
configSpaceSizes.set(this.configSpaceSizes)
colors.set(this.colors)
this.configSpaceOffsets = configSpaceOffsets
this.configSpaceSizes = configSpaceSizes
this.colors = colors
}
this.configSpaceOffsets[index * 2] = rect.origin.x
this.configSpaceOffsets[index * 2 + 1] = rect.origin.y
this.configSpaceSizes[index * 2] = rect.size.x
this.configSpaceSizes[index * 2 + 1] = rect.size.y
this.colors[index * 3] = color.r
this.colors[index * 3 + 1] = color.g
this.colors[index * 3 + 2] = color.b
}
}
export interface RectangleBatchRendererProps {
batch: RectangleBatch
configSpaceSrcRect: Rect
physicalSpaceDstRect: Rect
parityMin?: number
parityOffset?: number
}
export class RectangleBatchRenderer {
private command: regl.Command<RectangleBatchRendererProps>
constructor(gl: regl.Instance) {
// We draw the parity / 5 into the depth channel so it can be used in a
// post-processing step to draw boundaries between rectangles. We use 5
// different values (2 per row) + one for the background, so we can
// distingish both between adjacent rectangles on a row and between rows!
this.command = gl({
vert: `
uniform mat3 configSpaceToNDC;
// Non-instanced
attribute vec2 corner;
// Instanced
attribute vec2 configSpaceOffset;
attribute vec2 configSpaceSize;
attribute vec3 color;
attribute float index;
varying vec3 vColor;
void main() {
vColor = color;
vec2 configSpacePos = configSpaceOffset + corner * configSpaceSize;
vec2 position = (configSpaceToNDC * vec3(configSpacePos, 1)).xy;
gl_Position = vec4(position, 1, 1);
}
`,
depth: {
enable: false,
},
frag: `
precision mediump float;
varying vec3 vColor;
varying float vParity;
void main() {
gl_FragColor = vec4(vColor.rgb, 1);
}
`,
attributes: {
// Non-instanced attributes
corner: gl.buffer([[0, 0], [1, 0], [0, 1], [1, 1]]),
// Instanced attributes
configSpaceOffset: (context, props) => {
return {
buffer: props.batch.getConfigSpaceOffsetBuffer(),
offset: 0,
stride: 2 * 4,
size: 2,
divisor: 1,
}
},
configSpaceSize: (context, props) => {
return {
buffer: props.batch.getConfigSpaceSizeBuffer(),
offset: 0,
stride: 2 * 4,
size: 2,
divisor: 1,
}
},
color: (context, props) => {
return {
buffer: props.batch.getColorBuffer(),
offset: 0,
stride: 3 * 4,
size: 3,
divisor: 1,
}
},
},
uniforms: {
configSpaceToNDC: (context, props) => {
const configToPhysical = AffineTransform.betweenRects(
props.configSpaceSrcRect,
props.physicalSpaceDstRect,
)
const viewportSize = new Vec2(context.viewportWidth, context.viewportHeight)
const physicalToNDC = AffineTransform.withTranslation(new Vec2(-1, 1)).times(
AffineTransform.withScale(new Vec2(2, -2).dividedByPointwise(viewportSize)),
)
return physicalToNDC.times(configToPhysical).flatten()
},
parityOffset: (context, props) => {
return props.parityOffset == null ? 0 : props.parityOffset
},
parityMin: (context, props) => {
return props.parityMin == null ? 0 : 1 + props.parityMin
},
},
instances: (context, props) => {
return props.batch.getRectCount()
},
count: 4,
primitive: 'triangle strip',
})
}
render(props: RectangleBatchRendererProps) {
this.command(props)
}
resetStats() {
return Object.assign(this.command.stats, {cpuTime: 0, gpuTime: 0, count: 0})
}
stats() {
return this.command.stats
}
}
Vendored
-589
View File
@@ -1,589 +0,0 @@
declare module 'regl' {
interface InitializationOptions {
/** A reference to a WebGL rendering context. (Default created from canvas) */
gl?: WebGLRenderingContext
/** A reference to an HTML canvas element. (Default created and appending to container) */
canvas?: HTMLCanvasElement | string
/** A container element which regl inserts a canvas into. (Default document.body) */
container?: HTMLElement | string
/** The context creation attributes passed to the WebGL context constructor. See below for defaults. */
attributes?: {
/** Boolean that indicates if the canvas contains an alpha buffer. */
alpha?: boolean
/** Boolean that indicates that the drawing buffer has a depth buffer of at least 16 bits. */
depth?: boolean
/** Boolean that indicates that the drawing buffer has a stencil buffer of at least 8 bits. */
stencil?: boolean
/** Boolean that indicates whether or not to perform anti-aliasing. */
antialias?: boolean
/** Boolean that indicates that the page compositor will assume the drawing buffer contains colors with pre-multiplied alpha. */
premultipliedAlpha?: boolean
/** If the value is true the buffers will not be cleared and will preserve their values until cleared or overwritten by the author. */
preserveDrawingBuffer?: boolean
/** Boolean that indicates if a context will be created if the system performance is low. */
failIfMajorPerformanceCavet?: boolean
}
/** A multiplier which is used to scale the canvas size relative to the container. (Default window.devicePixelRatio) */
pixelRatio?: number
/** A list of extensions that must be supported by WebGL context. Default [] */
extensions?: string[] | string
/** A list of extensions which are loaded opportunistically. Default [] */
optionalExtensions?: string[] | string
/** If set, turns on profiling for all commands by default. (Default false) */
profile?: boolean
/**
* An optional callback which accepts a pair of arguments, (err, regl) that
* is called after the application loads. If not specified, context creation
* errors throw.
*/
onDone?: (err: Error, regl: regl.Instance) => void
}
function regl(options: InitializationOptions): regl.Instance
/** Create fullscreen canvas */
function regl(): regl.Instance
/** Build from an existing canvas */
function regl(canvas: HTMLCanvasElement): regl.Instance
/** Build from an existing div container */
function regl(container: HTMLElement): regl.Instance
/** Build from an existing WebGL context */
function regl(gl: WebGLRenderingContext): regl.Instance
namespace regl {
export type vec2 = [number, number]
export type vec3 = [number, number, number]
export type vec4 = [number, number, number, number]
export type mat3 = [number, number, number, number, number, number, number, number, number]
export type mat4 = [
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number
]
type GlslPrimitive = number | vec2 | vec3 | vec4 | mat3 | mat4
interface Tick {
cancel(): void
}
interface Instance {
<P>(params: CommandOptions<P>): Command<P>
clear(args: {
color?: [number, number, number, number]
depth?: number
stencil?: number
}): void
// TODO(jlfwong): read()
buffer(args: BufferArgs): Buffer
texture(width: number, height: number): Texture
texture(args: TextureArgs): Texture
framebuffer(args: FramebufferOptions): Framebuffer
renderbuffer(args: RenderBufferOptions): RenderBuffer
limits: {
colorBits: [number, number, number, number]
depthBits: number
stencilBits: number
subpixelBits: number
extensions: string[]
maxAnistropic: number
maxDrawbuffers: number
maxColorAttachments: number
pointSizeDims: number
lineWidthDims: number
maxViewportDims: number
maxCombinedTextureUnits: number
maxCubeMapSize: number
maxTextureUnits: number
maxTextureSize: number
maxAttributes: number
maxVertexUniforms: number
maxVertexTextureUnits: number
maxFragmentUniforms: number
glsl: string
renderer: string
vendor: string
version: string
}
stats: {
bufferCount: number
elementsCount: number
framebufferCount: number
shaderCount: number
textureCount: number
cubeCount: number
renderbufferCount: number
getTotalTextureSize(): number
getTotalBufferSize(): number
getTotalRenderbufferSize(): number
getMaxUniformsCount(): number
maxTextureUnits(): number
}
destroy(): void
frame(callback: (context: Context) => void): Tick
}
type TypedArray =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
type DrawMode =
| 'points'
| 'lines'
| 'line strip'
| 'line loop'
| 'triangles'
| 'triangle strip'
| 'triangle fan'
interface Context {
tick: number
time: number
viewportWidth: number
viewportHeight: number
framebufferWidth: number
framebufferHeight: number
drawingBufferWidth: number
drawingBufferHeight: number
pixelRatio: number
[key: string]: any
}
interface BufferOptions {
data?: TypedArray | GlslPrimitive[]
/** If data is null or not present reserves space for the buffer */
length?: number
/** Sets array buffer usage hint */
usage?: 'static' | 'dynamic' | 'stream'
}
type BufferArgs = number | number[] | vec2[] | vec3[] | mat3[] | TypedArray | BufferOptions
interface Buffer {
(args: BufferArgs): void
stats: {
size: number
}
destroy(): void
}
interface ElementsOptions {
data?: TypedArray
usage?: 'static' | 'dynamic' | 'stream'
length?: number
primitive?: GlslPrimitive
count?: number
}
type ElementsArgs = vec3[] | ElementsOptions
interface Elements {
(args: ElementsArgs): void
destroy(): void
}
type MagFilter = 'nearest' | 'linear'
type MinFilter =
| 'nearest'
| 'linear'
| 'mipmap'
| 'linear mipmap linear'
| 'nearest mipmap linear'
| 'nearest mipmap nearest'
type WrapMode = 'repeat' | 'clamp' | 'mirror'
type TextureFormat =
| 'alpha'
| 'luminance'
| 'luminance alpha'
| 'rgb'
| 'rgba'
| 'rgba4'
| 'rgb5 a1'
| 'rgb565'
| 'srgb'
| 'srgba'
| 'depth'
| 'depth stencil'
| 'rgb s3tc dxt1'
| 'rgb s3tc dxt5'
| 'rgb atc'
| 'rgba atc explicit alpha'
| 'rgba atc interpolated alpha'
| 'rgb pvrtc 4bppv1'
| 'rgb pvrtc 2bppv1'
| 'rgba pvrtc 4bppv1'
| 'rgba pvrtc 2bppv1'
| 'rgb etc1'
type TextureType = 'uint8' | 'uint16' | 'float' | 'float32' | 'half float' | 'float16'
type ColorSpace = 'none' | 'browser'
type MipmapHint = "don't care" | 'dont care' | 'nice' | 'fast'
type TextureData =
| number[]
| number[][]
| TypedArray
| HTMLImageElement
| HTMLVideoElement
| HTMLCanvasElement
| CanvasRenderingContext2D
interface TextureOptions {
width?: number
height?: number
shape?: [number, number] | [number, number, number]
radius?: number
/** Sets magnification filter */
mag?: MagFilter
/** Sets minification filter */
min?: MinFilter
/** Sets wrap mode on S axis */
wrapS?: WrapMode
/** Sets wrap mode on T axis */
wrapT?: WrapMode
/** Sets number of anisotropic samples, requires EXT_texture_filter_anisotropic */
aniso?: number
format?: TextureFormat
type?: TextureType
mipmap?: MipmapHint | boolean
/** Flips textures vertically when uploading */
flipY?: boolean
/** Sets unpack alignment per pixel */
alignment?: number
/** Premultiply alpha when unpacking */
premultiplyAlpha?: boolean
colorSpace?: ColorSpace
copy?: boolean
data?: TextureData
}
type TextureArgs = TextureData | TextureOptions
interface Texture {
width: number
height: number
(args: TextureArgs): void
resize(width: number, height: number): void
destroy(): void
stats: {
size: number
}
}
// TODO(jlfwong): Cube maps
// TODO(jlfwong): Cubic frame buffers
interface RenderBufferOptions {
format?:
| 'rgba4'
| 'rgb565'
| 'rgb5 a1'
| 'depth'
| 'stencil'
| 'depth stencil'
| 'srgba'
| 'rgba16f'
| 'rgb16f'
| 'rgba32f'
width?: number
height?: number
shape?: [number, number]
radius?: number
}
interface RenderBuffer {
(options: RenderBufferOptions): void
resize(width: number, height: number): void
destroy(): void
stats: {
size: number
}
}
interface FramebufferOptions {
width?: number
height?: number
shape?: [number, number]
color?: RenderBuffer[] | Texture[]
depth?: boolean | RenderBuffer | Texture
stencil?: boolean | RenderBuffer | Texture
depthStencil?: boolean | RenderBuffer | Texture
colorFormat?:
| 'rgba'
| 'rgba4'
| 'rgb565'
| 'rgb5 a1'
| 'rgb16f'
| 'rgba16f'
| 'rgba32f'
| 'srgba'
colorType?: 'uint8' | 'half float' | 'float'
}
interface Framebuffer {
width: number
height: number
color?: RenderBuffer[]
depth?: RenderBuffer
(options: FramebufferOptions): void
use(cb: (context: Context) => void): void
resize(width: number, height: number): void
destroy(): void
}
type Uniform = number | vec2 | vec3 | mat3 | Texture
interface AttributeOptions {
buffer?: Buffer | BufferArgs
offset?: number
stride?: number
normalized?: boolean
size?: number
divisor?: number
}
type Attribute =
| AttributeOptions
| Buffer
| BufferArgs
| {constant: number | vec2 | vec3 | vec4 | mat3 | mat4}
interface Computed<P, T> {
(context: Context, props: P, batchId: number): T
}
type MaybeComputed<P, T> = Computed<P, T> | T
type DepthFunction =
| 'never'
| 'always'
| '<'
| 'less'
| '<='
| 'lequal'
| '>'
| 'greater'
| '>='
| 'gequal'
| '='
| 'equal'
| '!='
| 'notequal'
type BlendFunction =
| 0
| 'zero'
| 1
| 'one'
| 'src color'
| 'one minus src color'
| 'src alpha'
| 'one minus src alpha'
| 'dst color'
| 'one minus dst color'
| 'dst alpha'
| 'one minus dst alpha'
| 'constant color'
| 'one minus constant color'
| 'one minus constant alpha'
| 'src alpha saturate'
type BlendEquation = 'add' | 'subtract' | 'reverse subtract' | 'min' | 'max'
type StencilFunction = DepthFunction
type StencilOp =
| 'zero'
| 'keep'
| 'replace'
| 'invert'
| 'increment'
| 'decrement'
| 'increment wrap'
| 'decrement wrap'
interface CommandOptions<P> {
/** Source code of vertex shader */
vert?: string
/** Source code of fragment shader */
frag?: string
context?: {[contextName: string]: MaybeComputed<P, any>}
uniforms?: {[uniformName: string]: MaybeComputed<P, Uniform>}
attributes?: {[attributeName: string]: MaybeComputed<P, Attribute>}
primitive?: DrawMode
/** Number of vertices to draw */
count?: MaybeComputed<P, number>
/** Offset of primitives to draw */
offset?: MaybeComputed<P, number>
/** Number of instances to render */
instances?: MaybeComputed<P, number>
/** Element array buffer */
elements?: MaybeComputed<P, Elements | ElementsArgs>
framebuffer?: MaybeComputed<P, Framebuffer>
profile?: MaybeComputed<P, boolean>
depth?: MaybeComputed<
P,
{
enable?: boolean
mask?: boolean
func?: DepthFunction
range?: [number, number]
}
>
blend?: MaybeComputed<
P,
{
enable?: boolean
func?:
| {
src: BlendFunction
dst: BlendFunction
}
| {
srcRGB: BlendFunction
srcAlpha: BlendFunction
dstRGB: BlendFunction
dstAlpha: BlendFunction
}
equation?:
| BlendEquation
| {
rgb: BlendEquation
alpha: BlendEquation
}
color?: vec4
}
>
stencil?: MaybeComputed<
P,
{
enable?: boolean
mask?: number
func?: StencilFunction
opFront?: {fail: StencilOp; zfail: StencilOp; pass: StencilOp}
opBack?: {fail: StencilOp; zfail: StencilOp; pass: StencilOp}
}
>
polygonOffset?: MaybeComputed<
P,
{
enable?: boolean
offset?: {
factor: number
units: number
}
}
>
cull?: MaybeComputed<
P,
{
enable?: boolean
face?: 'front' | 'back'
}
>
frontFace?: MaybeComputed<P, 'cw' | 'ccw'>
dither?: MaybeComputed<P, boolean>
lineWidth?: MaybeComputed<P, number>
colorMask?: MaybeComputed<P, [boolean, boolean, boolean, boolean]>
sample?: MaybeComputed<
P,
{
enable?: boolean
alpha?: boolean
coverage?: {
value: number
invert: boolean
}
}
>
scissor?: MaybeComputed<
P,
{
enable?: boolean
box?: {
x: number
y: number
width: number
height: number
}
}
>
viewport?: MaybeComputed<
P,
{
x: number
y: number
width: number
height: number
}
>
}
function prop<P>(name: keyof P): (context: Context, props: P, batchId: number) => P[keyof P]
function context<P>(
name: keyof Context,
): (context: Context, props: P, batchId: number) => Context[keyof Context]
interface Command<P> {
/** One shot rendering */
(): void
(p: P): void
/** Render a batch */
(ps: P[]): void
/** Scoped commands */
(cb: (context: Context) => void): void
(p: P, cb: (context: Context) => void): void
stats: {
gpuTime: number
cpuTime: number
hitCount: number
}
}
}
export default regl
}
-40
View File
@@ -1,40 +0,0 @@
import {Component} from 'preact'
export interface SerializedComponent<S> {
state: S
serializedSubcomponents: {[key: string]: any}
}
export abstract class ReloadableComponent<P, S> extends Component<P, S> {
serialize(): SerializedComponent<S> {
const serializedSubcomponents: {[key: string]: any} = Object.create(null)
const subcomponents = this.subcomponents()
for (const key in subcomponents) {
const val = subcomponents[key]
if (val && val instanceof ReloadableComponent) {
serializedSubcomponents[key] = val.serialize()
}
}
return {
state: this.state,
serializedSubcomponents,
}
}
rehydrate(serialized: SerializedComponent<S>) {
this.setState(serialized.state, () => {
const subcomponents = this.subcomponents()
for (const key in subcomponents) {
const val = subcomponents[key]
const data = serialized.serializedSubcomponents[key]
if (data && val && val instanceof ReloadableComponent) {
val.rehydrate(data)
}
}
})
}
subcomponents(): {[key: string]: any} {
return Object.create(null)
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,46 @@
Weight Self Weight Symbol Name
96.08 Gc 100.0% - example_app (40414)
96.08 Gc 100.0% - start
96.08 Gc 100.0% - main
96.08 Gc 100.0% - std::rt::lang_start::hdba6f1ebfd1bdcf8
96.08 Gc 100.0% - std::rt::lang_start_internal::hc453db0ee48af82e
96.08 Gc 100.0% - std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c
96.08 Gc 100.0% - std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc
96.08 Gc 100.0% - core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8
96.08 Gc 100.0% - example_app::main::hddab13ae8d8b6a6e
47.82 Gc 49.7% - example_app::example_a::h622d6879b734496d
46.92 Gc 48.8% 404.75 Mc std::time::Instant::elapsed::h2e3793148fc23529
45.92 Gc 47.7% 45.92 Gc mach_absolute_time
600.78 Mc 0.6% 600.78 Mc std::time::Instant::elapsed::h2e3793148fc23529
1.00 Mc 0.0% 1.00 Mc DYLD-STUB$$mach_absolute_time
634.35 Mc 0.6% 634.35 Mc core::time::Duration::as_millis::hae6ad1b9cf7bb5ec
181.50 Mc 0.1% 181.50 Mc example_app::example_a::h622d6879b734496d
84.45 Mc 0.0% - example_app::example_b::h71b31fcd89b9ffd2
81.45 Mc 0.0% - std::time::Instant::elapsed::h2e3793148fc23529
80.45 Mc 0.0% 80.45 Mc mach_absolute_time
1.00 Mc 0.0% 1.00 Mc std::time::Instant::elapsed::h2e3793148fc23529
1.00 Mc 0.0% - example_app::example_c::h631759c10d7dee93
1.00 Mc 0.0% - alloc::vec::Vec$LT$T$C$A$GT$::push::ha3426502ffc42c8b
1.00 Mc 0.0% - alloc::raw_vec::RawVec$LT$T$C$A$GT$::reserve_for_push::he4a29b8274e35dbb
1.00 Mc 0.0% - alloc::raw_vec::RawVec$LT$T$C$A$GT$::grow_amortized::h78db9ba423623c58
1.00 Mc 0.0% - alloc::raw_vec::finish_grow::h876f5af1c66d74c8
1.00 Mc 0.0% - _$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$::allocate::hcc733a40a34fbc94
1.00 Mc 0.0% - alloc::alloc::Global::alloc_impl::hc55feba7d6266dfa
1.00 Mc 0.0% - alloc::alloc::alloc::hfac63f3d6850b759
1.00 Mc 0.0% - _malloc_zone_malloc
1.00 Mc 0.0% - nanov2_malloc
1.00 Mc 0.0% - nanov2_allocate
1.00 Mc 0.0% - nanov2_allocate
1.00 Mc 0.0% 1.00 Mc nanov2_find_block_and_allocate
1.00 Mc 0.0% 1.00 Mc example_app::example_b::h71b31fcd89b9ffd2
1.00 Mc 0.0% 1.00 Mc core::time::Duration::as_millis::hae6ad1b9cf7bb5ec
47.45 Gc 49.3% 415.12 Mc std::time::Instant::elapsed::h2e3793148fc23529
46.39 Gc 48.2% 46.39 Gc mach_absolute_time
649.70 Mc 0.6% 649.70 Mc std::time::Instant::elapsed::h2e3793148fc23529
614.22 Mc 0.6% 614.22 Mc core::time::Duration::as_millis::hae6ad1b9cf7bb5ec
190.55 Mc 0.1% 190.55 Mc example_app::main::hddab13ae8d8b6a6e
1.34 Kc 0.0% - std::io::stdio::_print::hdecfefdeb43586ed
1.34 Kc 0.0% - _$LT$$RF$std..io..stdio..Stdout$u20$as$u20$std..io..Write$GT$::write_fmt::h2cb06dcd2b172844
1.34 Kc 0.0% - core::fmt::write::hed96bcfc6342aee5
532 cycles 0.0% - _$LT$std..io..Write..write_fmt..Adapter$LT$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::hbe33ec23de24ce2f
532 cycles 0.0% 532 cycles _$LT$std..io..stdio..StdoutLock$u20$as$u20$std..io..Write$GT$::write_all::h22667d0a03b2151b
File diff suppressed because one or more lines are too long
@@ -0,0 +1,30 @@
# callgrind format
events: Instructions
fl=alpha.c
fn=alpha
1 10
cfl=beta.c
cfn=beta
calls=1 1
1 10
cfn=gamma
calls=1 1
1 10
cfn=delta
calls=1 1
1 20
fn=delta
1 10
cfn=gamma
calls=1 1
1 10
fn=gamma
1 10
cfl=
fl=beta.c
fn=beta
1 10
@@ -0,0 +1,24 @@
# callgrind format
events: Instructions
fl=file1.c
fn=main
16 20
cfn=func1
calls=1 50
16 400
cfi=file2.c
cfn=func2
calls=3 20
16 400
fn=func1
51 100
cfi=file2.c
cfn=func2
calls=2 20
51 300
fl=file2.c
fn=func2
20 700
@@ -0,0 +1,29 @@
version: 1
creator: xdebug 3.0.2 (PHP 7.4.14)
cmd: /var/www/html/index.php
part: 1
positions: line
events: Time_(10ns) Memory_(bytes)
fl=(1) file1.c
fn=(1) main
16 20 15000
cfn=(2) func1
calls=1 50
16 400 20000
cfi=(2) file2.c
cfn=(3) func2
calls=3 51
16 400 3000
fn=(2)
51 100 15000
cfi=(2)
cfn=(3)
calls=2 20
51 300 5000
fl=(2)
fn=(3)
20 700 8000
@@ -0,0 +1,24 @@
# callgrind format
events: Instructions
fl=(1) file1.c
fn=(1) main
16 20
cfn=(2) func1
calls=1 50
16 400
cfi=(2) file2.c
cfn=(3) func2
calls=3 20
16 400
fn=(2)
51 100
cfi=(2)
cfn=(3)
calls=2 20
51 300
fl=(2)
fn=(3)
20 700
@@ -0,0 +1,24 @@
# callgrind format
events: Instructions
fl=file1.c
fn=main
16 20
cfn=func1
calls=1 50
* 400
cfi=file2.c
cfn=func2
calls=3 20
* *
fn=func1
+35 -300
cfi=file2.c
cfn=func2
calls=2 20
* 300
fl=file2.c
fn=func2
-31 +400
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,6 @@
simple-terminat 10 198792.736893: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
@@ -0,0 +1,881 @@
# ========
# captured on: Wed Aug 15 16:01:24 2018
# hostname : e2b5bab9a538
# os release : 4.9.93-linuxkit-aufs
# perf version : 4.15.18
# arch : x86_64
# nrcpus online : 4
# nrcpus avail : 4
# cpudesc : Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
# cpuid : GenuineIntel,6,70,1
# total memory : 2046644 kB
# cmdline : /usr/lib/linux-tools-4.15.0-30/perf record -F 999 -g ./simple-terminates
# event : name = cpu-clock, , type = 1, size = 112, { sample_period, sample_freq } = 999, sample_type = IP|TID|TIME|CALLCHAIN|PERIOD, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1
# CPU_TOPOLOGY info available, use -I to display
# pmu mappings: breakpoint = 5, power = 7, software = 1, tracepoint = 2, msr = 6
# CACHE info available, use -I to display
# missing features: TRACING_DATA NUMA_TOPOLOGY BRANCH_STACK GROUP_DESC AUXTRACE STAT
# ========
#
simple-terminat 9 198789.478194: 1001001 cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.479183: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.480175: 1001001 cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.481194: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.482189: 1001001 cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.482989: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.484239: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.485180: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.486198: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.487190: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.488202: 1001001 cpu-clock:
6aa _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.489329: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.490298: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.491297: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.492295: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.493164: 1001001 cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.494212: 1001001 cpu-clock:
685 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.495431: 1001001 cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.496316: 1001001 cpu-clock:
655 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.497329: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.498322: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.499325: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.500327: 1001001 cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.501320: 1001001 cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.502265: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.503165: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.504336: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.505331: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.506328: 1001001 cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.507324: 1001001 cpu-clock:
670 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.508328: 1001001 cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.509334: 1001001 cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.510272: 1001001 cpu-clock:
67c _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.511373: 1001001 cpu-clock:
64c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.512319: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.513188: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.514391: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.515336: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.516359: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.517344: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.518263: 1001001 cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.519381: 1001001 cpu-clock:
6b3 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.520359: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.521293: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.522326: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.523217: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.524395: 1001001 cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.525355: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.526189: 1001001 cpu-clock:
6b3 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.527412: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.528331: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.529367: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.530368: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.531369: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.532360: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.533218: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.534427: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.535372: 1001001 cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.536386: 1001001 cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.537337: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.538397: 1001001 cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.539383: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.540390: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.541389: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.542400: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.543268: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.544277: 1001001 cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.545289: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.546425: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.547283: 1001001 cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.548516: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.549479: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.550495: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.551493: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.552486: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.553398: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.554516: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.555493: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.556494: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.557354: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.558422: 1001001 cpu-clock:
679 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.559521: 1001001 cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.560351: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.561388: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.562544: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.563411: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.564311: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.565551: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.566493: 1001001 cpu-clock:
679 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.567486: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.568508: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.569498: 1001001 cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.570501: 1001001 cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.571502: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.572502: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.573415: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.574532: 1001001 cpu-clock:
679 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.575498: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.576507: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.577513: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.578510: 1001001 cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.579516: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.580509: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.581511: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.582519: 1001001 cpu-clock:
655 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.583440: 1001001 cpu-clock:
6b3 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.584538: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.585513: 1001001 cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.586522: 1001001 cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.587526: 1001001 cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.588513: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.589523: 1001001 cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.590520: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.591524: 1001001 cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.592527: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.593438: 1001001 cpu-clock:
679 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.594550: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.595513: 1001001 cpu-clock:
6bc _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.596531: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.597523: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.598527: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.599528: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.600528: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.601529: 1001001 cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.602525: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.603449: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.604547: 1001001 cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.605522: 1001001 cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.606529: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.607410: 1001001 cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.608466: 1001001 cpu-clock:
618 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.609472: 1001001 cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.610646: 1001001 cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.611607: 1001001 cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.612623: 1001001 cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9 198789.613576: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
@@ -0,0 +1,877 @@
simple-terminat 9/9 198791.127353: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.128290: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.129324: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.130316: cpu-clock:
6b3 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.131320: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.132319: cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.133315: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.134322: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.135321: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.136320: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.137351: cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.138306: cpu-clock:
6b3 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.139325: cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.140311: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.141325: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.142313: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.143342: cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.144354: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.145382: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.146345: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.147357: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.148361: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.149342: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.150356: cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.151341: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.152346: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.153346: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.154346: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.155347: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.156347: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.157355: cpu-clock:
679 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.158347: cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.159352: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.160373: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.161353: cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.162359: cpu-clock:
6b3 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.163363: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.164353: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.165365: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.166367: cpu-clock:
6b3 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.167368: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.168370: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.169356: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.170362: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.171331: cpu-clock:
680 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.172382: cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.173360: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.174372: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.175463: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.176511: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.177286: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.178500: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.179495: cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.180496: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.181506: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.182430: cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.183529: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.184491: cpu-clock:
6bc _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.185341: cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.186539: cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.187500: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.188512: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.189509: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.190317: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.191545: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.192298: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.193537: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.194522: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.195336: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.196578: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.197454: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.198536: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.199525: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.200521: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.201544: cpu-clock:
655 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.202435: cpu-clock:
6aa _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.203550: cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.204529: cpu-clock:
677 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.205532: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.206533: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.207533: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.208532: cpu-clock:
679 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.209542: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.210538: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.211536: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.212400: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.213571: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.214532: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.215548: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.216391: cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.217575: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.218511: cpu-clock:
6bf _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.219538: cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.220531: cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.221401: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.222426: cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.223566: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.224531: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.225462: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.226563: cpu-clock:
64e _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.227376: cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.228586: cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.229367: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.230467: cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.231584: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.232398: cpu-clock:
6aa _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.233591: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.234477: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.235641: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.236770: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.237747: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.238743: cpu-clock:
682 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.239739: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.240744: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.241743: cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.242591: cpu-clock:
63c _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.243804: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.244620: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.245775: cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.246736: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.247757: cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.248761: cpu-clock:
645 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.249760: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.250751: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.251765: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.252616: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.253805: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.254754: cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
6ee main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.255617: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.256794: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.257759: cpu-clock:
61e _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.258769: cpu-clock:
670 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.259766: cpu-clock:
613 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.260771: cpu-clock:
6b1 _Z5gammav (/workdir/simple-terminates)
6f8 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.261751: cpu-clock:
60c _Z5alphav (/workdir/simple-terminates)
690 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.262617: cpu-clock:
615 _Z5alphav (/workdir/simple-terminates)
6e9 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
simple-terminat 9/9 198791.263815: cpu-clock:
ffffffffad1ee8b5 [unknown] ([kernel.kallsyms])
ffffffffad1ee98a [unknown] ([kernel.kallsyms])
ffffffffad1f1ca9 [unknown] ([kernel.kallsyms])
ffffffffad1aab1d [unknown] ([kernel.kallsyms])
ffffffffad1c4c94 [unknown] ([kernel.kallsyms])
ffffffffad1c5ab1 [unknown] ([kernel.kallsyms])
ffffffffad1ccc4a [unknown] ([kernel.kallsyms])
ffffffffad0dc851 [unknown] ([kernel.kallsyms])
ffffffffad0e27a4 [unknown] ([kernel.kallsyms])
ffffffffad0e2d50 [unknown] ([kernel.kallsyms])
ffffffffad0e2dc1 [unknown] ([kernel.kallsyms])
ffffffffad0033c0 [unknown] ([kernel.kallsyms])
ffffffffad7fa08e [unknown] ([kernel.kallsyms])
@@ -0,0 +1,6 @@
simple-terminat 10 198792.736893: 1001001 cpu-clock:
643 _Z4betav (/workdir/simple-terminates)
695 _Z5deltav (/workdir/simple-terminates)
6f3 main (/workdir/simple-terminates)
21b97 __libc_start_main (/lib/x86_64-linux-gnu/libc-2.27.so)
6ce258d4c544155 [unknown] ([unknown])
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"head":{"functionName":"(root)","url":"","lineNumber":-1,"bailoutReason":"","id":1,"scriptId":0,"hitCount":0,"children":[{"functionName":"","url":"","lineNumber":0,"callUID":1,"bailoutReason":"","id":2,"scriptId":0,"hitCount":0,"children":[{"functionName":"a","url":"","lineNumber":0,"callUID":2,"bailoutReason":"","id":3,"scriptId":0,"hitCount":0,"children":[{"functionName":"b","url":"","lineNumber":5,"callUID":3,"bailoutReason":"","id":4,"scriptId":0,"hitCount":0,"children":[{"functionName":"d","url":"","lineNumber":13,"callUID":4,"bailoutReason":"","id":5,"scriptId":0,"hitCount":14,"children":[]}]},{"functionName":"c","url":"","lineNumber":9,"callUID":3,"bailoutReason":"","id":6,"scriptId":0,"hitCount":0,"children":[{"functionName":"d","url":"","lineNumber":13,"callUID":6,"bailoutReason":"","id":7,"scriptId":0,"hitCount":14,"children":[]}]}]}]}]},"startTime":163140,"endTime":163140,"samples":[2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7],"timestamps":[163140599286,163140610861,163140611921,163140612966,163140614236,163140615507,163140616694,163140617968,163140619238,163140620258,163140621507,163140622765,163140624037,163140625303,163140626378,163140627649,163140628923,163140630191,163140631457,163140632746,163140634032,163140635304,163140636440,163140637716,163140638990,163140640255,163140641520,163140642791,163140644063,163140645206]}
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
This directory contains profiles & source-maps to test if source-map
remapping of profiles is working correctly. See the corresponding
"sourcemaps" directory in programs/javascript to see how these were
generated.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["gamma.ts", "beta.ts", "delta.ts", "alpha.ts", "kludge.ts", "typescript-source-map-test.ts"],
"sourcesContent": ["export const gamma = () => {\n let prod = 1\n for (let i = 1; i < 1000; i++) {\n prod *= i\n }\n return prod\n}\n", "import {gamma} from './gamma'\n\nexport function beta() {\n for (let i = 0; i < 10; i++) {\n gamma()\n }\n}\n", "import {gamma} from './gamma'\n\nexport const delta = function () {\n for (let i = 0; i < 10; i++) {\n gamma()\n }\n}\n", "import {beta} from './beta'\nimport {delta} from './delta'\n\nexport function alpha() {\n ;(function () {\n for (let i = 0; i < 1000; i++) {\n beta()\n delta()\n }\n })()\n}\n", "import {alpha} from './alpha'\n\nexport class Kludge {\n constructor() {\n alpha()\n console.log(this.floop)\n }\n\n zap() {\n alpha()\n }\n\n get floop(): number {\n alpha()\n return 1\n }\n}\n", "import {Kludge} from './kludge'\n\nconst k = new Kludge()\nk.zap()\n"],
"mappings": "MAAO,KAAM,GAAQ,KACnB,GAAI,GAAO,EACX,OAAS,GAAI,EAAG,EAAI,IAAM,IACxB,GAAQ,EAEV,MAAO,ICHF,aACL,OAAS,GAAI,EAAG,EAAI,GAAI,IACtB,ICFG,KAAM,GAAQ,WACnB,OAAS,GAAI,EAAG,EAAI,GAAI,IACtB,KCDG,aACJ,AAAC,YACA,OAAS,GAAI,EAAG,EAAI,IAAM,IACxB,IACA,QCPN,QAGE,cACE,IACA,QAAQ,IAAI,KAAK,OAGnB,MACE,OAGE,SACF,WACO,GCZX,KAAM,GAAI,GAAI,GACd,EAAE",
"names": []
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"sources":["gamma.ts","beta.ts","delta.ts","alpha.ts","kludge.ts","typescript-source-map-test.ts"],"names":[],"mappings":";AAAO,aAAA,OAAA,eAAA,QAAA,aAAA,CAAA,OAAA,IAAA,QAAA,WAAA,EAAA,IAAM,EAAQ,WAEd,IADD,IAAA,EAAO,EACF,EAAI,EAAG,EAAI,IAAM,IACxB,GAAQ,EAEH,OAAA,GALF,QAAA,MAAA;;ACMN,aAAA,OAAA,eAAA,QAAA,aAAA,CAAA,OAAA,IAAA,QAAA,KAAA,EAND,IAAA,EAAA,QAAA,WAEM,SAAU,IACT,IAAA,IAAI,EAAI,EAAG,EAAI,GAAI,KACtB,EAAA,EAAA;;ACFG,aAAA,OAAA,eAAA,QAAA,aAAA,CAAA,OAAA,IAAA,QAAA,WAAA,EAFP,IAAA,EAAA,QAAA,WAEa,EAAQ,WACd,IAAA,IAAI,EAAI,EAAG,EAAI,GAAI,KACtB,EAAA,EAAA,UAFG,QAAA,MAAA;;ACQN,aAAA,OAAA,eAAA,QAAA,aAAA,CAAA,OAAA,IAAA,QAAA,MAAA,EAVD,IAAA,EAAA,QAAA,UACA,EAAA,QAAA,WAEM,SAAU,KACZ,WACK,IAAA,IAAI,EAAI,EAAG,EAAI,IAAM,KACxB,EAAA,EAAA,SACA,EAAA,EAAA,SAHF;;ACFJ,aAAA,OAAA,eAAA,QAAA,aAAA,CAAA,OAAA,IAAA,QAAA,YAAA,EAFA,IAAA,EAAA,QAAA,WAEA,EAAA,WACE,SAAA,KACE,EAAA,EAAA,SACA,QAAQ,IAAI,KAAK,OAWrB,OARE,EAAA,UAAA,IAAA,YACE,EAAA,EAAA,UAGF,OAAA,eAAI,EAAA,UAAA,QAAK,CAAT,IAAA,WAES,OADP,EAAA,EAAA,SACO,GAFA,YAAA,EAVX,cAAA,IAcA,EAdA,GAAA,QAAA,OAAA;;ACCA,aAHA,IAAA,EAAA,QAAA,YAEM,EAAI,IAAI,EAAJ,OACV,EAAE","file":"typescript-source-map-test.js","sourceRoot":"..","sourcesContent":["export const gamma = () => {\n let prod = 1\n for (let i = 1; i < 1000; i++) {\n prod *= i\n }\n return prod\n}\n","import {gamma} from './gamma'\n\nexport function beta() {\n for (let i = 0; i < 10; i++) {\n gamma()\n }\n}\n","import {gamma} from './gamma'\n\nexport const delta = function () {\n for (let i = 0; i < 10; i++) {\n gamma()\n }\n}\n","import {beta} from './beta'\nimport {delta} from './delta'\n\nexport function alpha() {\n ;(function () {\n for (let i = 0; i < 1000; i++) {\n beta()\n delta()\n }\n })()\n}\n","import {alpha} from './alpha'\n\nexport class Kludge {\n constructor() {\n alpha()\n console.log(this.floop)\n }\n\n zap() {\n alpha()\n }\n\n get floop(): number {\n alpha()\n return 1\n }\n}\n","import {Kludge} from './kludge'\n\nconst k = new Kludge()\nk.zap()\n"]}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"sources":["webpack://speedscope-sourcemap-test-project/./gamma.ts","webpack://speedscope-sourcemap-test-project/./beta.ts","webpack://speedscope-sourcemap-test-project/./delta.ts","webpack://speedscope-sourcemap-test-project/./alpha.ts","webpack://speedscope-sourcemap-test-project/./typescript-source-map-test.ts","webpack://speedscope-sourcemap-test-project/./kludge.ts"],"names":["gamma","prod","i","beta","delta","alpha","console","log","this","floop","zap"],"mappings":"mBAAO,IAAMA,EAAQ,WAEnB,IADA,IAAIC,EAAO,EACFC,EAAI,EAAGA,EAAI,IAAMA,IACxBD,GAAQC,EAEV,OAAOD,GCHF,SAASE,IACd,IAAK,IAAID,EAAI,EAAGA,EAAI,GAAIA,IACtBF,ICFG,IAAMI,EAAQ,WACnB,IAAK,IAAIF,EAAI,EAAGA,EAAI,GAAIA,IACtBF,KCDG,SAASK,KACb,WACC,IAAK,IAAIH,EAAI,EAAGA,EAAI,IAAMA,IACxBC,IACAC,IAHH,ICFO,ICAV,WACE,aACEC,IACAC,QAAQC,IAAIC,KAAKC,OAWrB,OARE,YAAAC,IAAA,WACEL,KAGF,sBAAI,oBAAK,C,IAAT,WAEE,OADAA,IACO,G,gCAEX,EAdA,KDCEK,O","file":"typescript-source-map-test.js","sourcesContent":["export const gamma = () => {\n let prod = 1\n for (let i = 1; i < 1000; i++) {\n prod *= i\n }\n return prod\n}\n","import {gamma} from './gamma'\n\nexport function beta() {\n for (let i = 0; i < 10; i++) {\n gamma()\n }\n}\n","import {gamma} from './gamma'\n\nexport const delta = function () {\n for (let i = 0; i < 10; i++) {\n gamma()\n }\n}\n","import {beta} from './beta'\nimport {delta} from './delta'\n\nexport function alpha() {\n ;(function () {\n for (let i = 0; i < 1000; i++) {\n beta()\n delta()\n }\n })()\n}\n","import {Kludge} from './kludge'\n\nconst k = new Kludge()\nk.zap()\n","import {alpha} from './alpha'\n\nexport class Kludge {\n constructor() {\n alpha()\n console.log(this.floop)\n }\n\n zap() {\n alpha()\n }\n\n get floop(): number {\n alpha()\n return 1\n }\n}\n"],"sourceRoot":""}
@@ -1 +1,81 @@
{"version":"0.0.1","$schema":"https://www.speedscope.app/file-format-schema.json","shared":{"frames":[{"name":"a"},{"name":"b"},{"name":"c"},{"name":"d"}]},"profiles":[{"type":"evented","name":"simple.txt","unit":"none","startValue":0,"endValue":14,"events":[{"type":"O","frame":0,"at":0},{"type":"O","frame":1,"at":0},{"type":"O","frame":2,"at":0},{"type":"C","frame":2,"at":2},{"type":"O","frame":3,"at":2},{"type":"C","frame":3,"at":6},{"type":"O","frame":2,"at":6},{"type":"C","frame":2,"at":9},{"type":"C","frame":1,"at":14},{"type":"C","frame":0,"at":14}]}]}
{
"$schema": "https://www.speedscope.app/file-format-schema.json",
"profiles": [
{
"endValue": 14,
"events": [
{
"at": 0,
"frame": 0,
"type": "O"
},
{
"at": 0,
"frame": 1,
"type": "O"
},
{
"at": 0,
"frame": 2,
"type": "O"
},
{
"at": 2,
"frame": 2,
"type": "C"
},
{
"at": 2,
"frame": 3,
"type": "O"
},
{
"at": 6,
"frame": 3,
"type": "C"
},
{
"at": 6,
"frame": 2,
"type": "O"
},
{
"at": 9,
"frame": 2,
"type": "C"
},
{
"at": 14,
"frame": 1,
"type": "C"
},
{
"at": 14,
"frame": 0,
"type": "C"
}
],
"name": "simple.txt",
"startValue": 0,
"type": "evented",
"unit": "none"
}
],
"shared": {
"frames": [
{
"name": "a"
},
{
"name": "b"
},
{
"name": "c"
},
{
"name": "d"
}
]
},
"version": "0.0.1"
}
@@ -0,0 +1,29 @@
{
"exporter": "speedscope@0.6.0",
"$schema": "https://www.speedscope.app/file-format-schema.json",
"name": "Two Samples",
"activeProfileIndex": 1,
"profiles": [
{
"type": "sampled",
"name": "one",
"unit": "seconds",
"startValue": 0,
"endValue": 14,
"samples": [[0, 1, 2], [0, 1, 2], [0, 1, 3], [0, 1, 2], [0, 1]],
"weights": [1, 1, 4, 3, 5]
},
{
"type": "sampled",
"name": "two",
"unit": "seconds",
"startValue": 0,
"endValue": 14,
"samples": [[0, 1, 2], [0, 1, 2], [0, 1, 3], [0, 1, 2], [0, 1]],
"weights": [1, 1, 4, 3, 5]
}
],
"shared": {
"frames": [{"name": "a"}, {"name": "b"}, {"name": "c"}, {"name": "d"}]
}
}
@@ -0,0 +1,16 @@
{
"$schema": "https://www.speedscope.app/file-format-schema.json",
"shared": {
"frames": [{"name": "A"}]
},
"profiles": [
{
"type": "evented",
"name": "p1",
"unit": "none",
"startValue": 0,
"endValue": 100,
"events": [{"type": "O", "frame": 0, "at": 0}]
}
]
}
@@ -0,0 +1,25 @@
{
"$schema": "https://www.speedscope.app/file-format-schema.json",
"shared": {
"frames": [{"name": "A"}, {"name": "B"}]
},
"profiles": [
{
"type": "evented",
"name": "p1",
"unit": "none",
"startValue": 0,
"endValue": 100,
"events": [
{"type": "O", "frame": 0, "at": 0},
{"type": "C", "frame": 0, "at": 1},
{"type": "O", "frame": 1, "at": 2},
{"type": "O", "frame": 0, "at": 2},
{"type": "O", "frame": 0, "at": 3},
{"type": "C", "frame": 0, "at": 4},
{"type": "C", "frame": 1, "at": 4},
{"type": "C", "frame": 0, "at": 5}
]
}
]
}
@@ -0,0 +1,5 @@
a;b;c 1
a;b;c 1
a;b;d 4
a;b;c 3
a;b 5
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,8 @@
# comment that gives extra info about the samples
// some other comment
a;b;c 1
a;b;c 1
a;b;d 4
a;b;c 3
a;b 5
invalid line
File diff suppressed because one or more lines are too long
@@ -0,0 +1,25 @@
[
{ "pid": 0, "tid": 0, "ph": "B", "ts": 0, "name": "A" },
{ "pid": 0, "tid": 0, "ph": "E", "ts": 2, "name": "A" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 0, "dur": 2, "name": "B" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 10, "dur": 2, "name": "C" },
{ "pid": 0, "tid": 0, "ph": "B", "ts": 10, "name": "D" },
{ "pid": 0, "tid": 0, "ph": "E", "ts": 12, "name": "D" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 20, "dur": 1, "name": "E" },
{ "pid": 0, "tid": 0, "ph": "B", "ts": 20, "name": "F" },
{ "pid": 0, "tid": 0, "ph": "E", "ts": 22, "name": "F" },
{ "pid": 0, "tid": 0, "ph": "B", "ts": 30, "name": "G" },
{ "pid": 0, "tid": 0, "ph": "E", "ts": 32, "name": "G" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 30, "dur": 1, "name": "H" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 41, "dur": 1, "name": "I" },
{ "pid": 0, "tid": 0, "ph": "B", "ts": 40, "name": "J" },
{ "pid": 0, "tid": 0, "ph": "E", "ts": 42, "name": "J" },
{ "pid": 0, "tid": 0, "ph": "B", "ts": 50, "name": "K" },
{ "pid": 0, "tid": 0, "ph": "E", "ts": 52, "name": "K" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 51, "dur": 1, "name": "L" }
]
@@ -0,0 +1,5 @@
[
{"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
{"pid": 0, "tid": 0, "ph": "E", "name": "alpha", "ts": 1},
{"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 2}
]
@@ -0,0 +1,6 @@
[
{"pid": 0, "tid": 0, "ph": "B", "name": "A", "args": {"x": 1}, "ts": 0},
{"pid": 0, "tid": 0, "ph": "B", "name": "B", "args": {"x": 2}, "ts": 1},
{"pid": 0, "tid": 0, "ph": "E", "name": "A", "args": {"x": 2}, "ts": 10},
{"pid": 0, "tid": 0, "ph": "X", "name": "Z", "args": {"x": 1}, "ts": 10, "dur": 1}
]
@@ -0,0 +1,7 @@
[
{"tid": 1, "ph": "X", "pid": 0, "name": "alpha", "args": {"x": 0}, "ts": 0, "dur": 10},
{"tid": 1, "ph": "B", "pid": 0, "name": "beta", "args": {"x": 0}, "ts": 1},
{"tid": 1, "ph": "B", "pid": 0, "name": "gamma", "args": {"x": 0}, "ts": 1},
{"tid": 1, "ph": "E", "pid": 0, "name": "beta", "args": {"x": 1}, "ts": 2},
{"tid": 1, "ph": "E", "pid": 0, "name": "gamma", "args": {"x": 1}, "ts": 2}
]
@@ -0,0 +1,4 @@
[
{ "pid": 0, "tid": 0, "ph": "X", "ts": 0, "dur": 10, "name": "alpha" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 5, "dur": 10, "name": "beta" }
]
@@ -0,0 +1,7 @@
[
{ "pid": 0, "tid": 0, "ph": "X", "ts": 0, "dur": 10, "name": "alpha" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 1, "dur": 1, "name": "beta" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 1, "dur": 1, "name": "gamma" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 5, "dur": 1, "name": "gamma" },
{ "pid": 0, "tid": 0, "ph": "X", "ts": 5, "dur": 1, "name": "beta" }
]
@@ -0,0 +1,4 @@
[
{"pid": 0, "tid": 0, "ph": "B", "name": "A", "args": {"x": 1}, "ts": 0},
{"pid": 0, "tid": 0, "ph": "E", "name": "A", "args": {"x": 2}, "ts": 10}
]
@@ -0,0 +1,4 @@
[
{"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
{"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 10}
]

Some files were not shown because too many files have changed in this diff Show More