Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Throttler / Timer ; use current scheduler #9611

Closed
wants to merge 8 commits into from

Conversation

ivovandongen
Copy link
Contributor

@ivovandongen ivovandongen commented Jul 25, 2017

This PR builds on top of #9728 to make the Timers and throttlers use the current scheduler.

@ivovandongen ivovandongen added Android Mapbox Maps SDK for Android Core The cross-platform C++ core, aka mbgl GLFW iOS Mapbox Maps SDK for iOS Linux macOS Mapbox Maps SDK for macOS Node.js node-mapbox-gl-native Qt Mapbox Maps SDK for Qt, aka Qt Location Mapbox GL ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold labels Jul 25, 2017
@ivovandongen ivovandongen self-assigned this Jul 25, 2017
@ivovandongen ivovandongen force-pushed the ivd-current-scheduler branch 4 times, most recently from 63f1b25 to d0f27bf Compare July 27, 2017 15:30
@ivovandongen
Copy link
Contributor Author

ivovandongen commented Jul 27, 2017

@jfirebaugh I've started on adding delayed scheduling to the Scheduler. I've borrowed some patterns from Akka, but would love your feedback.

The idea is to schedule a message for later delivery on the given mailbox with:

virtual std::unique_ptr<Scheduled> schedule(Duration timeout, std::weak_ptr<Mailbox>, std::unique_ptr<Message>) = 0;

Since we need the object to make the Message this needs to go through either Actor or ActorRef:

std::unique_ptr<Scheduler::Scheduled> invokeDelayed(Duration timeout, Fn fn, Args&&... args, Scheduler& scheduler = *Scheduler::GetCurrent()) {

The Throttler is already using this.

The actual implementations for Scheduler would use different strategies for the timers. On the Runloop backed schedulers, we can use the existing Timer/Alarm classes. The thread pool would have a dedicated thread/threads for controlling the timers.

The scheduler returns a handle in the form of Scheduler::Scheduled that is analogous to the Cancelable on Akka, but also has ownership of the timer so one needs to keep it alive to keep the timer alive.

The Throttler now is a proxy for the ActorRef passed in and has a similar interface to ActorRef. The throttling is now ActorRef-wide, not per method.

Note: ThreadBasedTimer is a quick implementation to try things out, it's not very fast and I want to replace it with a Runloop backed one for most, but couldn't quite get it compiling right away.

@ivovandongen ivovandongen force-pushed the ivd-current-scheduler branch 5 times, most recently from 0431ca6 to 4ddc3ca Compare July 31, 2017 13:31
@ivovandongen ivovandongen removed the ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold label Jul 31, 2017
@ivovandongen
Copy link
Contributor Author

I've added two implementations for the timers:

The only RunLoop that doesn't support scheduling a delayed message is the NodeThreadPool. But, no timers are used there anyway.

This should be sufficient to continue work on #9576

@ivovandongen
Copy link
Contributor Author

Trying out this branch, I noticed that I overlooked one issue with the way I use timers now. They still get the current Runloop instead of the runloop I intended them to be scheduled on.

@@ -58,8 +58,8 @@ void ThreadLocal<T>::set(T* ptr) {
}
}

template class ThreadLocal<RunLoop>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Removes the template instantiation, but the corresponding code is still there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The code that used the template was in RunLoop, but has since been removed in favor of a ThreadLocal on Scheduler


// Set/Get the current Scheduler for this thread
static Scheduler* GetCurrent();
static void SetCurrent(Scheduler*);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this one protected so that only subclasses can set the current scheduler?

// Invoke twice in a row
throttler.invoke(&Test::doIt);
throttler.invoke(&Test::doIt);
loop.runOnce(); // Let the timer do it's thing
Copy link
Contributor

Choose a reason for hiding this comment

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

typo -> "its" ;)

virtual void cancel() = 0;

virtual bool isFinished() = 0;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

We already have an almost identical class called WorkTask (and a few others that are similar). Maybe we can reuse/unify those?

Copy link
Contributor

Choose a reason for hiding this comment

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

AsyncRequest is the most generic interface. It's an interface for objects that cancel themselves when they go out of scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've made it extend from AsyncRequest. However, we need a way to see if the task is completed (for Throttler) that's why I made it a new class with a isFinished() method.

class ThreadPoolScheduledTask : public Scheduler::Scheduled {
public:
// The Impl is scheduled on the Runloop of the timer thread
// and uses it to start a timer. When the timer endsm it calls
Copy link
Contributor

Choose a reason for hiding this comment

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

typo


delegate.invoke(fn, std::forward<Args>(args)...);
});
pendingInvocation = delegate.invokeDelayed(timeToNextInvocation, fn, std::forward<Args>(args)...);
Copy link
Contributor

Choose a reason for hiding this comment

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

std::move(fn)

}
private:
std::shared_ptr<Fn> fn;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

We have the combination of WorkRequest/WorkTask which is very similar to this. Can this be reused here?

wrap(
[&, weakMailbox = std::move(weakMailbox), message = std::move(message)] () mutable {
if (auto mailbox = weakMailbox.lock()) {
mailbox->push(std::forward<std::unique_ptr<Message>>(message));
Copy link
Contributor

Choose a reason for hiding this comment

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

Why forward instead of move?

Copy link
Contributor

Choose a reason for hiding this comment

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

Since the lambda is mutable, this should also protect against double-invocation when message is empty.

};

} // namespace util
} // namespace mbgl
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing newline

Copy link
Contributor

@jfirebaugh jfirebaugh left a comment

Choose a reason for hiding this comment

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

Can you submit the RunLoop::GetScheduler::GetCurrent changes as a separate PR? I'm 👍 on those ones but much less certain of the throttler / timer changes. Maybe we should just rip out the throttler dependency and rethink it entirely.

@@ -200,19 +200,20 @@ Milliseconds RunLoop::Impl::processRunnables() {
}

RunLoop* RunLoop::Get() {
return current.get();
assert(static_cast<RunLoop*>(Scheduler::GetCurrent()));
Copy link
Contributor

Choose a reason for hiding this comment

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

Check the type too: assert(dynamic_cast<RunLoop*>(Scheduler::GetCurrent())) (x4).

@@ -4,6 +4,7 @@
#include <mbgl/util/thread_local.hpp>
Copy link
Contributor

Choose a reason for hiding this comment

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

No longer used (x2).

virtual void cancel() = 0;

virtual bool isFinished() = 0;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

AsyncRequest is the most generic interface. It's an interface for objects that cancel themselves when they go out of scope.

@@ -62,6 +62,14 @@ class RunLoop : public Scheduler,
push(task);
return std::make_unique<WorkRequest>(task);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: excess whitespace here.

#include <memory>

namespace mbgl {

class Mailbox;
class Message;

/*
A `Scheduler` is responsible for coordinating the processing of messages by
Copy link
Contributor

Choose a reason for hiding this comment

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

Update the references to RunLoop in this comment.

@ivovandongen ivovandongen force-pushed the ivd-current-scheduler branch 3 times, most recently from 9df6cda to b0c3a82 Compare August 7, 2017 17:32
ivovandongen added a commit that referenced this pull request Aug 9, 2017
- This doesn't work for asynchronous rendering -  see #9611
@ivovandongen ivovandongen mentioned this pull request Aug 10, 2017
6 tasks
ivovandongen added a commit that referenced this pull request Aug 10, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Aug 18, 2017
- This doesn't work for asynchronous rendering -  see #9611
@ivovandongen
Copy link
Contributor Author

As discussed in chat; closing this and just removing the throttling all together.

ivovandongen added a commit that referenced this pull request Sep 4, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 8, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 12, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 13, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 15, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 18, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 19, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 21, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 22, 2017
- This doesn't work for asynchronous rendering -  see #9611
ivovandongen added a commit that referenced this pull request Sep 22, 2017
- This doesn't work for asynchronous rendering -  see #9611
@jfirebaugh jfirebaugh deleted the ivd-current-scheduler branch October 24, 2017 20:40
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Android Mapbox Maps SDK for Android Core The cross-platform C++ core, aka mbgl iOS Mapbox Maps SDK for iOS Linux macOS Mapbox Maps SDK for macOS Node.js node-mapbox-gl-native Qt Mapbox Maps SDK for Qt, aka Qt Location Mapbox GL
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants