Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ProfiT-HPC
aggregator
Commits
af71d06a
Commit
af71d06a
authored
Oct 10, 2019
by
Azat Khuziyakhmetov
Browse files
faster attribute computation
parent
5d60482d
Changes
2
Hide whitespace changes
Inline
Side-by-side
rcm/attributes.py
View file @
af71d06a
...
@@ -13,27 +13,60 @@ def printd(*args, **kargs):
...
@@ -13,27 +13,60 @@ def printd(*args, **kargs):
def
rcmattr
(
func
):
def
rcmattr
(
func
):
'''Function decorator. Checks and sets arguments'''
'''Function decorator. Checks and sets arguments'''
def
wrapper
(
Aggr
,
*
args
,
**
kwargs
):
def
wrapper
(
*
args
,
**
kwargs
):
if
type
(
Aggr
)
!=
Aggregator
:
raise
TypeError
(
"argument of attribute should be Aggregator"
)
printd
(
" - evaluation of the attribute {:s} - "
.
format
(
func
.
__name__
))
printd
(
" - evaluation of the attribute {:s} - "
.
format
(
func
.
__name__
))
res
=
func
(
Aggr
,
*
args
,
**
kwargs
)
res
=
func
(
*
args
,
**
kwargs
)
printd
(
" - finished the attribute {:s} ({}) - "
.
format
(
func
.
__name__
,
res
))
printd
(
" - finished the attribute {:s} ({}) - "
.
format
(
func
.
__name__
,
res
))
return
res
return
res
wrapper
.
decorator
=
rcmattr
wrapper
.
__name__
=
func
.
__name__
wrapper
.
__doc__
=
func
.
__doc__
return
wrapper
return
wrapper
class
Attributes
:
class
Attributes
:
_aggr
=
None
attr_values
=
{}
def
__init__
(
self
,
Aggr
):
# init function
if
type
(
Aggr
)
!=
Aggregator
:
raise
TypeError
(
"argument for init should be Aggregator"
)
self
.
_aggr
=
Aggr
return
def
calculate_attrs
(
self
):
attr_func
=
self
.
get_attribute_funcs
()
for
func
in
attr_func
:
self
.
attr_values
[
func
.
__name__
]
=
func
()
return
self
.
attr_values
def
get_attribute_funcs
(
self
):
"""
Returns all methods with attribute decorator
"""
methods
=
[]
for
maybeDecorated
in
dir
(
self
):
cur_attr
=
self
.
__getattribute__
(
maybeDecorated
)
if
hasattr
(
cur_attr
,
'decorator'
):
if
cur_attr
.
decorator
is
rcmattr
:
methods
.
append
(
cur_attr
)
return
methods
@
rcmattr
@
rcmattr
def
cpu_usage_total_max
(
Aggr
):
def
cpu_usage_total_max
(
self
):
cpu_usage
=
0
cpu_usage
=
0
cpu_usage_sum
=
0
cpu_usage_sum
=
0
alloc_cu_sum
=
0
alloc_cu_sum
=
0
cpu_requested
=
A
ggr
.
job
.
requested_cu
cpu_requested
=
self
.
_a
ggr
.
job
.
requested_cu
for
node
in
A
ggr
.
nodes
:
for
node
in
self
.
_a
ggr
.
nodes
:
thr_cnt
=
node
.
virt_thr_core
+
node
.
phys_thr_core
thr_cnt
=
node
.
virt_thr_core
+
node
.
phys_thr_core
cpu_usage_sum
+=
node
.
proc
.
cpu_usage
cpu_usage_sum
+=
node
.
proc
.
cpu_usage
...
@@ -47,45 +80,42 @@ class Attributes:
...
@@ -47,45 +80,42 @@ class Attributes:
res
=
"NORM"
res
=
"NORM"
if
cpu_usage
<
50
and
alloc_cu_sum
<=
8
:
if
cpu_usage
<
50
and
alloc_cu_sum
<=
8
:
res
=
"LOW"
res
=
"LOW"
break
elif
cpu_usage
<
80
and
alloc_cu_sum
>
8
:
elif
cpu_usage
<
80
and
alloc_cu_sum
>
8
:
res
=
"LOW"
res
=
"LOW"
break
return
res
return
res
@
rcmattr
@
rcmattr
def
mem_usage_total
(
Aggr
):
def
mem_usage_total
(
self
):
MEM
DIFF_HIGH
=
1024
*
1024
*
1024
MEM
_LOW_BOUND
=
32
*
1024
*
1024
*
1024
# 32 GiB
mem_req_total
=
0
mem_req_total
=
0
mem_used_max
=
0
mem_used_max
=
0
for
node
in
A
ggr
.
nodes
:
for
node
in
self
.
_a
ggr
.
nodes
:
mem_per_core
=
node
.
main_mem
/
(
node
.
sockets
*
node
.
cores_per_socket
)
thr_cnt
=
node
.
virt_thr_core
+
node
.
phys_thr_core
mem_
req_total
+=
mem_per_core
*
node
.
alloc_cu
mem_
per_core
=
node
.
main_mem
/
(
node
.
sockets
*
node
.
cores_per_socket
*
thr_cnt
)
mem_req_total
+=
mem_per_core
*
node
.
alloc_cu
mem_used_max
+=
node
.
proc
.
mem_rss_max
mem_used_max
+=
node
.
proc
.
mem_rss_max
mem_ratio
=
mem_used_max
/
mem_req_total
mem_ratio
=
mem_used_max
/
mem_req_total
mem_diff
=
abs
(
mem_used_max
-
mem_req_total
)
printd
(
"mem total = {}, mem used {}, ratio {}"
.
printd
(
"mem total = {}, mem used {}, ratio {}"
.
format
(
mem_req_total
,
mem_used_max
,
mem_ratio
))
format
(
mem_req_total
,
mem_used_max
,
mem_ratio
))
res
=
"
MED
"
res
=
"
NORM
"
if
mem_
ratio
>
1
and
mem_diff
>
MEMDIFF_HIGH
:
if
mem_
used_max
>
MEM_LOW_BOUND
and
mem_ratio
>
1
:
res
=
"HIGH"
res
=
"HIGH"
elif
mem_
ratio
<
0.5
and
mem_diff
>
MEMDIFF_HIGH
:
elif
mem_
used_max
>
MEM_LOW_BOUND
and
mem_ratio
<
0.3
:
res
=
"LOW"
res
=
"LOW"
return
res
return
res
@
rcmattr
@
rcmattr
def
node_cpu_usage_max
(
Aggr
):
def
node_cpu_usage_max
(
self
):
res
=
[
"ZERO"
,
"LOW"
,
"NORM"
,
"HIGH"
]
res
=
[
"ZERO"
,
"LOW"
,
"NORM"
,
"HIGH"
]
max_res
=
res
.
index
(
"ZERO"
)
max_res
=
res
.
index
(
"ZERO"
)
for
node
in
A
ggr
.
nodes
:
for
node
in
self
.
_a
ggr
.
nodes
:
thr_cnt
=
node
.
virt_thr_core
+
node
.
phys_thr_core
thr_cnt
=
node
.
virt_thr_core
+
node
.
phys_thr_core
node_proc_ratio
=
node
.
proc
.
cpu_usage
/
(
node
.
alloc_cu
/
thr_cnt
)
node_proc_ratio
=
node
.
proc
.
cpu_usage
/
(
node
.
alloc_cu
/
thr_cnt
)
...
@@ -107,10 +137,11 @@ class Attributes:
...
@@ -107,10 +137,11 @@ class Attributes:
return
res
[
max_res
]
return
res
[
max_res
]
def
node_cpu_usage_min
(
Aggr
):
@
rcmattr
def
node_cpu_usage_min
(
self
):
res
=
[
"ZERO"
,
"LOW"
,
"NORM"
,
"HIGH"
]
res
=
[
"ZERO"
,
"LOW"
,
"NORM"
,
"HIGH"
]
min_res
=
res
.
index
(
"HIGH"
)
min_res
=
res
.
index
(
"HIGH"
)
for
node
in
A
ggr
.
nodes
:
for
node
in
self
.
_a
ggr
.
nodes
:
thr_cnt
=
node
.
virt_thr_core
+
node
.
phys_thr_core
thr_cnt
=
node
.
virt_thr_core
+
node
.
phys_thr_core
node_proc_ratio
=
node
.
proc
.
cpu_usage
/
(
node
.
alloc_cu
/
thr_cnt
)
node_proc_ratio
=
node
.
proc
.
cpu_usage
/
(
node
.
alloc_cu
/
thr_cnt
)
...
@@ -128,20 +159,20 @@ class Attributes:
...
@@ -128,20 +159,20 @@ class Attributes:
elif
node_proc_ratio
>
80
and
node
.
alloc_cu
>
8
:
elif
node_proc_ratio
>
80
and
node
.
alloc_cu
>
8
:
node_res
=
res
.
index
(
"NORM"
)
node_res
=
res
.
index
(
"NORM"
)
min_res
=
min
(
node_res
,
m
ax
_res
)
min_res
=
min
(
node_res
,
m
in
_res
)
return
res
[
min_res
]
return
res
[
min_res
]
@
rcmattr
@
rcmattr
def
req_walltime
(
Aggr
):
def
req_walltime
(
self
):
MIN_R
=
4
MIN_R
=
4
SHIFT_R
=
6
SHIFT_R
=
6
rtime
=
A
ggr
.
job
.
run_time
rtime
=
self
.
_a
ggr
.
job
.
run_time
utime
=
A
ggr
.
job
.
requested_time
utime
=
self
.
_a
ggr
.
job
.
requested_time
res
=
"UNKNOWN"
res
=
"UNKNOWN"
if
rtime
>
MIN_R
&&
utime
<
rtime
/
2
&&
utime
<
(
rtime
-
SHIFT_R
):
if
rtime
>
MIN_R
and
utime
<
rtime
/
2
and
utime
<
(
rtime
-
SHIFT_R
):
res
=
"HIGH"
res
=
"HIGH"
else
:
else
:
res
=
"NORM"
res
=
"NORM"
...
@@ -149,9 +180,9 @@ class Attributes:
...
@@ -149,9 +180,9 @@ class Attributes:
return
res
return
res
@
rcmattr
@
rcmattr
def
overloaded_node_exists
(
Aggr
):
def
overloaded_node_exists
(
self
):
exists
=
False
exists
=
False
for
node
in
A
ggr
.
nodes
:
for
node
in
self
.
_a
ggr
.
nodes
:
if
node
.
proc
.
cpu_usage
>
90
:
if
node
.
proc
.
cpu_usage
>
90
:
continue
continue
...
@@ -162,8 +193,8 @@ class Attributes:
...
@@ -162,8 +193,8 @@ class Attributes:
return
exists
return
exists
@
rcmattr
@
rcmattr
def
job_nodes_amount
(
Aggr
):
def
job_nodes_amount
(
self
):
nnodes
=
count
(
A
ggr
.
nodes
)
nnodes
=
len
(
self
.
_a
ggr
.
nodes
)
res
=
"ERR"
res
=
"ERR"
if
nnodes
==
1
:
if
nnodes
==
1
:
...
@@ -172,3 +203,13 @@ class Attributes:
...
@@ -172,3 +203,13 @@ class Attributes:
res
=
"MULT"
res
=
"MULT"
return
res
return
res
@
rcmattr
def
mem_swap_used
(
self
):
swap_used
=
False
for
node
in
self
.
_aggr
.
nodes
:
if
node
.
proc
.
mem_swap_max
>
0
:
swap_used
=
True
return
swap_used
rcm/rcm.py
View file @
af71d06a
from
.rules
import
RULES
from
.rules
import
RULES
from
rcm
import
attributes
from
rcm
import
attributes
attributes
.
DEBUG
=
Tru
e
attributes
.
DEBUG
=
Fals
e
def
attributes_match
(
attrs
,
Aggr
):
def
attributes_match
(
attrs
,
values
):
matches
=
True
matches
=
True
for
rule_attr
,
attr_value
in
attrs
.
items
():
for
attr_name
,
attr_expected
in
attrs
.
items
():
try
:
if
attr_name
not
in
values
:
attr_func
=
getattr
(
attributes
.
Attributes
,
rule_attr
)
raise
ValueError
(
"Attribute is not found"
,
attr_name
)
except
AttributeError
:
raise
AttributeError
(
"there is no attribute "
+
rule_attr
)
attr_value
=
values
[
attr_name
]
expected_vals
=
[]
expected_vals
=
[]
if
isinstance
(
attr_value
,
list
):
expected_vals
.
extend
(
attr_value
)
if
isinstance
(
attr_expected
,
list
):
expected_vals
.
extend
(
attr_expected
)
else
:
else
:
expected_vals
.
append
(
attr_
value
)
expected_vals
.
append
(
attr_
expected
)
if
attr_
func
(
Aggr
)
not
in
expected_vals
:
if
attr_
value
not
in
expected_vals
:
matches
=
False
matches
=
False
break
break
...
@@ -25,9 +25,13 @@ def attributes_match(attrs, Aggr):
...
@@ -25,9 +25,13 @@ def attributes_match(attrs, Aggr):
def
get_recommendations
(
Aggr
):
def
get_recommendations
(
Aggr
):
Attrs
=
attributes
.
Attributes
(
Aggr
)
attr_values
=
Attrs
.
calculate_attrs
()
rcms
=
[]
rcms
=
[]
for
rule
in
RULES
:
for
rule
in
RULES
:
if
attributes_match
(
rule
[
"attrs"
],
Aggr
):
if
attributes_match
(
rule
[
"attrs"
],
attr_values
):
rcms
.
append
(
rule
[
"msg"
])
rcms
.
append
(
rule
[
"msg"
])
return
rcms
return
rcms
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment