Skip to content
aglitke edited this page Jan 10, 2011 · 25 revisions

MOM is designed to enable dynamic tuning of a KVM host in response to statistics that are continuously collected from the host and its running guests.
This tuning policy is described using a LISP-like mini-language as described here.

Comments

Comments are expressed with the ‘#’ symbol. When ‘#’ is encountered, it and all remaining characters on the line are ignored.

Example:

Code Result

# This is a full line comment
(+ 1 1) # This is a partial-line comment

 
2

Strings

Strings are created by placing text between double-quotes. Variables can be assigned string values. Sting concatenation and repetition can be performed by using the ‘+’ and ‘*’ operators.

Example:

Code Result

"foo" "bar"
# Operators on strings have the same effect as for Python
(+ "Hello " "World!")
(+ (* 3 "Hey ") "!")
# Multi-line string
"multi-
line"

foo
bar
Hello World!
Hey Hey Hey !

multi-
line

Numbers

Numbers can be expressed as a floating point, integer, integer in scientific notation, hexidecimal, and octal. However, numerical results are always base 10 integers or floats. The basic arithmetic operators +, -, *, /, <<. and >> are supported and have their usual meanings.

Example:

Code Result

10
00                  # Octal
.3                  # The leading 0 on a float is not required
(* 0 1)
(+ 1 2)
(/ 11 2)            # Integer division
(/ 11 2.0)          # Floating point division
(* 3 6)
(- 1 9)             # Negative result
(* (- 8 6) 9)
(>> (<< 1 4) 2)
(+ 0xFF 0x1)        # Hex numbers
(* 011 02)
(+ 0xa 10)          # Numeric type mixing
(+ 10.0e3 100e-2)   # Scientific notation for integers and floats

10
0
0.3
0
3
5
5.5
18
-8
18
4
256
18
20
10001.0

Logic and Comparison

The policy language supports 3 logic operators: and, or, not. These operators use short-circuit logic behavior equivalent to the Python language. See the example below for more details. In addition to the logic operators, comparisons are supported using: <, >, <=, >=, ==, and !=.

Example:

Code Result

(and 1 "")          # The values 0 and "" evaluate to False
                    # Everything else evaluates to True
(and 0 1)           # 'and' returns the first False value
(and 1 2)           # if all values are True, the last value is returned
(or "" 17)          # 'or' returns the first True value encountered
(or "" "")          # if all values are False, 'or' returns the last one
(not "")
(not -0)

(< 5 4)
(> 1 0)
(<= 10 10)
(>= 2 (/ 10 2))
(== (+ 1 2) (/ 9 3))
(!= "foo" "foo")
(== 0x0 0)

""

0
2
17
""
True
True
 
False
True
True
False
True
False
True

Macros

Macros enhance readability of a policy by grouping related and reusable statements into a single named block. While very similar to functions, macros have at least one key practical difference. They cannot be used for recursion. Attempting to call a macro from within itself will trigger an error. However, nesting of macros is allowed. Macro definitions are created with the def statement. Names must begin with a letter and may contain letters, digits, underscores, dashes, and periods. Once created, they are called like functions.

Example:

Code Result

(def foo () 10)
(def bar (a)
    (* 2 a))
(/ (foo) (bar 5))
(def baz (b)
    (- 2 (bar b)))
(baz 12)
(def foo (a) {
    (def bar (b) (+ b 1))   # Nested function
    (bar a)
})
(foo 9)

foo
 
bar
1
 
baz
-22



foo
10

Variables and Scope

Variables are defined with the defvar statement. Names must begin with a letter and may contain letters, digits, underscores, dashes, and periods. It is an error to reference an undefined variable. The set statement can be used to set the value of a defined variable. The execution of a policy begins with a global variable scope. A new local scope is created during the execution of a macro. Accessing variables outside the current scope can be done with no special syntax. After completion of a macro, the local scope is retired.

The let Statement

The let statement creates a new scope that contains a specified set of variables and values.

Example:

Code Result

(defvar foo "bar")
(defvar a 5)
(defvar b 6)
(+ a b)
(set a 8)
(+ a b)
(* foo 2)
(defvar e3 7)
(+ 1 e3)        # Make sure e3 is not mistaken for scientific notation

(def baz (a) (+ 2 a))
(defvar a 2)
(let ((a 1) (b 2)) (baz a))
a                               # Value of 'a' unaffected by let

(defvar a 10)
(def baz (b) (set a b))         # set affects the global 'a'
(baz 2)
a
(def baz (b) (defvar a b))      # defvar creates a local 'a'
(baz 4)
a
(set a 5)
(let ((a 4)) a)                 # let creates a local 'a'
a
(if (== a 5) (defvar a 4) 0)    # if does not create a new scope
a

bar
5
6
11
8
14
barbar
7
8
 
baz
2
3
2
 
10
baz
2
2
baz
4
2
5
4
5
4
4

The if Statement

Conditional branching is implemented by using the if statement. It always has the form (if cond-expr true-stmt false-stmt). In other words, the else clause is required. If-elsif-else style statements can be constructed with nesting.

Example:

Code Result

(defvar a 1)
(defvar b 0)
(def f (cond)
    (if cond
        "yes"
        "no"))
(if a 4 3)
(if b 1 0)
(f (> 2 1))

1
0
 
 
 
f
4
0
yes

Compound Statements

Compound statements can be created by using braces ‘{’ ‘}’. They are most useful for macro bodies, if statements, and let statements. Nesting is allowed. Compound statements always evaluate to the value of the last statement they contain. Therefore, a macro can be made to “return” a value by writing the desired return value or expression as the last statement in the macro body.

Example:

Code Result

{ 10 4 }                # A multi-statement evaluates to the last value
(def f (a b) {          # Use them for function bodies
    (defvar c (+ a b))
    (set c (+ 1 c))
    c
})
(f 4 5)

(defvar q 11)
(let ((q 2) (r 3)) {            # Use them for let statements
    q r
    (- r q)
})

(if (== q 11) {                 # Use them in if statements
    "q maintains proper scope"
    (set q 12)
} {
    "oops, q has the wrong value"
})
(- q 10)

4
 
 
 
 
f
10
 
11
 
 
 
1
 
 
 
 
 
 
12
2

Entities

Entities provide the means by which a policy interacts with the outside world. These special purpose objects appear in the global scope of an executing policy to provide access to: host and guest properties, real-time statistics, and an interface to modify system configuration.

The Input Entities: Host and Guests

MOM maintains an Entity for the host and each running guest on the system. These Entities are populated with static information (properties) such as the guest name and UUID, continuously updated data (statistics) such as current memory usage, and policy modifiable variables. The specific information available to the policy will depend on the Collectors that are in use. See Collectors for specifics.

Guest properties
  • id – A MOM-assigned unique id for each guest. This id will change each time the guest is started
  • uuid – The libvirt-assigned UUID of the guest. This value will remain constant across guest life-cycles
  • name – The libvirt-assigned guest name. This value is also persistent.
  • pid – The pid of the host qemu process. This value is discovered using ps and is not 100% guaranteed.
  • ip – The IP address of the guest as indicated by a configured name-to-ip helper script (see GuestNetworkDaemon in Collectors for details).
Input Entity Methods

The host and guest Entities provide four basic methods used for accessing properties, statistics and variables:

  • Prop – Get the value of the named property
  • StatAvg – Return the average value of the named statistic over all stored historical samples. By default, the 10 most recent samples are used for this calculation. To access the most recent sample, access the statistic directly by name (see the examples).
  • SetVar – Set an Entity variable of the given name to the given value.
  • GetVar – Get the value of a previously set Entity variable.

Controller Entities

Control()

The with Guests Construct

Entity Examples:

Code Result

# Fill in examples

# Fill in results

External Functions

  • (abs x): Return the absolute value of ‘x’