#47: Tick Thread and better scheduling
------------------------+---------------------------------------------------
 Reporter:  toots       |       Owner:  admin    
     Type:  Feature     |      Status:  new      
 Priority:  8           |   Milestone:           
Component:  Liquidsoap  |     Version:  0.3.4+svn
 Keywords:              |  
------------------------+---------------------------------------------------
 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..

 A proposed implementation is attached as patch and pasted here:


 {{{
 Index: tools/tutils.ml
 ===================================================================
 --- tools/tutils.ml     (révision 4720)
 +++ tools/tutils.ml     (copie de travail)
 @@ -97,6 +97,56 @@
         id
    ) ()

 +module Tick =
 +struct
 +
 +  let conf_tick =
 +  Conf.float ~p:(Configure.conf#plug "tick_delay") ~d:2.
 +    "Set the maximun delay between two ticks, 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
 +        delay := min !delay (t -. time) ;
 +        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 maximal delay between two wake ups is set
 +    * using "tick_delay" 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/47>
Savonet <http://savonet.rastageeks.org/>
Let's program our stream !

Répondre à