Revision 375969eb htools/Ganeti/HTools/Program/Hspace.hs

b/htools/Ganeti/HTools/Program/Hspace.hs
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

Also available in: Unified diff