Skip to content

Commit

Permalink
Merge branch 'release_23.2' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
mvdbeek committed Dec 19, 2023
2 parents 698a0b4 + 3a2e673 commit 038d31e
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
id="change-dbkey-of-selected-content"
title="Change Database/Build?"
title-tag="h2"
body-class="modal-with-selector"
@ok="changeDbkeyOfSelected">
<p v-localize>Select a new Database/Build for {{ numSelected }} items:</p>
<DbKeyProvider v-slot="{ item: dbkeys, loading: loadingDbKeys }">
Expand All @@ -99,14 +100,14 @@
:loading="loadingDbKeys"
:items="dbkeys"
:current-item-id="selectedDbKey"
class="mb-5 pb-5"
@update:selected-item="onSelectedDbKey" />
</DbKeyProvider>
</b-modal>
<b-modal
id="change-datatype-of-selected-content"
title="Change data type?"
title-tag="h2"
body-class="modal-with-selector"
:ok-disabled="selectedDatatype == null"
@ok="changeDatatypeOfSelected">
<p v-localize>Select a new data type for {{ numSelected }} items:</p>
Expand All @@ -116,7 +117,6 @@
:loading="loadingDatatypes"
:items="datatypes"
:current-item-id="selectedDatatype"
class="mb-5 pb-5"
@update:selected-item="onSelectedDatatype" />
</DatatypesProvider>
</b-modal>
Expand Down Expand Up @@ -347,3 +347,9 @@ export default {
},
};
</script>

<style>
.modal-with-selector {
overflow: initial;
}
</style>
11 changes: 1 addition & 10 deletions client/src/components/Panels/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,22 +158,13 @@ export function getValidToolsInCurrentView(
isWorkflowPanel = false,
excludedSectionIds: string[] = []
) {
const addedToolTexts: string[] = [];
const toolEntries = Object.entries(toolsById).filter(([, tool]) => {
// filter out duplicate tools (different ids, same exact name+description)
// related ticket: https://github.com/galaxyproject/galaxy/issues/16145
const toolText = tool.name + tool.description;
if (addedToolTexts.includes(toolText)) {
return false;
} else {
addedToolTexts.push(toolText);
}
// filter on non-hidden, non-disabled, and workflow compatibile (based on props.workflow)
return (
!tool.hidden &&
tool.disabled !== true &&
!(isWorkflowPanel && !tool.is_workflow_compatible) &&
!excludedSectionIds.includes(tool.panel_section_id || "")
!excludedSectionIds.includes(tool.panel_section_id)
);
});
return Object.fromEntries(toolEntries);
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Upload/UploadModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,6 @@ defineExpose({
.upload-dialog-body {
height: 500px;
overflow: hidden;
overflow: initial;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@
<div class="mb-3 workflow-invocation-state-component">
<div v-if="invocationAndJobTerminal">
<span>
<b-button v-b-tooltip.hover size="sm" class="invocation-report-link" :href="invocationLink">
<b-button
v-b-tooltip.hover
:title="invocationStateSuccess ? reportTooltip : disabledReportTooltip"
:disabled="!invocationStateSuccess"
size="sm"
class="invocation-report-link"
:href="invocationLink">
View Report
</b-button>
<b-button
v-b-tooltip.hover
:title="invocationStateSuccess ? generatePdfTooltip : disabledReportTooltip"
:disabled="!invocationStateSuccess"
size="sm"
class="invocation-pdf-link"
:href="invocationPdfLink"
Expand Down Expand Up @@ -109,6 +117,8 @@ export default {
return {
stepStatesInterval: null,
jobStatesInterval: null,
reportTooltip: "View report for this workflow invocation",
generatePdfTooltip: "Generate PDF report for this workflow invocation",
};
},
computed: {
Expand All @@ -126,6 +136,28 @@ export default {
invocationState: function () {
return this.invocation?.state || "new";
},
invocationStateSuccess: function () {
return this.invocationState == "scheduled" && this.runningCount === 0 && this.invocationAndJobTerminal;
},
disabledReportTooltip: function () {
const state = this.invocationState;
const runCount = this.runningCount;
if (this.invocationState != "scheduled") {
return (
"This workflow is not currently scheduled. The current state is ",
state,
". Once the workflow is fully scheduled and jobs have complete this option will become available."
);
} else if (runCount != 0) {
return (
"The workflow invocation still contains ",
runCount,
" running job(s). Once these jobs have completed this option will become available. "
);
} else {
return "Steps for this workflow are still running. A report will be available once complete.";
}
},
stepCount: function () {
return this.invocation?.steps.length;
},
Expand Down
2 changes: 1 addition & 1 deletion client/src/stores/toolStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface Tool {
link: string;
min_width: number;
target: string;
panel_section_id: string | null;
panel_section_id: string;
panel_section_name: string | null;
form_style: string;
disabled?: boolean;
Expand Down
83 changes: 66 additions & 17 deletions lib/galaxy/job_metrics/instrumenters/cgroup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""The module describes the ``cgroup`` job metrics plugin."""
import decimal
import logging
import numbers
from collections import namedtuple
Expand All @@ -17,7 +18,27 @@

log = logging.getLogger(__name__)

VALID_VERSIONS = ("auto", "1", "2")
DEFAULT_PARAMS = (
# cgroupsv1 - this is probably more params than are useful to collect, but don't remove any for legacy reasons
"memory.memsw.max_usage_in_bytes",
"memory.max_usage_in_bytes",
"memory.limit_in_bytes",
"memory.memsw.limit_in_bytes",
"memory.soft_limit_in_bytes",
"memory.failcnt",
"memory.oom_control.oom_kill_disable",
"memory.oom_control.under_oom",
"cpuacct.usage",
# cgroupsv2
"memory.events.oom_kill",
"memory.peak",
"cpu.stat.system_usec",
"cpu.stat.usage_usec",
"cpu.stat.user_usec",
)
TITLES = {
# cgroupsv1
"memory.memsw.max_usage_in_bytes": "Max memory usage (MEM+SWP)",
"memory.max_usage_in_bytes": "Max memory usage (MEM)",
"memory.limit_in_bytes": "Memory limit on cgroup (MEM)",
Expand All @@ -27,14 +48,35 @@
"memory.oom_control.oom_kill_disable": "OOM Control enabled",
"memory.oom_control.under_oom": "Was OOM Killer active?",
"cpuacct.usage": "CPU Time",
# cgroupsv2
"memory.events.low": "Number of times the cgroup was reclaimed due to high memory pressure even though its usage is under the low "
"boundary",
"memory.events.high": "Number of times processes of the cgroup were throttled and routed to perform direct memory reclaim because "
"the high memory boundary was exceeded",
"memory.events.max": "Number of times the cgroup's memory usage was about to go over the max boundary",
"memory.events.oom": "Number of time the cgroup's memory usage reached the limit and allocation was about to fail",
"memory.events.oom_kill": "Number of processes belonging to this cgroup killed by any kind of OOM killer",
"memory.events.oom_group_kill": "Number of times a group OOM has occurred",
"memory.high": "Memory usage throttle limit",
"memory.low": "Best-effort memory protection",
"memory.max": "Memory usage hard limit",
"memory.min": "Hard memory protection",
"memory.peak": "Max memory usage recorded",
"cpu.stat.system_usec": "CPU system time",
"cpu.stat.usage_usec": "CPU usage time",
"cpu.stat.user_usec": "CPU user time",
}
CONVERSION = {
"memory.oom_control.oom_kill_disable": lambda x: "No" if x == 1 else "Yes",
"memory.oom_control.under_oom": lambda x: "Yes" if x == 1 else "No",
"memory.peak": lambda x: nice_size(x),
"cpuacct.usage": lambda x: formatting.seconds_to_str(x / 10**9), # convert nanoseconds
"cpu.stat.system_usec": lambda x: formatting.seconds_to_str(x / 10**6), # convert microseconds
"cpu.stat.usage_usec": lambda x: formatting.seconds_to_str(x / 10**6), # convert microseconds
"cpu.stat.user_usec": lambda x: formatting.seconds_to_str(x / 10**6), # convert microseconds
}
CPU_USAGE_TEMPLATE = r"""
if [ -e "/proc/$$/cgroup" -a -d "{cgroup_mount}" ]; then
CGROUPSV1_TEMPLATE = r"""
if [ -e "/proc/$$/cgroup" -a -d "{cgroup_mount}" -a ! -f "{cgroup_mount}/cgroup.controllers" ]; then
cgroup_path=$(cat "/proc/$$/cgroup" | awk -F':' '($2=="cpuacct,cpu") || ($2=="cpu,cpuacct") {{print $3}}');
if [ ! -e "{cgroup_mount}/cpu$cgroup_path/cpuacct.usage" ]; then
cgroup_path="";
Expand All @@ -44,12 +86,6 @@
echo "__$(basename $f)__" >> {metrics}; cat "$f" >> {metrics} 2>/dev/null;
fi;
done;
fi
""".replace(
"\n", " "
).strip()
MEMORY_USAGE_TEMPLATE = """
if [ -e "/proc/$$/cgroup" -a -d "{cgroup_mount}" ]; then
cgroup_path=$(cat "/proc/$$/cgroup" | awk -F':' '$2=="memory"{{print $3}}');
if [ ! -e "{cgroup_mount}/memory$cgroup_path/memory.max_usage_in_bytes" ]; then
cgroup_path="";
Expand All @@ -61,6 +97,16 @@
""".replace(
"\n", " "
).strip()
CGROUPSV2_TEMPLATE = r"""
if [ -e "/proc/$$/cgroup" -a -f "{cgroup_mount}/cgroup.controllers" ]; then
cgroup_path=$(cat "/proc/$$/cgroup" | awk -F':' '($1=="0") {{print $3}}');
for f in {cgroup_mount}/${{cgroup_path}}/{{cpu,memory}}.*; do
echo "__$(basename $f)__" >> {metrics}; cat "$f" >> {metrics} 2>/dev/null;
done;
fi
""".replace(
"\n", " "
).strip()


Metric = namedtuple("Metric", ("key", "subkey", "value"))
Expand All @@ -76,7 +122,7 @@ def format(self, key, value):
return title, nice_size(value)
except ValueError:
pass
elif isinstance(value, (numbers.Integral, numbers.Real)) and value == int(value):
elif isinstance(value, (decimal.Decimal, numbers.Integral, numbers.Real)) and value == int(value):
value = int(value)
return title, value

Expand All @@ -90,33 +136,36 @@ class CgroupPlugin(InstrumentPlugin):
def __init__(self, **kwargs):
self.verbose = asbool(kwargs.get("verbose", False))
self.cgroup_mount = kwargs.get("cgroup_mount", "/sys/fs/cgroup")
self.version = str(kwargs.get("version", "auto"))
assert self.version in VALID_VERSIONS, f"cgroup metric version option must be one of {VALID_VERSIONS}"
params_str = kwargs.get("params", None)
if isinstance(params_str, list):
params = params_str
elif params_str:
params = [v.strip() for v in params_str.split(",")]
else:
params = list(TITLES.keys())
params = list(DEFAULT_PARAMS)
self.params = params

def post_execute_instrument(self, job_directory: str) -> List[str]:
commands: List[str] = []
commands.append(self.__record_cgroup_cpu_usage(job_directory))
commands.append(self.__record_cgroup_memory_usage(job_directory))
if self.version in ("auto", "1"):
commands.append(self.__record_cgroup_v1_usage(job_directory))
if self.version in ("auto", "2"):
commands.append(self.__record_cgroup_v2_usage(job_directory))
return commands

def job_properties(self, job_id, job_directory: str) -> Dict[str, Any]:
metrics = self.__read_metrics(self.__cgroup_metrics_file(job_directory))
return metrics

def __record_cgroup_cpu_usage(self, job_directory: str) -> str:
# comounted cgroups (which cpu and cpuacct are on the supported Linux distros) can appear in any order (cpu,cpuacct or cpuacct,cpu)
return CPU_USAGE_TEMPLATE.format(
def __record_cgroup_v1_usage(self, job_directory: str) -> str:
return CGROUPSV1_TEMPLATE.format(
metrics=self.__cgroup_metrics_file(job_directory), cgroup_mount=self.cgroup_mount
)

def __record_cgroup_memory_usage(self, job_directory: str) -> str:
return MEMORY_USAGE_TEMPLATE.format(
def __record_cgroup_v2_usage(self, job_directory: str) -> str:
return CGROUPSV2_TEMPLATE.format(
metrics=self.__cgroup_metrics_file(job_directory), cgroup_mount=self.cgroup_mount
)

Expand Down
Loading

0 comments on commit 038d31e

Please sign in to comment.