Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Export PLT #1931

Open
Zalastax opened this issue Nov 6, 2018 · 16 comments
Open

Export PLT #1931

Zalastax opened this issue Nov 6, 2018 · 16 comments

Comments

@Zalastax
Copy link

Zalastax commented Nov 6, 2018

I'd like to distribute a PLT file that contains all the specs in my applications.
To do that I expect to be able to use rebar3 dialyzer with some special flag.

If I turn on DEBUG,

?DEBUG("Running dialyzer with options: ~p~n", [Opts2]),
almost prints what I need when being called from succ_typings:

[{warnings,[]},
  {check_plt,false},
  {analysis_type,succ_typings},
  {get_warnings,true},
  {from,byte_code},
  {files, [BunchOfFiles]},
  {init_plt, "MyInitPLT"}]

for my use case I just need to

  • change {analysis_type,succ_typings} to {analysis_type,plt_add}
  • add {output_plt, "somefilename"}

Would you accept a PR where I add a new option

{export_plt_to, $x, "export-plt-to", string, "Export the project PLT to a file"}

and simply duplicate succ_typings into a new function export_plt which I modify to pass in my suggested options?

@Zalastax Zalastax changed the title Output project PLT Export PLT Nov 6, 2018
@fishcakez
Copy link
Contributor

I think if we want to support a PLT that includes everything we should have a configs option that match our lower level/base PLTs, and then a flag to build the higher level PLT. This would allow us to do more efficient changes to the PLT as we already have code to do this. Also we can guarantee to keep the PLT in sync with the code. This would also enable a new use case where rebar3 dialyzer could only show warnings for what changed since it was last run (and do faster analysis). Given how this provider works I guess it would be more matching the style for a flag true/false to do this top level one.

@Zalastax
Copy link
Author

Zalastax commented Nov 7, 2018

So the idea would be to maintain a list of files + the modification date they had when they were added? When dialyzing, we would start by removing any modified/removed files from the PLT, write that to a PLT, followed by adding the modified files to that new PLT?
How often will that be faster than just building all from scratch? Perhaps we need to do a benchmark. Or was your idea mainly to get an output that is less noisy if there are many errors?

@ferd
Copy link
Collaborator

ferd commented Nov 7, 2018

My understanding was that PLTs were sensitive to absolute paths in a system and therefore should not be packaged and distributed since the differences in paths would cause the PLT to be rebuilt anyway?

If that is indeed the case, then exporting the PLTs would be of limited value in the first place. Would it still be worth it for you? What's your use case with the exported PLT?

@Zalastax
Copy link
Author

Zalastax commented Nov 7, 2018

It would still be useful to me! The use case is that my rebar3 projects are sub-components in a larger system which is not built using rebar3. To run dialyzer for the whole system we need a PLT for each sub-component; this leads to my initial suggestion. The PLTs are used in a very controlled environment so paths changing is not a problem.

@tothlac
Copy link
Contributor

tothlac commented Nov 11, 2018

We have also started thinking about something similar.

We have 42 rebar3 projects stored in different repos. If I run dialyzer on project1 which includes let's say lager─3.6.4+build.167.refbba1452 (that's from the output of rebar3 tree) it would be useful to create lager─3.6.4+build.167.refbba1452.plt, store it similarly to how rebar3 caches pkg files in the cache folder : $HOME/.cache/rebar3/plts/lager─3.6.4+build.167.refbba1452.plt. Similarly the plt stored to the project itself (in this case project1-1.0.1+build.XXXXX.plt) should be stored, then if an other repository wants to use it just get it out from the cache.

Why would it be useful? On most projects having only a few tests most of the time is taken by dialyzer if I run a CI job. It would make the CI jobs at least 2-3 times faster.

@fishcakez
Copy link
Contributor

@tothlac having projects in different repos makes this a challenge because of @ferd's comment. There may also be other complications because the PLTs would be overlapping. For example both PLTs would contain their dependencies. I wonder if CI could handle this via a fake umbrella project with git submodules?

Before starting on this we need to understand the desired dialyzer workflow and check it doesn't need changes to dialyzer itself.

@Zalastax
Copy link
Author

I've looked at dialyzer_plt and as far as I can tell it's the file contents rather than the name that matters. Duplicates might raise a warning (which I hope you can silence, otherwise I find that to be a bug). I believe that the workflow is already supported - my initial suggestion sure is.

@Zalastax
Copy link
Author

I had a look at this again.

From the documentation:

--plts plt*

    Merge the specified PLTs to create the initial PLT. This requires that the PLTs are disjoint (that is, do not have any module appearing in more than one PLT). The PLTs are created in the usual way:

    dialyzer --build_plt --output_plt plt_1 files_to_include
    ...
    dialyzer --build_plt --output_plt plt_n files_to_include

    They can then be used in either of the following ways:

    dialyzer files_to_analyze --plts plt_1 ... plt_n

    or

    dialyzer --plts plt_1 ... plt_n -- files_to_analyze

    Notice the -- delimiter in the second case.

We see here that multiple PLTs can be combined, but only in analyze mode. --add_to_plt together with --plts causes Dialyzer to crash. --build_plt causes --plts to be ignored. We also see that we can't combine PLTs that have the same modules in them.

This gives two ways of working:

Serial mode

Use --add_to_plt to build up a single PLT. To get useful errors in each step, add projects in dependency order.

Serial mode will create one very large PLT. When a dependency is updated, we would have to build the PLT from scratch. --remove_from_plt could be used to avoid rebuilding from scratch but that seems tricky. Modules might have been removed in between version so it's not possible to just overwrite the PLT with the new beams.

Parallel mode

Use --build_plt to create multiple PLTs. Many errors from these builds have to be ignored since there's no way to include dependency information. Finally, run dialyzer in analyze mode with --plts.

Parallel mode is what we use now in our Make-based solution. We keep track of the errors from each PLT built but mostly focus on the errors reported when everything is put together.

My proposal

Rebar3 should support the parallel mode approach. To do that, we need to build a PLT for each dependency that only contains the modules of the dependency itself. We will need two modes:

  • Analyze mode: Add PLTs for all transitive dependencies using --plts and analyze the beam files of the project.
  • Extract mode: Build a PLT for only the beam files of the project. Put the PLT and the PLTs of transitive dependencies in an accessible place.

Unfortunately, I think this would require a major rework of rebar_prv_dialyzer.

@ferd
Copy link
Collaborator

ferd commented Feb 27, 2020

Also: what would be the benefit of this? Would it still be only about letting people export PLTs that only they can use (because of path-related issues and restrictions)?
I'm not insensitive to the case, but I'm having a harder time gauging it with what would be a major rewrite of how this whole thing works today given limited development time.

@Zalastax
Copy link
Author

This would let people export PLTs that can be reused by anyone since the PLTs do not have path-related issues. It would for example be possible to store the PLTs in hex if so desired. We need this so that rebar3 projects can play nicely under our Make based umbrella project. I believe this approach would also speed up consecutive runs of rebar3 dialyzer.
I totally understand that there's not enough bandwidth for you to make this change. However, if you agree that this is a good goal, then my organization might be able to put resources into implementing it. I know that there are stills costs attached with code reviews etc.

@ferd
Copy link
Collaborator

ferd commented Feb 27, 2020

Did anything change in Dialyzer that suddenly made PLTs portable? Because they absolutely weren't at any point in the past.

@Zalastax
Copy link
Author

I noticed now that there is file information included but our experience is that you can use the PLTs even if the file information is incorrect, e.g. if the beam files have been moved. @uabboli, can you shed some light on the issue?

@max-au
Copy link
Contributor

max-au commented Mar 12, 2020

We're introducing Dialyzer to our codebase, and having similar issues. After some trial and error path, we came up to this approach:

  1. Run (modified) rebar3 dialyzer provider to add all project applications into PLT (rebar_prv_dialyzer:proj_plt_files has plt_extra_apps flag, that can be reused to say "all apps of the umbrella").
  2. Analyse apps (or rather folders) one-by-one with "rebar3 dialyzer --app=app1" (potentially it could be "--dir=appname/src", to stay in line with rebar3 ct provider).

This is rather limited change, would it work for your use-case too? @Zalastax

@max-au
Copy link
Contributor

max-au commented Mar 13, 2020

Made a PR, #2249
Would it also solve original problem?

@Zalastax
Copy link
Author

My initial impression is that it should work to solve our original problem. Will have a look at the PR to see if there's anything that would make it not so.

@Zalastax
Copy link
Author

No, that PR doesn't solve my problem. I need to be able to use PLTs coming from two different umbrella projects that share dependencies together.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants