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
.Setup
(CommonSetupFlags
(..))
54 import Distribution
.Simple
.Utils
59 import Distribution
.Verbosity
63 import GHC
.Environment
67 benchCommand
:: CommandUI
(NixStyleFlags
())
70 { commandName
= "v2-bench"
71 , commandSynopsis
= "Run benchmarks."
72 , commandUsage
= usageAlternatives
"v2-bench" ["[TARGETS] [FLAGS]"]
73 , commandDescription
= Just
$ \_
->
75 "Runs the specified benchmarks, first ensuring they are up to "
77 ++ "Any benchmark in any package in the project can be specified. "
78 ++ "A package can be specified in which case all the benchmarks in the "
79 ++ "package are run. The default is to run all the benchmarks in the "
80 ++ "package in the current directory.\n\n"
81 ++ "Dependencies are built or rebuilt as necessary. Additional "
82 ++ "configuration flags can be specified on the command line and these "
83 ++ "extend the project configuration from the 'cabal.project', "
84 ++ "'cabal.project.local' and other files."
85 , commandNotes
= Just
$ \pname
->
90 ++ " Run all the benchmarks in the package in the current directory\n"
93 ++ " v2-bench pkgname\n"
94 ++ " Run all the benchmarks in the package named pkgname\n"
97 ++ " v2-bench cname\n"
98 ++ " Run the benchmark named cname\n"
101 ++ " v2-bench cname -O2\n"
102 ++ " Run the benchmark built with '-O2' (including local libs used)\n"
103 , commandDefaultFlags
= defaultNixStyleFlags
()
104 , commandOptions
= nixStyleOptions
(const [])
107 -- | The @build@ command does a lot. It brings the install plan up to date,
108 -- selects that part of the plan needed by the given or implicit targets and
109 -- then executes the plan.
111 -- For more details on how this works, see the module
112 -- "Distribution.Client.ProjectOrchestration"
113 benchAction
:: NixStyleFlags
() -> [String] -> GlobalFlags
-> IO ()
114 benchAction flags
@NixStyleFlags
{..} targetStrings globalFlags
= do
115 baseCtx
<- establishProjectBaseContext verbosity cliConfig OtherCommand
118 either (reportTargetSelectorProblems verbosity
) return
119 =<< readTargetSelectors
(localPackages baseCtx
) (Just BenchKind
) targetStrings
122 runProjectPreBuildPhase verbosity baseCtx
$ \elaboratedPlan
-> do
123 when (buildSettingOnlyDeps
(buildSettings baseCtx
)) $
124 dieWithException verbosity BenchActionException
126 fullArgs
<- getFullArgs
127 when ("+RTS" `
elem` fullArgs
) $
129 giveRTSWarning
"bench"
131 -- Interpret the targets on the command line as bench targets
132 -- (as opposed to say build or haddock targets).
134 either (reportTargetProblems verbosity
) return $
137 selectComponentTarget
142 let elaboratedPlan
' =
143 pruneInstallPlanToTargets
147 return (elaboratedPlan
', targets
)
149 printPlan verbosity baseCtx buildCtx
151 buildOutcomes
<- runProjectBuildPhase verbosity baseCtx buildCtx
152 runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes
154 verbosity
= fromFlagOrDefault normal
(setupVerbosity
$ configCommonFlags configFlags
)
156 commandLineFlagsToProjectConfig
159 mempty
-- ClientInstallFlags, not needed here
161 -- | This defines what a 'TargetSelector' means for the @bench@ command.
162 -- It selects the 'AvailableTarget's that the 'TargetSelector' refers to,
163 -- or otherwise classifies the problem.
165 -- For the @bench@ command we select all buildable benchmarks,
166 -- or fail if there are no benchmarks or no buildable benchmarks.
169 -> [AvailableTarget k
]
170 -> Either BenchTargetProblem
[k
]
171 selectPackageTargets targetSelector targets
172 -- If there are any buildable benchmark targets then we select those
173 |
not (null targetsBenchBuildable
) =
174 Right targetsBenchBuildable
175 -- If there are benchmarks but none are buildable then we report those
176 |
not (null targetsBench
) =
177 Left
(TargetProblemNoneEnabled targetSelector targetsBench
)
178 -- If there are no benchmarks but some other targets then we report that
179 |
not (null targets
) =
180 Left
(noBenchmarksProblem targetSelector
)
181 -- If there are no targets at all then we report that
183 Left
(TargetProblemNoTargets targetSelector
)
185 targetsBenchBuildable
=
186 selectBuildableTargets
187 . filterTargetsKind BenchKind
192 . filterTargetsKind BenchKind
195 -- | For a 'TargetComponent' 'TargetSelector', check if the component can be
198 -- For the @bench@ command we just need to check it is a benchmark, in addition
199 -- to the basic checks on being buildable etc.
200 selectComponentTarget
201 :: SubComponentTarget
203 -> Either BenchTargetProblem k
204 selectComponentTarget subtarget
@WholeComponent t
205 | CBenchName _
<- availableTargetComponentName t
=
206 selectComponentTargetBasic subtarget t
209 ( componentNotBenchmarkProblem
210 (availableTargetPackageId t
)
211 (availableTargetComponentName t
)
213 selectComponentTarget subtarget t
=
215 ( isSubComponentProblem
216 (availableTargetPackageId t
)
217 (availableTargetComponentName t
)
221 -- | The various error conditions that can occur when matching a
222 -- 'TargetSelector' against 'AvailableTarget's for the @bench@ command.
224 = -- | The 'TargetSelector' matches targets but no benchmarks
225 TargetProblemNoBenchmarks TargetSelector
226 |
-- | The 'TargetSelector' refers to a component that is not a benchmark
227 TargetProblemComponentNotBenchmark PackageId ComponentName
228 |
-- | Asking to benchmark an individual file or module is not supported
229 TargetProblemIsSubComponent PackageId ComponentName SubComponentTarget
232 type BenchTargetProblem
= TargetProblem BenchProblem
234 noBenchmarksProblem
:: TargetSelector
-> TargetProblem BenchProblem
235 noBenchmarksProblem
= CustomTargetProblem
. TargetProblemNoBenchmarks
237 componentNotBenchmarkProblem
:: PackageId
-> ComponentName
-> TargetProblem BenchProblem
238 componentNotBenchmarkProblem pkgid name
=
239 CustomTargetProblem
$
240 TargetProblemComponentNotBenchmark pkgid name
242 isSubComponentProblem
245 -> SubComponentTarget
246 -> TargetProblem BenchProblem
247 isSubComponentProblem pkgid name subcomponent
=
248 CustomTargetProblem
$
249 TargetProblemIsSubComponent pkgid name subcomponent
251 reportTargetProblems
:: Verbosity
-> [BenchTargetProblem
] -> IO a
252 reportTargetProblems verbosity
=
253 dieWithException verbosity
. RenderBenchTargetProblem
. map renderBenchTargetProblem
255 renderBenchTargetProblem
:: BenchTargetProblem
-> String
256 renderBenchTargetProblem
(TargetProblemNoTargets targetSelector
) =
257 case targetSelectorFilter targetSelector
of
259 | kind
/= BenchKind
->
260 "The bench command is for running benchmarks, but the target '"
261 ++ showTargetSelector targetSelector
263 ++ renderTargetSelector targetSelector
265 _
-> renderTargetProblemNoTargets
"benchmark" targetSelector
266 renderBenchTargetProblem problem
=
267 renderTargetProblem
"benchmark" renderBenchProblem problem
269 renderBenchProblem
:: BenchProblem
-> String
270 renderBenchProblem
(TargetProblemNoBenchmarks targetSelector
) =
271 "Cannot run benchmarks for the target '"
272 ++ showTargetSelector targetSelector
273 ++ "' which refers to "
274 ++ renderTargetSelector targetSelector
276 ++ plural
(targetSelectorPluralPkgs targetSelector
) "it does" "they do"
277 ++ " not contain any benchmarks."
278 renderBenchProblem
(TargetProblemComponentNotBenchmark pkgid cname
) =
279 "The bench command is for running benchmarks, but the target '"
280 ++ showTargetSelector targetSelector
282 ++ renderTargetSelector targetSelector
283 ++ " from the package "
287 targetSelector
= TargetComponent pkgid cname WholeComponent
288 renderBenchProblem
(TargetProblemIsSubComponent pkgid cname subtarget
) =
289 "The bench command can only run benchmarks as a whole, "
290 ++ "not files or modules within them, but the target '"
291 ++ showTargetSelector targetSelector
293 ++ renderTargetSelector targetSelector
296 targetSelector
= TargetComponent pkgid cname subtarget