63 |
63 |
, oIMem
|
64 |
64 |
, oIDisk
|
65 |
65 |
, oIVcpus
|
|
66 |
, oMachineReadable
|
66 |
67 |
, oMaxCpu
|
67 |
68 |
, oMinDisk
|
68 |
69 |
, oTieredSpec
|
... | ... | |
77 |
78 |
| PFinal
|
78 |
79 |
| PTiered
|
79 |
80 |
|
|
81 |
-- | The kind of instance spec we print.
|
|
82 |
data SpecType = SpecNormal
|
|
83 |
| SpecTiered
|
|
84 |
|
|
85 |
-- | What we prefix a spec with.
|
|
86 |
specPrefix :: SpecType -> String
|
|
87 |
specPrefix SpecNormal = "SPEC"
|
|
88 |
specPrefix SpecTiered = "TSPEC_INI"
|
|
89 |
|
|
90 |
-- | The description of a spec.
|
|
91 |
specDescription :: SpecType -> String
|
|
92 |
specDescription SpecNormal = "Normal (fixed-size)"
|
|
93 |
specDescription SpecTiered = "Tiered (initial size)"
|
|
94 |
|
|
95 |
-- | Efficiency generic function.
|
|
96 |
effFn :: (Cluster.CStats -> Integer)
|
|
97 |
-> (Cluster.CStats -> Double)
|
|
98 |
-> (Cluster.CStats -> Double)
|
|
99 |
effFn fi ft cs = fromIntegral (fi cs) / ft cs
|
|
100 |
|
|
101 |
-- | Memory efficiency.
|
|
102 |
memEff :: Cluster.CStats -> Double
|
|
103 |
memEff = effFn Cluster.csImem Cluster.csTmem
|
|
104 |
|
|
105 |
-- | Disk efficiency.
|
|
106 |
dskEff :: Cluster.CStats -> Double
|
|
107 |
dskEff = effFn Cluster.csIdsk Cluster.csTdsk
|
|
108 |
|
|
109 |
-- | Cpu efficiency.
|
|
110 |
cpuEff :: Cluster.CStats -> Double
|
|
111 |
cpuEff = effFn Cluster.csIcpu (fromIntegral . Cluster.csVcpu)
|
|
112 |
|
80 |
113 |
statsData :: [(String, Cluster.CStats -> String)]
|
81 |
114 |
statsData = [ ("SCORE", printf "%.8f" . Cluster.csScore)
|
82 |
115 |
, ("INST_CNT", printf "%d" . Cluster.csNinst)
|
... | ... | |
87 |
120 |
, ("MEM_INST", printf "%d" . Cluster.csImem)
|
88 |
121 |
, ("MEM_OVERHEAD",
|
89 |
122 |
\cs -> printf "%d" (Cluster.csXmem cs + Cluster.csNmem cs))
|
90 |
|
, ("MEM_EFF",
|
91 |
|
\cs -> printf "%.8f" (fromIntegral (Cluster.csImem cs) /
|
92 |
|
Cluster.csTmem cs))
|
|
123 |
, ("MEM_EFF", printf "%.8f" . memEff)
|
93 |
124 |
, ("DSK_FREE", printf "%d" . Cluster.csFdsk)
|
94 |
125 |
, ("DSK_AVAIL", printf "%d". Cluster.csAdsk)
|
95 |
126 |
, ("DSK_RESVD",
|
96 |
127 |
\cs -> printf "%d" (Cluster.csFdsk cs - Cluster.csAdsk cs))
|
97 |
128 |
, ("DSK_INST", printf "%d" . Cluster.csIdsk)
|
98 |
|
, ("DSK_EFF",
|
99 |
|
\cs -> printf "%.8f" (fromIntegral (Cluster.csIdsk cs) /
|
100 |
|
Cluster.csTdsk cs))
|
|
129 |
, ("DSK_EFF", printf "%.8f" . dskEff)
|
101 |
130 |
, ("CPU_INST", printf "%d" . Cluster.csIcpu)
|
102 |
|
, ("CPU_EFF",
|
103 |
|
\cs -> printf "%.8f" (fromIntegral (Cluster.csIcpu cs) /
|
104 |
|
Cluster.csTcpu cs))
|
|
131 |
, ("CPU_EFF", printf "%.8f" . cpuEff)
|
105 |
132 |
, ("MNODE_MEM_AVAIL", printf "%d" . Cluster.csMmem)
|
106 |
133 |
, ("MNODE_DSK_AVAIL", printf "%d" . Cluster.csMdsk)
|
107 |
134 |
]
|
... | ... | |
128 |
155 |
PFinal -> "FIN"
|
129 |
156 |
PTiered -> "TRL"
|
130 |
157 |
|
131 |
|
-- | Print final stats and related metrics
|
132 |
|
printResults :: Node.List -> Int -> Int -> [(FailMode, Int)] -> IO ()
|
133 |
|
printResults fin_nl num_instances allocs sreason = do
|
|
158 |
-- | Print final stats and related metrics.
|
|
159 |
printResults :: Bool -> Node.List -> Node.List -> Int -> Int
|
|
160 |
-> [(FailMode, Int)] -> IO ()
|
|
161 |
printResults True _ fin_nl num_instances allocs sreason = do
|
134 |
162 |
let fin_stats = Cluster.totalResources fin_nl
|
135 |
163 |
fin_instances = num_instances + allocs
|
136 |
164 |
|
... | ... | |
150 |
178 |
]
|
151 |
179 |
printKeys $ map (\(x, y) -> (printf "ALLOC_%s_CNT" (show x),
|
152 |
180 |
printf "%d" y)) sreason
|
|
181 |
|
|
182 |
printResults False ini_nl fin_nl _ allocs sreason = do
|
|
183 |
putStrLn "Normal (fixed-size) allocation results:"
|
|
184 |
printf " - %3d instances allocated\n" allocs :: IO ()
|
|
185 |
printf " - most likely failure reason: %s\n" $ failureReason sreason::IO ()
|
|
186 |
printClusterScores ini_nl fin_nl
|
|
187 |
printClusterEff (Cluster.totalResources fin_nl)
|
|
188 |
|
|
189 |
-- | Prints the final @OK@ marker in machine readable output.
|
|
190 |
printFinal :: Bool -> IO ()
|
|
191 |
printFinal True =
|
153 |
192 |
-- this should be the final entry
|
154 |
193 |
printKeys [("OK", "1")]
|
155 |
194 |
|
|
195 |
printFinal False = return ()
|
|
196 |
|
156 |
197 |
-- | Compute the tiered spec counts from a list of allocated
|
157 |
198 |
-- instances.
|
158 |
199 |
tieredSpecMap :: [Instance.Instance]
|
... | ... | |
222 |
263 |
-- strings, whereas the rest are numeric
|
223 |
264 |
[False, False, False, True, True, True]
|
224 |
265 |
|
|
266 |
-- | Formats nicely a list of resources.
|
|
267 |
formatResources :: a -> [(String, (a->String))] -> String
|
|
268 |
formatResources res =
|
|
269 |
intercalate ", " . map (\(a, fn) -> a ++ " " ++ fn res)
|
|
270 |
|
|
271 |
-- | Print the cluster resources.
|
|
272 |
printCluster :: Bool -> Cluster.CStats -> Int -> IO ()
|
|
273 |
printCluster True ini_stats node_count = do
|
|
274 |
printKeys $ map (\(a, fn) -> ("CLUSTER_" ++ a, fn ini_stats)) clusterData
|
|
275 |
printKeys [("CLUSTER_NODES", printf "%d" node_count)]
|
|
276 |
printKeys $ printStats PInitial ini_stats
|
|
277 |
|
|
278 |
printCluster False ini_stats node_count = do
|
|
279 |
printf "The cluster has %d nodes and the following resources:\n %s.\n"
|
|
280 |
node_count (formatResources ini_stats clusterData)::IO ()
|
|
281 |
printf "There are %s initial instances on the cluster.\n"
|
|
282 |
(if inst_count > 0 then show inst_count else "no" )
|
|
283 |
where inst_count = Cluster.csNinst ini_stats
|
|
284 |
|
|
285 |
-- | Prints the normal instance spec.
|
|
286 |
printISpec :: Bool -> RSpec -> SpecType -> DiskTemplate -> IO ()
|
|
287 |
printISpec True ispec spec disk_template = do
|
|
288 |
printKeys $ map (\(a, fn) -> (prefix ++ "_" ++ a, fn ispec)) specData
|
|
289 |
printKeys [ (prefix ++ "_RQN", printf "%d" req_nodes) ]
|
|
290 |
printKeys [ (prefix ++ "_DISK_TEMPLATE", dtToString disk_template) ]
|
|
291 |
where req_nodes = Instance.requiredNodes disk_template
|
|
292 |
prefix = specPrefix spec
|
|
293 |
|
|
294 |
printISpec False ispec spec disk_template = do
|
|
295 |
printf "%s instance spec is:\n %s, using disk\
|
|
296 |
\ template '%s'.\n"
|
|
297 |
(specDescription spec)
|
|
298 |
(formatResources ispec specData) (dtToString disk_template)
|
|
299 |
|
|
300 |
-- | Prints the tiered results.
|
|
301 |
printTiered :: Bool -> [(RSpec, Int)] -> Double
|
|
302 |
-> Node.List -> Node.List -> [(FailMode, Int)] -> IO ()
|
|
303 |
printTiered True spec_map m_cpu nl trl_nl _ = do
|
|
304 |
printKeys $ printStats PTiered (Cluster.totalResources trl_nl)
|
|
305 |
printKeys [("TSPEC", intercalate " " (formatSpecMap spec_map))]
|
|
306 |
printAllocationStats m_cpu nl trl_nl
|
|
307 |
|
|
308 |
printTiered False spec_map _ ini_nl fin_nl sreason = do
|
|
309 |
_ <- printf "Tiered allocation results:\n"
|
|
310 |
mapM_ (\(ispec, cnt) ->
|
|
311 |
printf " - %3d instances of spec %s\n" cnt
|
|
312 |
(formatResources ispec specData)) spec_map
|
|
313 |
printf " - most likely failure reason: %s\n" $ failureReason sreason::IO ()
|
|
314 |
printClusterScores ini_nl fin_nl
|
|
315 |
printClusterEff (Cluster.totalResources fin_nl)
|
|
316 |
|
|
317 |
printClusterScores :: Node.List -> Node.List -> IO ()
|
|
318 |
printClusterScores ini_nl fin_nl = do
|
|
319 |
printf " - initial cluster score: %.8f\n" $ Cluster.compCV ini_nl::IO ()
|
|
320 |
printf " - final cluster score: %.8f\n" $ Cluster.compCV fin_nl
|
|
321 |
|
|
322 |
printClusterEff :: Cluster.CStats -> IO ()
|
|
323 |
printClusterEff cs =
|
|
324 |
mapM_ (\(s, fn) ->
|
|
325 |
printf " - %s usage efficiency: %5.2f%%\n" s (fn cs * 100))
|
|
326 |
[("memory", memEff),
|
|
327 |
(" disk", dskEff),
|
|
328 |
(" vcpu", cpuEff)]
|
|
329 |
|
|
330 |
-- | Computes the most likely failure reason.
|
|
331 |
failureReason :: [(FailMode, Int)] -> String
|
|
332 |
failureReason = show . fst . head
|
|
333 |
|
|
334 |
-- | Sorts the failure reasons.
|
|
335 |
sortReasons :: [(FailMode, Int)] -> [(FailMode, Int)]
|
|
336 |
sortReasons = reverse . sortBy (comparing snd)
|
|
337 |
|
225 |
338 |
-- | Main function.
|
226 |
339 |
main :: IO ()
|
227 |
340 |
main = do
|
... | ... | |
237 |
350 |
shownodes = optShowNodes opts
|
238 |
351 |
disk_template = optDiskTemplate opts
|
239 |
352 |
req_nodes = Instance.requiredNodes disk_template
|
|
353 |
machine_r = optMachineReadable opts
|
240 |
354 |
|
241 |
355 |
(ClusterData gl fixed_nl il ctags) <- loadExternalData opts
|
242 |
356 |
|
243 |
|
printKeys $ map (\(a, fn) -> ("SPEC_" ++ a, fn ispec)) specData
|
244 |
|
printKeys [ ("SPEC_RQN", printf "%d" req_nodes) ]
|
245 |
|
printKeys [ ("SPEC_DISK_TEMPLATE", dtToString disk_template) ]
|
246 |
|
|
247 |
357 |
let num_instances = length $ Container.elems il
|
248 |
358 |
|
249 |
359 |
let offline_passed = optOffline opts
|
... | ... | |
289 |
399 |
hPrintf stderr "Initial coefficients: overall %.8f, %s\n"
|
290 |
400 |
ini_cv (Cluster.printStats nl)
|
291 |
401 |
|
292 |
|
printKeys $ map (\(a, fn) -> ("CLUSTER_" ++ a, fn ini_stats)) clusterData
|
293 |
|
printKeys [("CLUSTER_NODES", printf "%d" (length all_nodes))]
|
294 |
|
printKeys $ printStats PInitial ini_stats
|
|
402 |
printCluster machine_r ini_stats (length all_nodes)
|
|
403 |
|
|
404 |
printISpec machine_r ispec SpecNormal disk_template
|
295 |
405 |
|
296 |
406 |
let bad_nodes = fst $ Cluster.computeBadItems nl il
|
297 |
407 |
stop_allocation = length bad_nodes > 0
|
... | ... | |
316 |
426 |
(case optTieredSpec opts of
|
317 |
427 |
Nothing -> return ()
|
318 |
428 |
Just tspec -> do
|
319 |
|
(_, trl_nl, trl_il, trl_ixes, _) <-
|
|
429 |
(treason, trl_nl, trl_il, trl_ixes, _) <-
|
320 |
430 |
if stop_allocation
|
321 |
431 |
then return result_noalloc
|
322 |
432 |
else exitifbad (Cluster.tieredAlloc nl il Nothing (iofspec tspec)
|
323 |
433 |
allocnodes [] [])
|
324 |
434 |
let spec_map' = tieredSpecMap trl_ixes
|
|
435 |
treason' = sortReasons treason
|
325 |
436 |
|
326 |
437 |
printAllocationMap verbose "Tiered allocation map" trl_nl trl_ixes
|
327 |
438 |
|
... | ... | |
331 |
442 |
maybeSaveData (optSaveCluster opts) "tiered" "after tiered allocation"
|
332 |
443 |
(ClusterData gl trl_nl trl_il ctags)
|
333 |
444 |
|
334 |
|
printKeys $ map (\(a, fn) -> ("TSPEC_INI_" ++ a, fn tspec)) specData
|
335 |
|
printKeys $ printStats PTiered (Cluster.totalResources trl_nl)
|
336 |
|
printKeys [("TSPEC", intercalate " " (formatSpecMap spec_map'))]
|
337 |
|
printAllocationStats m_cpu nl trl_nl)
|
|
445 |
printISpec machine_r tspec SpecTiered disk_template
|
|
446 |
|
|
447 |
printTiered machine_r spec_map' m_cpu nl trl_nl treason'
|
|
448 |
)
|
338 |
449 |
|
339 |
450 |
-- Run the standard (avg-mode) allocation
|
340 |
451 |
|
... | ... | |
345 |
456 |
reqinst allocnodes [] [])
|
346 |
457 |
|
347 |
458 |
let allocs = length ixes
|
348 |
|
sreason = reverse $ sortBy (comparing snd) ereason
|
|
459 |
sreason = sortReasons ereason
|
349 |
460 |
|
350 |
461 |
printAllocationMap verbose "Standard allocation map" fin_nl ixes
|
351 |
462 |
|
... | ... | |
354 |
465 |
maybeSaveData (optSaveCluster opts) "alloc" "after standard allocation"
|
355 |
466 |
(ClusterData gl fin_nl fin_il ctags)
|
356 |
467 |
|
357 |
|
printResults fin_nl num_instances allocs sreason
|
|
468 |
printResults machine_r nl fin_nl num_instances allocs sreason
|
|
469 |
|
|
470 |
printFinal machine_r
|