Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parentless sequential clock trigger spawns #5732

Conversation

dwsutherland
Copy link
Member

@dwsutherland dwsutherland commented Sep 15, 2023

superseded by #5738

Spawning parentless clock triggered tasks out to the run ahead limit is unnecessary, and creates a lot of UI clutter.

Naturally clock trigger tasks are sequential in time, so it makes sense to only spawn the next parentless clock-trigger task when the current clock trigger is satisfied.

This PR attempts this.. In the simplest case;

[scheduling]
    initial cycle point = 20230915T0140Z
    [[xtriggers]]
        clock_1 = wall_clock()
    [[graph]]
        PT1M = """
@clock_1 => a
a => b
"""
[runtime]
    [[root]]
        script = sleep 5
    [[a,b]]

cutting down this;
image

to this:
image

(would only show one cycle, but obviously the trigger is satisfied)

Real workflows often have a much greater chain than a => b (and possibly much greater run-ahead limits), so you can imagine the clutter. (such as those at NIWA)

One thing to note; if your task has multiple xtriggers including a clock trigger, i.e.;

    [[xtriggers]]
        clock_1 = wall_clock()
        up_1 = workflow_state(workflow=clockspawn, task=b, point=%(point)s, offset=-P1Y):PT10S
    [[graph]]
        PT1M = """
@clock_1 => a
a => b
"""
        +PT1M/PT1M = """
@up_1 => b
"""

Then the task will still be clock blocked from spawning out to the RH (will instead spawn sequentially on trigger satisfaction, as described).
And if for some fringe reason a user wants the non-clock xtrigger to be checked/run out into the future/RH-limit and associated task clock bound to when it actually runs, then they can simply split them up:

    [[xtriggers]]
        clock_1 = wall_clock()
        up_1 = workflow_state(workflow=clockspawn, task=b, point=%(point)s, offset=-P1Y):PT10S
    [[graph]]
        PT1M = """
@clock_1 => a
a => b
"""
        +PT1M/PT1M = """
@up_1 => up_xtrig
up_xtrig => a
"""

(or w/e they desire.. alternatively turning their bespoke xtrigger into a task if that works)

In this way, I believe the behavior introduced here should be the default/natural restriction..

Check List

  • I have read CONTRIBUTING.md and added my name as a Code Contributor.
  • Contains logically grouped changes (else tidy your branch by rebase).
  • Does not contain off-topic changes (use other PRs for other changes).
  • Applied any dependency changes to both setup.cfg (and conda-environment.yml if present).
  • Appears to be covered by existing Tests.
  • CHANGES.md entry included if this is a change that can affect users
  • Cylc-Doc pull request opened if required at cylc/cylc-doc/pull/XXXX.

@dwsutherland dwsutherland added this to the cylc-8.3.0 milestone Sep 15, 2023
@dwsutherland dwsutherland self-assigned this Sep 15, 2023
@dwsutherland dwsutherland added the efficiency For notable efficiency improvements label Sep 15, 2023
@dwsutherland dwsutherland added small and removed small labels Sep 15, 2023
@dwsutherland
Copy link
Member Author

Actually, I might broaden this to optionally specify other xtriggers as sequential-spawn, e.g:

    [[xtriggers]]
        up_a = workflow_state(workflow=aflow, task=a, point=%(point)s):PT10S
        [[[settings]]]
            sequential-spawn = up_a
    [[graph]]
        PT1M = """
@up_1 => b
"""

Because, for some workflows, I wouldn't want workflow_state xtriggers to flood the UI (not to mention the process pool)..

Even though you could add a clock-trigger to make them sequential, this would clutter the workflow definition and be too narrow (i.e. you may want them to run sequential but not bound by real time)..

Wall clock xtriggers should still be sequential.

Copy link
Member

@hjoliver hjoliver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a good play around with this; it appears to do what it says on the tin 👍

Couple of comments...

@@ -211,6 +211,11 @@ def __init__(
# Signatures of active functions (waiting on callback).
self.active: list = []

# Gather named wall-clocks closet to current time.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Gather named wall-clocks closet to current time.
# Gather named wall-clock triggers closest to current time.

@@ -211,6 +211,11 @@ def __init__(
# Signatures of active functions (waiting on callback).
self.active: list = []

# Gather named wall-clocks closet to current time.
# (no need to check or spawn future clocks of tasks respectively).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rephrase this comment? It doesn't seem to make much sense as worded!)

Comment on lines 1737 to 1741
if housekeep_xtriggers:
# Spawn parentless clock-triggered
self.pool.spawn_parentless_clock_triggered()
# (Could do this periodically?)
self.xtrigger_mgr.housekeep(self.pool.get_tasks())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right place to handle the spawning? The reason for the if block here is to "delete satisfied xtriggers no longer needed by any tasks" (from the xtrigger_mgr.housekeep() docstring).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that housekeep_xtriggers is satisfied if xtriggers are, so just piggy backed off that.. But could just use that spawns list.

# Gather named wall-clocks closet to current time.
# (no need to check or spawn future clocks of tasks respectively).
self.wall_clock_labels: set = set()
self.wall_clock_spawns: list = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this variable be named better? like clock_spawn_next or something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, will change.. maybe to broaden sequential_spawn_next

@hjoliver
Copy link
Member

My test case:

[scheduling]
    initial cycle point = now
    [[xtriggers]]
        c2 = "wall_clock(offset=PT1M)"
        x1 = "xrandom(percent=50, _=%(point)s)"
    [[graph]]
        PT1M = """
            @wall_clock => foo1
            @c2 => foo2
            @x1 => bar
            qux
        """
[runtime]
    [[foo1, foo2, bar, qux]]
        script = sleep 5

One weird thing noticed. Spawned tasks waiting on clock triggers should be visible as waiting in n=0. When I run this, foo1 disappears from Tui after a few cycles, except when it is actually running. But foo2 is always visible as a waiting task. Both are present in cylc dump -t, however, so presumably that implies a bug in Tui, not the datastore?

@hjoliver
Copy link
Member

Tested with a parent in one cycle too, all good. As above, with this additional bit of graph:

       R1/+PT2M/PT0M = "qux => foo2"       

@hjoliver
Copy link
Member

hjoliver commented Sep 18, 2023

[x] Appears to be covered by existing Tests.

Coverage passed, but we can't be verifying the new spawning behavior as you haven't modified any of the test files.

@dwsutherland
Copy link
Member Author

dwsutherland commented Sep 18, 2023

When I run this, foo1 disappears from Tui after a few cycles, except when it is actually running.

Yes, I found the same.. Will have a look (maybe after next revision)

Coverage passed, but we can't be verifying the new spawning behavior as you haven't modified any of the test files.

I guess what I mean is; the current tests appear to cover 100% of this patch.. But, yes, will need to add specific tests (especially with expanded to optionally other xtriggers)

@dwsutherland
Copy link
Member Author

superseded by #5738

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
efficiency For notable efficiency improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants