#44: Better scheduler handling
-------------------------+--------------------------------------------------
Reporter: toots | Owner: toots
Type: Bugs | Status: assigned
Priority: 8 | Milestone:
Component: Liquidsoap | Version: 0.3.3
Resolution: | Keywords:
-------------------------+--------------------------------------------------
Changes (by toots):
* owner: admin => toots
* priority: 1 => 8
* status: new => assigned
* summary: High CPU usage on empty or bad playlists => Better scheduler
handling
Old description:
> Liquidsoap consumes too much CPU un scheduling when empty or broken
> playlist is given.
New description:
Liquidsoap consumes too much CPU on scheduling when empty or broken
playlist is given.
More generaly, we should have a scheduler that is capable of:
* Scheduling new tasks immediatly
* Go to sleep for some time if no task are to be executed for now
This conditions are difficult to reach since the delay call cannot be
canceled, so you can go to sleep but not wake up.
My proposition is to add another "tick" thread that will perform regular
actions based on a minimal delay.
Then, using a global_sleep lock (as it is in place actually) in the
scheduler, we'll be able to either wake it up every [delay] sec, or as
soon as a task is scheduled.
This tick system will also be very usefull for lastfm sumbission, later,
and I suspect it may be of a great help for synchronisation
debugging/managing..
Comment:
Ok folks, I have an implementation to propose.
The patch is pasted below, and available at:
http://www.rastageeks.org/~toots/add_scheduler_thread.patch
Of course, I'll never commit anything until I have some feedback, and
especially david's advice.
{{{
Index: tools/tutils.ml
===================================================================
--- tools/tutils.ml (révision 4720)
+++ tools/tutils.ml (copie de travail)
@@ -97,6 +97,55 @@
id
) ()
+module Tick =
+struct
+
+ let conf_tick =
+ Conf.float ~p:(Configure.conf#plug "tick_delay") ~d:2.
+ "Set the tick minimun delay, in seconds."
+
+ type action = Simple of (unit -> unit) | Recursive of (unit ->
(float*action))
+
+ let alist = ref []
+ let alist_lock = Mutex.create ()
+ let delay = ref conf_tick#get
+
+ let add a =
+ Mutex.lock alist_lock ;
+ let time = Unix.time () in
+ alist := (time,a) :: !alist ;
+ Mutex.unlock alist_lock
+
+ let rec tick_task () =
+ Mutex.lock alist_lock ;
+ let newlist = ref [] in
+ delay := conf_tick#get ;
+ let time = Unix.time () in
+ let apply (t,a) =
+ if time >= t then
+ match a with
+ | Simple f -> f ()
+ | Recursive f ->
+ let (d,a') = f () in
+ newlist := (time +. d, a') :: !newlist ;
+ delay := min !delay d
+ else
+ newlist := (t,a) :: !newlist
+ in
+ List.iter apply !alist ;
+ alist := !newlist ;
+ Mutex.unlock alist_lock ;
+ Thread.delay !delay ;
+ tick_task ()
+
+ let tick () =
+ ignore (create tick_task () "Tick thread")
+
+ let () =
+ ignore (Dtools.Init.at_start tick)
+
+end
+
module Task =
struct
Index: tools/tutils.mli
===================================================================
--- tools/tutils.mli (révision 4720)
+++ tools/tutils.mli (copie de travail)
@@ -41,6 +41,30 @@
(** Check if a thread is running. *)
val running : string -> Thread.t -> bool
+module Tick :
+sig
+
+ (** Regular tick thread for liquidsoap
+ * You can add actions to be executed regulary
+ * Simple actions are executed when the thread
+ * wakes up.
+ *
+ * Recursive actions are executed, and then
+ * rescheduled after the ammount of time they
+ * ask for. Resursive actions return (delay,new_action)
+ *
+ * When this thread is asleep, nothing can wake it up
+ * Its minimal delay between two make ups is set
+ * using "tick" configuration key, and is 2. by default
+ * Because of this, you shouldn't use it for an immediate
+ * task *)
+
+ type action = Simple of (unit -> unit) | Recursive of (unit ->
(float*action))
+
+ val add : action -> unit
+
+end
+
module Task :
sig
type task = unit -> return_t
Index: Makefile
===================================================================
--- Makefile (révision 4720)
+++ Makefile (copie de travail)
@@ -81,9 +81,9 @@
$(if $(W_PORTAUDIO),io/portaudio_io.ml) \
$(if $(W_JACK),io/jack_io.ml)
-tools = tools/doc.ml tools/plug.ml tools/utils.ml \
+tools = tools/doc.ml tools/plug.ml tools/utils.ml configure.ml \
tools/tutils.ml tools/rqueue.ml tools/ringbuffer.ml \
- tools/wav.ml $(if $(BYTE),tools/dynliq.ml) configure.ml \
+ tools/wav.ml $(if $(BYTE),tools/dynliq.ml) \
tools/sutils.ml tools/http.ml \
$(if $(W_XML),tools/xmliq.ml tools/lastfm.ml)
}}}
--
Ticket URL: <http://savonet.rastageeks.org/ticket/44#comment:3>
Savonet <http://savonet.rastageeks.org/>
Let's program our stream !