A tool for analyzing the output of `tsc --generateTrace`

Overview

@typescript/analyze-trace

Tool for analyzing the output of tsc --generateTrace automatically, rather than following the steps here.

Note: The goal is to identify clear-cut hot-spots and provide enough context to extract a small repro. The repro can then be used as the basis of a bug report or a starting point for manual code inspection or profiling.

Usage

First, build your project with tsc --generateTrace traceDir. This will create a new traceDir directory with paired trace and types files.

Next, install @typescript/analyze-trace to make its various commands available in your project.

For a sorted list of compilation hot-spots, run npx analyze-trace traceDir. Pass --help to learn more about configuration options. For best results, run the analyzer on a machine where the paths in the trace file(s) resolve correctly.

For a simplified view of a types file (useful when investigating an individual trace), run npx simplify-trace-types traceDir\types.json output_path. Note that the resulting file is for human consumption and should not be passed to the analyzer (i.e. don't clobber the original).

To pretty-print individual types from a types file (faster than processing the entire file), run npx print-trace-types traceDir\types.json id+.

Deployment

To publish a new version of this package, change the version in package.json and push to main.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

Comments
  • Use exit package rather than process.exit

    Use exit package rather than process.exit

    It sounds like process.exit might truncate in-flight I/O, so use process.exitCode in non-error scenarios.

    (I'm tentatively assuming that a tiny message sent to stdout/stderr immediately before exit will make it to the console.)

    Fixes #33

    opened by amcasey 13
  • output can break if data is too big

    output can break if data is too big

    Something here is breaking, because it's cutting off our output.

        return new Promise<ProjectResult>(resolve => {
            const child = cp.fork(path.join(__dirname, "analyze-trace-file"), args, { stdio: "pipe" });
    
            let stdout = "";
            let stderr = "";
    
            child.stdout!.on("data", chunk => stdout += chunk);
            child.stderr!.on("data", chunk => stderr += chunk);
    
            child.on("exit", (code, signal) => {
                resolve({
                    project,
                    stdout: stdout.trim(),
                    stderr: stderr.trim(),
                    exitCode: code ?? undefined,
                    signal: signal ?? undefined,
                });
            });
        });
    

    If we run analyze-trace-file on the command line with the same arguments it works fine.

    I tried setting maxBuffer but that's not an option for fork, and even if I changed it to exec it still fails with the same problem.

    This is what it looks like when the output gets cut off. Maybe exit is being fired before all of on('data') had a chance to fire?

    Screen Shot 2022-09-21 at 5 55 47 PM
    opened by dylang 7
  • Add `jsonparse` as a dependency

    Add `jsonparse` as a dependency

    jsonparse is used in analyze-trace-file.ts but is not declared as a dependency.

    Yarn >=2 with PnP throws an error when running yarn dlx @typescript/analyse-trace trace-dir because it is stricter with dependencies.

    Error: @typescript/analyze-trace tried to access jsonparse, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.
    
    Required package: jsonparse
    
    opened by julienfouilhe 5
  • Customizable thresholds constants

    Customizable thresholds constants

    There are a bunch of constants that govern ultimately how many results are shown:

    https://github.com/microsoft/typescript-analyze-trace/blob/fbca82e26714dc44ac76d667a1b67072c1c30de4/src/analyze-trace-file.ts#L31-L33

    IMHO perhaps those constants should be customizable from the CLI, or even better there should just be a "limit" flag to limit the number of files outputted, which by default could be 10 or even the current essentially "auto" limit.

    Was https://github.com/amcasey/ts-analyze-trace/issues/7 from @fabiospampinato

    opened by amcasey 5
  • Add support for JSON output

    Add support for JSON output

    Fixes #21

    TODO: If I were doing this from scratch, I would probably implement JSON as the default output and then have a wrapper that pretty-prints the output as text. As things stand, there are two distinct implementations that share a lot of helper functions. The biggest difference between the two is that JSON nodes use explicit children properties (i.e. follow a schema), whereas text output nodes follow treeify's structure (i.e. children are dynamically generated properties on parent node).

    NB: While JSON is obviously intended for programmatic consumption, please don't take a dependency on the output format yet. Until a non-trivial consumer flushes out the bugs, it can't really be considered stable.

    opened by amcasey 4
  • Support JSON output

    Support JSON output

    Hi!

    First, thanks for this tool ! I've tried to use it on a very big project to find hot spots. Here is an example of output:

    Hot Spots
    ├─ Check file d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\abtestingtabs\abtestdashboard.ts (2316ms)
    │  └─ Check variable declaration from (line 164, char 11) to (line 164, char 51) (1909ms)
    │     └─ Check expression from (line 164, char 21) to (line 164, char 51) (1909ms)
    │        └─ Determine variance of type 13937 (1908ms)
    │           ├─ Compare types 20107 and 20106 (1074ms)
    │           │  └─ Compare types 20191 and 20190 (1064ms)
    │           │     └─ Compare types 20197 and 20198 (1064ms)
    │           │        └─ Determine variance of type 20192 (1064ms)
    │           │           └─ Compare types 20200 and 20199 (1048ms)
    │           │              └─ Compare types 20203 and 20202 (1048ms)
    │           │                 └─ Compare types 20214 and 20213 (1047ms)
    │           │                    └─ Determine variance of type 20208 (1046ms)
    │           │                       └─ Compare types 24092 and 24091 (748ms)
    │           │                          └─ Compare types 24290 and 24289 (708ms)
    │           │                             └─ Check expression from (line 177, char 2) to (line 177, char 2) (708ms)
    │           │                                └─ Determine variance of type 14841 (706ms)
    │           │                                   └─ {"id":14841,"kind":"GenericType","name":"ButtonProperties","typeArguments":[14842,14843,14844,14845,14846,14847,14848,14849,14850,14851],"location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":1}}
    │           │                                      ├─ {"id":14842,"kind":"TypeParameter","name":"K","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":35}}
    │           │                                      ├─ {"id":14843,"kind":"TypeParameter","name":"S","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":48}}
    │           │                                      ├─ {"id":14844,"kind":"TypeParameter","name":"KText","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":61}}
    │           │                                      ├─ {"id":14845,"kind":"TypeParameter","name":"SText","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":78}}
    │           │                                      ├─ {"id":14846,"kind":"TypeParameter","name":"KIcon","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":95}}
    │           │                                      ├─ {"id":14847,"kind":"TypeParameter","name":"SIcon","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":112}}
    │           │                                      ├─ {"id":14848,"kind":"TypeParameter","name":"KImage","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":129}}
    │           │                                      ├─ {"id":14849,"kind":"TypeParameter","name":"SImage","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":147}}
    │           │                                      ├─ {"id":14850,"kind":"TypeParameter","name":"KAnimated","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":165}}
    │           │                                      └─ {"id":14851,"kind":"TypeParameter","name":"SAnimated","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\button.ts","line":20,"char":186}}
    │           └─ Compare types 35048 and 35047 (834ms)
    │              └─ Compare types 35074 and 35073 (650ms)
    │                 └─ Compare types 35077 and 35076 (650ms)
    │                    └─ Compare types 35080 and 35079 (649ms)
    │                       └─ Determine variance of type 14166 (648ms)
    │                          └─ Compare types 35101 and 35100 (556ms)
    │                             └─ Compare types 35132 and 35131 (546ms)
    │                                └─ Compare types 35136 and 35134 (546ms)
    │                                   └─ Compare types 35135 and 35133 (546ms)
    │                                      └─ Compare types 35107 and 35102 (545ms)
    │                                         └─ Determine variance of type 35081 (545ms)
    │                                            └─ Compare types 36320 and 36319 (421ms)
    │                                               └─ Compare types 36360 and 36356 (408ms)
    │                                                  └─ Compare types 36357 and 36353 (295ms)
    │                                                     └─ Determine variance of type 35199 (295ms)
    │                                                        └─ Compare types 36397 and 36396 (225ms)
    │                                                           └─ Compare types 36422 and 36421 (221ms)
    │                                                              └─ Compare types 36435 and 36433 (220ms)
    │                                                                 └─ Compare types 36434 and 36432 (220ms)
    │                                                                    └─ Compare types 36407 and 36400 (218ms)
    │                                                                       └─ Determine variance of type 36375 (218ms)
    │                                                                          └─ {"id":36375,"kind":"GenericType","name":"HeaderProperties","typeArguments":[36376,36377,36378,36379,36380,36381,36382,36383,36384,36385],"location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":1}}
    │                                                                             ├─ {"id":36376,"kind":"TypeParameter","name":"K","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":35}}
    │                                                                             ├─ {"id":36377,"kind":"TypeParameter","name":"S","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":43}}
    │                                                                             ├─ {"id":36378,"kind":"TypeParameter","name":"KSubHeader","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":51}}
    │                                                                             ├─ {"id":36379,"kind":"TypeParameter","name":"SSubHeader","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":68}}
    │                                                                             ├─ {"id":36380,"kind":"TypeParameter","name":"KIcon","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":85}}
    │                                                                             ├─ {"id":36381,"kind":"TypeParameter","name":"SIcon","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":97}}
    │                                                                             ├─ {"id":36382,"kind":"TypeParameter","name":"KImage","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":109}}
    │                                                                             ├─ {"id":36383,"kind":"TypeParameter","name":"SImage","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":122}}
    │                                                                             ├─ {"id":36384,"kind":"TypeParameter","name":"KText","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":135}}
    │                                                                             └─ {"id":36385,"kind":"TypeParameter","name":"SText","location":{"path":"d:\workspaces\xlefebvre\customer\royal\middleoffice\sparkowstudio\src\js\components\elements\header.ts","line":20,"char":147}}
    

    To find the types in question, i'm using the command simplify-trace-types and search for type ids in generated file. But it's can of tedious to go back and forth between the two files. Would it be possible to have an option for analyze-trace to inline type names ? and another maybe for their location ? (like it's already done for the leafs of the output).

    Maybe something like this: image

    opened by Ikaer 4
  • Update README.md

    Update README.md

    When running as instructed we get the following error:

    This PR fixes the instruction of the README by changing to the correct package name @typescript/analyze-trace.

    opened by klzns 4
  • Make README instructions more digestible

    Make README instructions more digestible

    With a bit of time, someone using this tool can probably figure out what commands to run - but if we could make it clearer from a quick glance to

    just run this!
    

    with codeblocks and and headings and the like, we can make the process feel less overwhelming.

    documentation help wanted 
    opened by DanielRosenwasser 3
  • Consider using another metric than time to check for hot spots

    Consider using another metric than time to check for hot spots

    This tool is great, I solved a few problems thanks to it.

    So I thought that I would add it as a step of our CI to prevent regressions or adding new performance issues. But our CI runs on much slower machines than mine so it catches a lot more things.

    Isn't there a metric more constant that this tool could be based on to figure out how much typescript has to work and where things could be improved?

    opened by julienfouilhe 3
  • Detect slow loading of barrel modules

    Detect slow loading of barrel modules

    We've seen some projects slowed down by pulling in a huge number of files from a library when they really only wanted a small portion of the functionality. Ideally, the compiler itself would recognize this but, until then, flagging them could help people make spot fixes. Unfortunately, this seems to have a lot of false positive, esp in monorepos where node_modules might actually be user code.

    Part of #2.

    opened by amcasey 1
  • Report on actionable emit hotspots

    Report on actionable emit hotspots

    After looking at lots of traces it appears that JS emit is nearly always proportional (with a small constant) to file size (even with down-levelling), so flagging JS files that took a long time to emit rarely does anything beyond identifying large input files.

    Declaration emit, on the other hand, is much less directly related to input size. So far, the most important factor we've found for disproportionately slow declaration emit is the presence of a lot of import expressions in the output. This PR attempts to flag such instances by searching slow-to-emit declaration files (if present) for import expressions.

    Fixes #3 (until we find some other cause of disproportionate slowdown).

    opened by amcasey 1
  • feature request: Show source code in the output

    feature request: Show source code in the output

    Showing the filename and line numbers is helpful, but it means a lot of manually digging when looking for common patterns.

    I made another POC. The tree component may need to be fixed or replaced to support new lines.

    Screen Shot 2022-09-22 at 11 45 53 AM

    As a developer using TypeScript, and not somebody developing TypeScript, it might even be more helpful to show less of the internal information, and instead display the results similar to how tsc shows errors.

    BEFORE

     {"id":4961,"kind":"GenericTypeAlias","name":"Pick","aliasTypeArguments":[4909,4960],"location":{"path":"/users/dylang/repo/node_modules/typescript/lib/lib.es5.d.ts","line":1578,"char":1}}
    

    AFTER

    repo/node_modules/typescript/lib/lib.es5.d.ts:1578:1
    
    1578 type Pick<T, K extends keyof T> = {
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    opened by dylang 3
  • request: something like `--watch`  mode

    request: something like `--watch` mode

    It would be helpful if there was something like --watch mode, or documentation for how to do this.

    Example workflow:

    1. We run analyze-trace ts-trace
    2. Oh look, a hot spot!
    Analyzed /Users/dylang/project/packages/example/tsconfig.json (trace.65458-188.json)
    Hot Spots
    └─ Check file /Users/dylang/project/packages/example/slow-type-in-here.js (1739ms)
       └─ Check variable declaration from (line 57, char 7) to (line 62, char 2) (1441ms)
          └─ Check expression from (line 57, char 30) to (line 62, char 2) (1441ms)
             └─ Check expression from (line 57, char 30) to (line 57, char 52) (1438ms)
                └─ Compare types 13361 and 4729 (1249ms)
    
    
    1. We make a change to try to fix it, and hit save....

    This is where this feature request starts.

    1. analyze-trace automatically runs again. Fewer files may need to be recompiled so analyze-trace is only showing results from those re-compiles. Feature Request
    2. The output from analyze-trace tells us how much faster or slower each change is compared to the previous run. Bonus Feature Request
    opened by dylang 0
  • Guidance on output redirection for Windows

    Guidance on output redirection for Windows

    If I try running the trace analyzer with npx analyze-trace --color false > foo.txt, then foo.txt gets something like the following output.

    Hot Spots
    Γö£ΓöÇ Check file c:\users\Daniel\scratch\ant-design-icons\packages\icons-react\node_modules\typescript\lib\lib.dom.d.ts (816ms)
    Γö£ΓöÇ Check file c:\users\Daniel\scratch\ant-design-icons\packages\icons-react\node_modules\@types\babel__traverse\index.d.ts (511ms)
    ΓööΓöÇ Check file c:\users\Daniel\scratch\ant-design-icons\packages\icons-react\node_modules\@types\react\index.d.ts (507ms)
    

    instead of the expected box drawing characters

    Hot Spots
    ├─ Check file c:\users\Daniel\scratch\ant-design-icons\packages\icons-react\node_modules\typescript\lib\lib.dom.d.ts (816ms)
    ├─ Check file c:\users\Daniel\scratch\ant-design-icons\packages\icons-react\node_modules\@types\babel__traverse\index.d.ts (511ms)
    └─ Check file c:\users\Daniel\scratch\ant-design-icons\packages\icons-react\node_modules\@types\react\index.d.ts (507ms)
    

    This is apparently because Node.js outputs to UTF8, and PowerShell's redirection functionality (at least the version I'm using, 5.1) thinks it's receiving UTF16. The fix is to set

    [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
    
    opened by DanielRosenwasser 0
  • Add baseline tests

    Add baseline tests

    Matrix:

    • file vs dir
    • types (un)available
    • source (un)available
    • json vs text

    It needs to be possible to diff against the old baseline and accept the new baseline.

    The biggest obstacle is likely to be source file lookup - real traces use absolute paths, but those won't be portable (e.g. to CI machines). Post-processing the trace files (i.e. test cases) to use forward-slash-delimited relative paths might suffice.

    opened by amcasey 0
  • State machine incorrectly treats division as the start of a regex

    State machine incorrectly treats division as the start of a regex

    e.g. in x / y, / y will be classified as a regex (to EOL).

    To handle this properly, we'd need a parser - you need to know whether the slash is at the start of an expression. Offsets in the incorrectly classified region will (probably) map to the correct line but an incorrect character position, since trivia skipping rules are different within regexes.

    opened by amcasey 2
Owner
Microsoft
Open source projects and samples from Microsoft
Microsoft
Palaemon is an open-source developer tool for monitoring health and resource metrics of Kubernetes clusters and analyzing Out of Memory (OOMKill) errors

Palaemon ?? ?? An Electron based developer tool for Kubernetes cluster monitoring and error analysis Palaemon is a Greek, child sea-god who came to ai

OSLabs Beta 99 Dec 28, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Minimal template engine with compiled output for JavaScript.

@fnando/seagull Minimal template engine with compiled output for JavaScript. Installation This package is available as a NPM package. To install it, u

Nando Vieira 5 Mar 1, 2022
Logs the output, time, arguments, and stacktrace of any function when it's called in a gorgeous way.

Function.prototype.log Logs the output, time, arguments, and stacktrace of any function when it's called. How to use: Like this: function yourFunction

--Explosion-- 4 Apr 9, 2022
Group and sort Eleventy’s verbose output by directory (and show file size with benchmarks)

eleventy-plugin-directory-output Group and sort Eleventy’s verbose output by directory (and show file size with benchmarks). Sample output from eleven

Eleventy 16 Oct 27, 2022
A string of four operations of the library, can solve the js digital calculation accuracy of scientific notation and formatting problems, support for thousands of decimal point formatting output operations

A string of four operations of the library, can solve the js digital calculation accuracy of scientific notation and formatting problems, support for thousands of decimal point formatting output operations

null 10 Apr 6, 2022
🔨 A more engineered, highly customizable, standard output format commitizen adapter.

cz-git Github | Installation | Website | 简体中文文档 Introduction A more engineered, highly customizable, standard output format commitizen adapter. What i

zhengqbbb 402 Dec 31, 2022
Script to fetch all NFT owners using moralis API. This script output is a data.txt file containing all owner addresses of a given NFT and their balances.

?? Moralis NFT Snapshot Moralis NFT API will only return 500 itens at a time when its is called. For that reason, a simple logic is needed to fetch al

Phill Menezes 6 Jun 23, 2022
Generate deterministic fake values: The same input will always generate the same fake-output.

import { copycat } from '@snaplet/copycat' copycat.email('foo') // => '[email protected]' copycat.email('bar') // => 'Thurman.Schowalter668@

Snaplet 201 Dec 30, 2022
ln-charts parses the output of bos accounting commands into various charts for your Lightning Node.

ln-charts ln-charts parses the output of bos accounting commands into various charts for your Lightning Node. It runs on Angular, JS, HTML, CSS, ngx-c

Steven Ellis 21 Dec 18, 2022
javascript library to convert a list of objects to a nested json output format, depending on the names in the list

formToNestedJson javascript "library" to convert a list of objects to a nested json output format, depending on the names in the list Basic usage Give

null 2 Aug 2, 2021
This package will help parse OData strings (only the Microsoft Dataverse subset). It can be used as a validator, or you can build some javascript library which consumes the output of this library.

@albanian-xrm/dataverse-odata This package will help parse OData strings (only the Microsoft Dataverse subset). It can be used as a validator, or you

AlbanianXrm 3 Oct 22, 2022
A CLI tool to create a NodeJS project with TypeScript CTSP is a CLI tool to make easier to start a new NodeJS project and configure Typescript on it.

CTSP- Create TS Project A CLI tool to create a NodeJS project with TypeScript CTSP is a CLI tool to make easier to start a new NodeJS project and conf

Jean Rodríguez 7 Sep 13, 2022
A tool to check for response status codes with ease

About Archer Archer is an cross-platform tool developed using Nodejs which focuses on the reconnaissance phase of a penetration test. Got a bunch of l

Umair 14 Oct 19, 2022
A simple JavaScript beautify tool

A simple JavaScript beautify tool This tool will do the following things: Beautify the JavaScript code Convert hexadecimal number to decimal number, s

phithon 27 May 8, 2022
A refined tool for exploring open-source projects on GitHub with a file tree, rich Markdown and image previews, multi-pane multi-tab layouts and first-class support for Ink syntax highlighting.

Ink codebase browser, "Kin" ?? The Ink codebase browser is a tool to explore open-source code on GitHub, especially my side projects written in the In

Linus Lee 20 Oct 30, 2022