Revision 375969eb

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
b/man/hspace.rst
10 10
--------
11 11

  
12 12
**hspace** {backend options...} [algorithm options...] [request options...]
13
[ -p [*fields*] ] [-v... | -q]
13
[output options...] [-v... | -q]
14 14

  
15 15
**hspace** --version
16 16

  
......
35 35
**[--vcpus** *vcpus* **]**
36 36
**[--tiered-alloc** *spec* **]**
37 37

  
38
Output options:
39

  
40
**[--machine-readable**[=*CHOICE*] **]**
41
**[-p**[*fields*]**]**
42

  
38 43

  
39 44
DESCRIPTION
40 45
-----------
......
48 53
allocation. It uses the exact same allocation algorithm as the hail
49 54
iallocator plugin in *allocate* mode.
50 55

  
51
The output of the program is designed to interpreted as a shell
52
fragment (or parsed as a *key=value* file). Options which extend the
53
output (e.g. -p, -v) will output the additional information on stderr
54
(such that the stdout is still parseable).
56
The output of the program is designed either for human consumption (the
57
default) or, when enabled with the ``--machine-readable`` option
58
(described further below), for machine consumption. In the latter case,
59
it is intended to interpreted as a shell fragment (or parsed as a
60
*key=value* file). Options which extend the output (e.g. -p, -v) will
61
output the additional information on stderr (such that the stdout is
62
still parseable).
55 63

  
56
The following keys are available in the output of the script (all
57
prefixed with *HTS_*):
64
The following keys are available in the machine-readable output of the
65
script (all prefixed with *HTS_*):
58 66

  
59 67
SPEC_MEM, SPEC_DSK, SPEC_CPU, SPEC_RQN, SPEC_DISK_TEMPLATE
60 68
  These represent the specifications of the instance model used for
61 69
  allocation (the memory, disk, cpu, requested nodes, disk template).
62 70

  
63
TSPEC_INI_MEM, TSPEC_INI_DSK, TSPEC_INI_CPU
71
TSPEC_INI_MEM, TSPEC_INI_DSK, TSPEC_INI_CPU, ...
64 72
  Only defined when the tiered mode allocation is enabled, these are
65 73
  similar to the above specifications but show the initial starting spec
66 74
  for tiered allocation.
......
185 193
metrics will be also displayed with a TRL_ prefix, and denote the
186 194
cluster status at the end of the tiered allocation run.
187 195

  
196
The human output format should be self-explanatory, so it is not
197
described further.
198

  
188 199
OPTIONS
189 200
-------
190 201

  
......
308 319
  the instance count for these two modes are not related one to
309 320
  another.
310 321

  
322
--machines-readable[=*choice*]
323
  By default, the output of the program is in "human-readable" format,
324
  i.e. text descriptions. By passing this flag you can either enable
325
  (``--machine-readable`` or ``--machine-readable=yes``) or explicitly
326
  disable (``--machine-readable=no``) the machine readable format
327
  described above.
328

  
311 329
-v, --verbose
312 330
  Increase the output verbosity. Each usage of this option will
313 331
  increase the verbosity (currently more than 2 doesn't make sense)

Also available in: Unified diff