JuliaControl / ControlSystems.jl

A Control Systems Toolbox for Julia
https://juliacontrol.github.io/ControlSystems.jl/stable/
Other
516 stars 86 forks source link

Split out OrdinaryDiffEq functionality #738

Closed baggepinnen closed 2 years ago

baggepinnen commented 2 years ago

In Julia v1.8, OrdinaryDiffEq takes an enormous amount of time to precompile and load without a system image. The following breakdown indicates that most of the latency when loading CS is related to OrdinaryDiffEq and dependencies of OrdinaryDiffEq such as ReverseDiff. I therefore propose to create a ControlSystemsBase where most things, everything that does not significantly contribute to latency, is kept, and ControlSystemsSimulation that contains the features that depend on OrdinaryDiffEq. The package ControlSystems will continue to export all the existing functionality, so the change would be non-breaking and only add the option to load ControlSystemsBase for workflows that do not need continuous-time simulation.

julia> @time using ControlSystems
 11.893709 seconds (48.08 M allocations: 3.387 GiB, 7.21% gc time, 5.97% compilation time: 65% of which was recompilation)

julia> @time_imports using ControlSystems
     34.1 ms  RecipesBase
      0.5 ms  LaTeXStrings
    114.9 ms  Polynomials
      2.6 ms  DocStringExtensions 66.35% compilation time
      0.1 ms  Reexport
      0.2 ms  Requires
      1.8 ms  ArrayInterfaceCore
      1.4 ms  StaticArraysCore
    477.7 ms  StaticArrays
      9.0 ms  FunctionWrappers
      0.2 ms  MuladdMacro
      4.7 ms  OrderedCollections
      0.1 ms  UnPack
      0.2 ms  Parameters
     11.4 ms  FiniteDiff 60.64% compilation time (13% recompilation)
      3.7 ms  IrrationalConstants
      0.5 ms  DiffRules
      1.6 ms  DiffResults
     13.6 ms  Preferences
      0.1 ms  OpenLibm_jll
      0.2 ms  NaNMath
      0.3 ms  Compat
     46.3 ms  ChainRulesCore
      0.3 ms  ChangesOfVariables
      0.4 ms  InverseFunctions
      0.5 ms  LogExpFunctions
      0.2 ms  JLLWrappers
      0.2 ms  CompilerSupportLibraries_jll
     20.0 ms  OpenSpecFun_jll 98.10% compilation time (94% recompilation)
     10.5 ms  SpecialFunctions
     46.0 ms  MacroTools
      0.2 ms  CommonSubexpressions
     91.8 ms  ForwardDiff
      0.5 ms  ConstructionBase
    264.8 ms  Setfield 91.94% compilation time (83% recompilation)
      0.2 ms  ZygoteRules
      0.2 ms  Adapt
      0.2 ms  ArrayInterfaceStaticArraysCore
    119.9 ms  FillArrays
      0.1 ms  DataValueInterfaces
      0.7 ms  DataAPI
      0.1 ms  IteratorInterfaceExtensions
      0.0 ms  TableTraits
      9.8 ms  Tables
      2.5 ms  GPUArraysCore
     21.3 ms  RecursiveArrayTools
     11.0 ms  IterativeSolvers
      0.0 ms  IfElse
     16.3 ms  Static
     10.3 ms  ArrayInterface
     74.9 ms  OffsetArrays
      0.5 ms  ArrayInterfaceOffsetArrays
      0.7 ms  ArrayInterfaceStaticArrays
      0.1 ms  SIMDTypes
      1.1 ms  ManualMemory
      2.7 ms  LayoutPointers
      0.7 ms  CpuId
     59.0 ms  CPUSummary 72.52% compilation time
      0.1 ms  BitTwiddlingConvenienceFunctions
     77.7 ms  HostCPUFeatures 12.31% compilation time
    439.9 ms  VectorizationBase
      3.0 ms  SLEEFPirates
     37.8 ms  ThreadingUtilities 79.04% compilation time
     12.3 ms  PolyesterWeave 71.02% compilation time
      2.5 ms  CloseOpenIntervals
      0.1 ms  SnoopPrecompile
     63.4 ms  SIMDDualNumbers
    280.4 ms  LoopVectorization
    155.1 ms  StrideArraysCore 2.07% compilation time
      0.5 ms  Polyester
    193.0 ms  TriangularSolve 3.54% compilation time
    345.8 ms  RecursiveFactorization
      0.1 ms  CommonSolve
      0.6 ms  FunctionWrappersWrappers
    129.8 ms  SciMLBase
      4.3 ms  NonlinearSolve
      0.3 ms  FastBroadcast
     61.5 ms  DataStructures
      0.2 ms  SortingAlgorithms
      6.3 ms  Missings
      0.2 ms  StatsAPI
     17.6 ms  StatsBase
     16.1 ms  PDMats
    191.1 ms  Rmath_jll 99.83% compilation time (100% recompilation)
     67.4 ms  Rmath 90.24% compilation time
      1.9 ms  Calculus
     59.3 ms  DualNumbers
      0.7 ms  HypergeometricFunctions
      4.6 ms  StatsFuns
      1.9 ms  QuadGK
      0.9 ms  DensityInterface
    174.8 ms  Distributions
     22.0 ms  DiffEqBase 52.71% compilation time
      0.1 ms  FastClosures
     12.2 ms  KLU
      7.6 ms  FastLapackInterface
     10.2 ms  Krylov
    214.0 ms  KrylovKit 0.94% compilation time
    242.3 ms  LinearSolve 15.35% compilation time (88% recompilation)
   3242.0 ms  ReverseDiff
      1.1 ms  PreallocationTools
     20.9 ms  GenericSchur
      0.1 ms  libblastrampoline_jll
      2.7 ms  ExponentialUtilities
      4.2 ms  Distances
      4.5 ms  NLSolversBase
      4.9 ms  LineSearches
      2.0 ms  NLsolve
      1.2 ms  SimpleTraits
      3.7 ms  ArnoldiMethod
      0.4 ms  Inflate
     33.1 ms  Graphs
      0.4 ms  VertexSafeGraphs
     13.5 ms  SparseDiffTools 40.25% compilation time
      0.1 ms  ArrayInterfaceGPUArrays
   2041.2 ms  OrdinaryDiffEq
    193.4 ms  FixedPointNumbers
     88.6 ms  ColorTypes 5.07% compilation time
    757.8 ms  Colors
      8.5 ms  AbstractFFTs
      0.6 ms  FFTW_jll
    484.0 ms  FFTW 3.81% compilation time (100% recompilation)
     28.3 ms  IterTools
     38.9 ms  DSP
      5.3 ms  DiffEqCallbacks
      2.9 ms  MatrixPencils
     10.3 ms  DelayDiffEq
    110.0 ms  LinearMaps
     10.7 ms  MatrixEquations
    324.5 ms  ControlSystems

Removal of DelayDiffEq, OrdinaryDiffEq from the Manifest rids us of the following dependencies

(ControlSystems) pkg> rm DelayDiffEq OrdinaryDiffEq
    Updating `~/.julia/dev/ControlSystems/Project.toml`
  [bcd4f6db] - DelayDiffEq v5.37.1
  [1dea7af3] - OrdinaryDiffEq v6.26.2
    Updating `~/.julia/dev/ControlSystems/Manifest.toml`
  [ec485272] - ArnoldiMethod v0.2.0
  [6ba088a2] - ArrayInterfaceGPUArrays v0.2.1
  [bcd4f6db] - DelayDiffEq v5.37.1
  [d4d017d3] - ExponentialUtilities v1.18.0
  [9aa1b823] - FastClosures v0.3.2
  [29a986be] - FastLapackInterface v1.2.6
  [c145ed77] - GenericSchur v0.5.3
  [86223c79] - Graphs v1.7.2
  [d25df0c9] - Inflate v0.1.3
  [ef3ab10e] - KLU v0.3.0
  [ba0b0d4f] - Krylov v0.8.3
  [0b1a1467] - KrylovKit v0.5.4
  [7ed4a6bd] - LinearSolve v1.26.0
  [1dea7af3] - OrdinaryDiffEq v6.26.2
  [d236fae5] - PreallocationTools v0.4.2
  [37e2e3b7] - ReverseDiff v1.14.1
  [699a6c99] - SimpleTraits v0.9.4
  [47a9eef4] - SparseDiffTools v1.26.2
  [19fa3120] - VertexSafeGraphs v0.2.0
  [a63ad114] - Mmap
  [1a1011a3] - SharedArrays
  [bea87d4a] - SuiteSparse_jll v5.10.1+0
    214.0 ms  KrylovKit 0.94% compilation time
    242.3 ms  LinearSolve 15.35% compilation time (88% recompilation)
   3242.0 ms  ReverseDiff
   2041.2 ms  OrdinaryDiffEq

Removing Colors further removes the following deps

(ControlSystems) pkg> rm Colors
    Updating `~/.julia/dev/ControlSystems/Project.toml`
  [5ae59095] - Colors v0.12.8
    Updating `~/.julia/dev/ControlSystems/Manifest.toml`
  [3da002f7] - ColorTypes v0.11.4
  [5ae59095] - Colors v0.12.8
  [53c48c17] - FixedPointNumbers v0.8.4

757.8 ms  Colors

which can be done independently from the other changes

albheim commented 2 years ago

Sounds reasonable to me. How do you plan to organize it? Different repos or just subfolders of the main repo?

baggepinnen commented 2 years ago

Not sure yet, Optimization.jl uses different folders in the same repo for their sub projects, many other org use different repos. I'd like to find out what the pros and cons of the different approaches are

albheim commented 2 years ago

Sounds good.

I remember liking it when ReinforcementLearning.jl switched from different repos to subfolders, felt easier to navigate and find the code after the change. But I have not played around with some of the surrounding stuff like docs (seems like this could be easy to keep as is for subfolders?) or testing (which I think I understood might be trickier if you e.g. make changes to one of the subfolders and don't want all tests to run) so wouldn't weight my experience very high...

baggepinnen commented 2 years ago

I think that docs can still be kept like it is now, instead of having separate docs for each package. It's rather easy in documenter to document several packages in the same docs. It's also good for discoverability if the docs are centralized. With everything in the same repo, you'd also get issues centralized in one place rather than having multiple different issue trackers etc., so maybe the subfolders way is most convenient.

albheim commented 2 years ago

Yeah, both issues that are centralized and PRs where if you have a PR that covers multiple packages it can now be contained in a single PR instead of having to synchronize multiple PRs over all repos.

baggepinnen commented 2 years ago

This is now done, users can now install and use ControlSystemsBase.jl for any workflow that does not use continuous-time simulation (using an ODE solver). Discrete-time simulation is handled by ControlSystemsBase.