1 {-# LANGUAGE RecordWildCards #-}
3 -- | cabal-install CLI command: bench
4 module Distribution
.Client
.CmdBench
5 ( -- * The @bench@ CLI and action
9 -- * Internals exposed for testing
10 , componentNotBenchmarkProblem
11 , isSubComponentProblem
13 , selectPackageTargets
14 , selectComponentTarget
17 import Distribution
.Client
.Compat
.Prelude
20 import Distribution
.Client
.CmdErrorMessages
23 , renderTargetProblemNoTargets
24 , renderTargetSelector
26 , targetSelectorFilter
27 , targetSelectorPluralPkgs
29 import Distribution
.Client
.Errors
30 import Distribution
.Client
.NixStyleOptions
32 , defaultNixStyleFlags
35 import Distribution
.Client
.ProjectOrchestration
36 import Distribution
.Client
.Setup
40 import Distribution
.Client
.TargetProblem
43 import Distribution
.Client
.Utils
46 import Distribution
.Simple
.Command
50 import Distribution
.Simple
.Flag
53 import Distribution
.Simple
.Utils
58 import Distribution
.Verbosity
62 import GHC
.Environment
66 benchCommand
:: CommandUI
(NixStyleFlags
())
69 { commandName
= "v2-bench"
70 , commandSynopsis
= "Run benchmarks."
71 , commandUsage
= usageAlternatives
"v2-bench" ["[TARGETS] [FLAGS]"]
72 , commandDescription
= Just
$ \_
->
74 "Runs the specified benchmarks, first ensuring they are up to "
76 ++ "Any benchmark in any package in the project can be specified. "
77 ++ "A package can be specified in which case all the benchmarks in the "
78 ++ "package are run. The default is to run all the benchmarks in the "
79 ++ "package in the current directory.\n\n"
80 ++ "Dependencies are built or rebuilt as necessary. Additional "
81 ++ "configuration flags can be specified on the command line and these "
82 ++ "extend the project configuration from the 'cabal.project', "
83 ++ "'cabal.project.local' and other files."
84 , commandNotes
= Just
$ \pname
->
89 ++ " Run all the benchmarks in the package in the current directory\n"
92 ++ " v2-bench pkgname\n"
93 ++ " Run all the benchmarks in the package named pkgname\n"
96 ++ " v2-bench cname\n"
97 ++ " Run the benchmark named cname\n"
100 ++ " v2-bench cname -O2\n"
101 ++ " Run the benchmark built with '-O2' (including local libs used)\n"
102 , commandDefaultFlags
= defaultNixStyleFlags
()
103 , commandOptions
= nixStyleOptions
(const [])
106 -- | The @build@ command does a lot. It brings the install plan up to date,
107 -- selects that part of the plan needed by the given or implicit targets and
108 -- then executes the plan.
110 -- For more details on how this works, see the module
111 -- "Distribution.Client.ProjectOrchestration"
112 benchAction
:: NixStyleFlags
() -> [String] -> GlobalFlags
-> IO ()
113 benchAction flags
@NixStyleFlags
{..} targetStrings globalFlags
= do
114 baseCtx
<- establishProjectBaseContext verbosity cliConfig OtherCommand
117 either (reportTargetSelectorProblems verbosity
) return
118 =<< readTargetSelectors
(localPackages baseCtx
) (Just BenchKind
) targetStrings
121 runProjectPreBuildPhase verbosity baseCtx
$ \elaboratedPlan
-> do
122 when (buildSettingOnlyDeps
(buildSettings baseCtx
)) $
123 dieWithException verbosity BenchActionException
125 fullArgs
<- getFullArgs
126 when ("+RTS" `
elem` fullArgs
) $
128 giveRTSWarning
"bench"
130 -- Interpret the targets on the command line as bench targets
131 -- (as opposed to say build or haddock targets).
133 either (reportTargetProblems verbosity
) return $
136 selectComponentTarget
141 let elaboratedPlan
' =
142 pruneInstallPlanToTargets
146 return (elaboratedPlan
', targets
)
148 printPlan verbosity baseCtx buildCtx
150 buildOutcomes
<- runProjectBuildPhase verbosity baseCtx buildCtx
151 runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes
153 verbosity
= fromFlagOrDefault normal
(configVerbosity configFlags
)
155 commandLineFlagsToProjectConfig
158 mempty
-- ClientInstallFlags, not needed here
160 -- | This defines what a 'TargetSelector' means for the @bench@ command.
161 -- It selects the 'AvailableTarget's that the 'TargetSelector' refers to,
162 -- or otherwise classifies the problem.
164 -- For the @bench@ command we select all buildable benchmarks,
165 -- or fail if there are no benchmarks or no buildable benchmarks.
168 -> [AvailableTarget k
]
169 -> Either BenchTargetProblem
[k
]
170 selectPackageTargets targetSelector targets
171 -- If there are any buildable benchmark targets then we select those
172 |
not (null targetsBenchBuildable
) =
173 Right targetsBenchBuildable
174 -- If there are benchmarks but none are buildable then we report those
175 |
not (null targetsBench
) =
176 Left
(TargetProblemNoneEnabled targetSelector targetsBench
)
177 -- If there are no benchmarks but some other targets then we report that
178 |
not (null targets
) =
179 Left
(noBenchmarksProblem targetSelector
)
180 -- If there are no targets at all then we report that
182 Left
(TargetProblemNoTargets targetSelector
)
184 targetsBenchBuildable
=
185 selectBuildableTargets
186 . filterTargetsKind BenchKind
191 . filterTargetsKind BenchKind
194 -- | For a 'TargetComponent' 'TargetSelector', check if the component can be
197 -- For the @bench@ command we just need to check it is a benchmark, in addition
198 -- to the basic checks on being buildable etc.
199 selectComponentTarget
200 :: SubComponentTarget
202 -> Either BenchTargetProblem k
203 selectComponentTarget subtarget
@WholeComponent t
204 | CBenchName _
<- availableTargetComponentName t
=
205 selectComponentTargetBasic subtarget t
208 ( componentNotBenchmarkProblem
209 (availableTargetPackageId t
)
210 (availableTargetComponentName t
)
212 selectComponentTarget subtarget t
=
214 ( isSubComponentProblem
215 (availableTargetPackageId t
)
216 (availableTargetComponentName t
)
220 -- | The various error conditions that can occur when matching a
221 -- 'TargetSelector' against 'AvailableTarget's for the @bench@ command.
223 = -- | The 'TargetSelector' matches targets but no benchmarks
224 TargetProblemNoBenchmarks TargetSelector
225 |
-- | The 'TargetSelector' refers to a component that is not a benchmark
226 TargetProblemComponentNotBenchmark PackageId ComponentName
227 |
-- | Asking to benchmark an individual file or module is not supported
228 TargetProblemIsSubComponent PackageId ComponentName SubComponentTarget
231 type BenchTargetProblem
= TargetProblem BenchProblem
233 noBenchmarksProblem
:: TargetSelector
-> TargetProblem BenchProblem
234 noBenchmarksProblem
= CustomTargetProblem
. TargetProblemNoBenchmarks
236 componentNotBenchmarkProblem
:: PackageId
-> ComponentName
-> TargetProblem BenchProblem
237 componentNotBenchmarkProblem pkgid name
=
238 CustomTargetProblem
$
239 TargetProblemComponentNotBenchmark pkgid name
241 isSubComponentProblem
244 -> SubComponentTarget
245 -> TargetProblem BenchProblem
246 isSubComponentProblem pkgid name subcomponent
=
247 CustomTargetProblem
$
248 TargetProblemIsSubComponent pkgid name subcomponent
250 reportTargetProblems
:: Verbosity
-> [BenchTargetProblem
] -> IO a
251 reportTargetProblems verbosity
=
252 dieWithException verbosity
. RenderBenchTargetProblem
. map renderBenchTargetProblem
254 renderBenchTargetProblem
:: BenchTargetProblem
-> String
255 renderBenchTargetProblem
(TargetProblemNoTargets targetSelector
) =
256 case targetSelectorFilter targetSelector
of
258 | kind
/= BenchKind
->
259 "The bench command is for running benchmarks, but the target '"
260 ++ showTargetSelector targetSelector
262 ++ renderTargetSelector targetSelector
264 _
-> renderTargetProblemNoTargets
"benchmark" targetSelector
265 renderBenchTargetProblem problem
=
266 renderTargetProblem
"benchmark" renderBenchProblem problem
268 renderBenchProblem
:: BenchProblem
-> String
269 renderBenchProblem
(TargetProblemNoBenchmarks targetSelector
) =
270 "Cannot run benchmarks for the target '"
271 ++ showTargetSelector targetSelector
272 ++ "' which refers to "
273 ++ renderTargetSelector targetSelector
275 ++ plural
(targetSelectorPluralPkgs targetSelector
) "it does" "they do"
276 ++ " not contain any benchmarks."
277 renderBenchProblem
(TargetProblemComponentNotBenchmark pkgid cname
) =
278 "The bench command is for running benchmarks, but the target '"
279 ++ showTargetSelector targetSelector
281 ++ renderTargetSelector targetSelector
282 ++ " from the package "
286 targetSelector
= TargetComponent pkgid cname WholeComponent
287 renderBenchProblem
(TargetProblemIsSubComponent pkgid cname subtarget
) =
288 "The bench command can only run benchmarks as a whole, "
289 ++ "not files or modules within them, but the target '"
290 ++ showTargetSelector targetSelector
292 ++ renderTargetSelector targetSelector
295 targetSelector
= TargetComponent pkgid cname subtarget