[hypercos] [PATCH 3/4] core: Add task load & core utilization tracking

  • From: Howard Chen <ibanezchen@xxxxxxxxx>
  • To: socware.help@xxxxxxxxx, hypercos@xxxxxxxxxxxxx
  • Date: Wed, 2 Nov 2016 10:29:21 +0800

---
 include/cfg.h  |   2 +-
 include/core.h |  12 +---
 include/load.h |  56 ++++++++++++++++
 src/core.c     |  67 ++++++-------------
 src/load.c     | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 277 insertions(+), 58 deletions(-)
 create mode 100644 include/load.h
 create mode 100644 src/load.c

diff --git a/include/cfg.h b/include/cfg.h
index 368e76c..df8809a 100644
--- a/include/cfg.h
+++ b/include/cfg.h
@@ -186,7 +186,7 @@
 
 /// support OS utilization statistics
 #ifndef CFG_OSUTIL
-#define CFG_OSUTIL     3
+#define CFG_OSUTIL     1
 #endif
 
 /// support stack overflow detection
diff --git a/include/core.h b/include/core.h
index f54f636..a9c2bec 100644
--- a/include/core.h
+++ b/include/core.h
@@ -27,6 +27,7 @@
 #ifndef HTOS
 #define HTOS
 
+#include "cfg.h"
 #include "ll.h"
 #include "cpu/reg.h"
 #include "cpu/_irq.h"
@@ -47,15 +48,8 @@ void *core_alloc(unsigned sz, int align_bits);
 
 #define _alloc(_sz)      core_alloc(_sz, 3)
 
-typedef struct {
-       unsigned *idles, idle_sz;
-       unsigned idle, all;
-} core_ut_t;
-
-void core_ut_init(int sample_ticks);
-
-extern core_ut_t core_ut;
-
 extern void (*core_abt) (void *ctx);
 
+struct task *core_idle();
+
 #endif
diff --git a/include/load.h b/include/load.h
new file mode 100644
index 0000000..21ca2f5
--- /dev/null
+++ b/include/load.h
@@ -0,0 +1,56 @@
+/*-****************************************************************************/
+/*-                                                                           
*/
+/*-            Copyright (c) of hyperCOS.                                     
*/
+/*-                                                                           
*/
+/*-  This software is copyrighted by and is the sole property of socware.net. 
*/
+/*-  All rights, title, ownership, or other interests in the software remain  
*/
+/*-  the property of socware.net. The source code is FREE for short-term      
*/
+/*-  evaluation, educational or non-commercial research only. Any commercial  
*/
+/*-  application may only be used in accordance with the corresponding 
license*/
+/*-  agreement. Any unauthorized use, duplication, transmission, 
distribution,*/
+/*-  or disclosure of this software is expressly forbidden.                   
*/
+/*-                                                                           
*/
+/*-  Knowledge of the source code may NOT be used to develop a similar 
product*/
+/*-                                                                           
*/
+/*-  This Copyright notice may not be removed or modified without prior       
*/
+/*-  written consent of socware.net.                                          
*/
+/*-                                                                           
*/
+/*-  socware.net reserves the right to modify this software                   
*/
+/*-  without notice.                                                          
*/
+/*-                                                                           
*/
+/*-  To contact socware.net:                                                  
*/
+/*-                                                                           
*/
+/*-             socware.help@xxxxxxxxx                                        
*/
+/*-                                                                           
*/
+/*-****************************************************************************/
+#ifndef LOAD0930
+#define LOAD0930
+
+#include "clk.h"
+#include <string.h>
+
+typedef struct {
+       unsigned ts;            ///< lastest scheduled time stamp
+       unsigned sum;
+       unsigned wei;           ///< weight, idle task shall be 0
+} load_t;
+
+typedef void (*load_tune_f) (unsigned load, unsigned load_full);
+
+/// @param load_ticking_scale, set 1 to sync every 32ticks, set 2 to sync every
+/// 64 ticks and so on.
+void load_init(clk_t * cpu_clk, int load_ticking_scale, load_tune_f tune);
+
+void load_dvfs(unsigned load, unsigned load_full);
+
+typedef struct {
+       unsigned idle, all;
+       unsigned ut_sta;
+       int sample_ticks;
+} load_ut_t;
+
+void load_ut_init(int sample_ticks);
+
+extern load_ut_t load_ut;
+
+#endif
diff --git a/src/core.c b/src/core.c
index 3985afc..d0416c1 100644
--- a/src/core.c
+++ b/src/core.c
@@ -23,7 +23,7 @@
 /*-             socware.help@xxxxxxxxx                                        
*/
 /*-                                                                           
*/
 
/*-****************************************************************************/
-
+#include "cfg.h"
 #include "core.h"
 #include "soc.h"
 #include "tmr.h"
@@ -38,56 +38,19 @@
 #include "cpu/cache.h"
 #include "cpu/_cpu.h"
 
+ll_t core_gc_task;
+
 unsigned core_heap;
 
+//SMP: cpudata
 static task_t core_task_idle;
 
-#if CFG_OSUTIL
-
-static unsigned idles[1 << CFG_OSUTIL], iidle;
-
-static unsigned ut_sta;
-
-static tmr_t ut_tmr;
-
-static int sample_ticks;
-
-core_ut_t core_ut = { idles, sizeof(idles) / sizeof(unsigned), 0, 0 };
-
-static int ut_tick(void *p)
-{
-       unsigned now, iflag;
-       iflag = irq_lock();
-       now = soc_rtcs();
-       core_ut.idles[iidle] = core_task_idle.ut;
-       core_task_idle.ut = 0;
-       core_ut.idle = (core_ut.idle >> 1) + core_ut.idles[iidle];
-       core_ut.all = (core_ut.all >> 1) + (now - ut_sta);
-       ut_sta = now;
-       irq_restore(iflag);
-       iidle = (iidle + 1) & ((1 << CFG_OSUTIL) - 1);
-       core_ut.idles[iidle] = 0;
-       return sample_ticks;
-}
-
-void core_ut_init(int _sample_ticks)
-{
-       ut_sta = soc_rtcs();
-       sample_ticks = _sample_ticks;
-       tmr_init(&ut_tmr, 0, ut_tick);
-       tmr_on(&ut_tmr, _sample_ticks);
-}
-
-#endif
-
-ll_t core_gc_task;
-
-static void core_idle(void *priv)
+static void _idle(void *priv)
 {
        sch_schedule(1);
        for (;;) {
 #if CFG_TASK_GC
-               if (!ll_empty(&core_gc_task)) {
+               while (!ll_empty(&core_gc_task)) {
                        unsigned iflag = irq_lock();
                        task_t *gct =
                            lle_get(ll_head(&core_gc_task), task_t, ll);
@@ -95,7 +58,6 @@ static void core_idle(void *priv)
                        irq_restore(iflag);
                        if (task_gc)
                                task_gc(gct);
-                       continue;
                }
 #endif
 #if CFG_TICKLESS
@@ -123,19 +85,28 @@ void core_init()
        cpu_init();
        soc_init();
        sch_init();
+       tmr_init_sys();
+       ll_init(&core_gc_task);
+
+       //SMP: per-cpu init
        task_init(&core_task_idle,
                  "idle",
-                 core_idle,
+                 _idle,
                  CFG_TPRI_NUM - 1,
                  _alloc(CFG_IDLE_STACK), CFG_IDLE_STACK, 10, 0);
-       tmr_init_sys();
-       ll_init(&core_gc_task);
+       task_set_idle(&core_task_idle);
 }
 
 void core_start()
 {
        lle_del(&core_task_idle.ll);
        _task_cur = &core_task_idle;
-       _task_cur->sch = soc_rtcs();
+       _task_cur->load.ts = soc_rtcs();
+       //SMP: bootup
        task_load(&core_task_idle);
 }
+
+struct task *core_idle()
+{
+       return &core_task_idle;
+}
diff --git a/src/load.c b/src/load.c
new file mode 100644
index 0000000..4de21b3
--- /dev/null
+++ b/src/load.c
@@ -0,0 +1,198 @@
+/*-****************************************************************************/
+/*-                                                                           
*/
+/*-            Copyright (c) of hyperCOS.                                     
*/
+/*-                                                                           
*/
+/*-  This software is copyrighted by and is the sole property of socware.net. 
*/
+/*-  All rights, title, ownership, or other interests in the software remain  
*/
+/*-  the property of socware.net. The source code is FREE for short-term      
*/
+/*-  evaluation, educational or non-commercial research only. Any commercial  
*/
+/*-  application may only be used in accordance with the corresponding 
license*/
+/*-  agreement. Any unauthorized use, duplication, transmission, 
distribution,*/
+/*-  or disclosure of this software is expressly forbidden.                   
*/
+/*-                                                                           
*/
+/*-  Knowledge of the source code may NOT be used to develop a similar 
product*/
+/*-                                                                           
*/
+/*-  This Copyright notice may not be removed or modified without prior       
*/
+/*-  written consent of socware.net.                                          
*/
+/*-                                                                           
*/
+/*-  socware.net reserves the right to modify this software                   
*/
+/*-  without notice.                                                          
*/
+/*-                                                                           
*/
+/*-  To contact socware.net:                                                  
*/
+/*-                                                                           
*/
+/*-             socware.help@xxxxxxxxx                                        
*/
+/*-                                                                           
*/
+/*-****************************************************************************/
+#include "clk.h"
+#include "tmr.h"
+#include "core.h"
+#include "task.h"
+#include "load.h"
+#include "soc.h"
+#include "tmr.h"
+#include "sch.h"
+
+#define LOAD_TICKING_SHIFT     5
+
+#define FULL_ITERATION         20
+
+static unsigned load_full;
+//SMP:
+static load_t core_load;
+
+static clk_t *clk_cpu;
+
+static tmr_t tmr;
+
+static int load_ticking;
+
+static task_switch_t switch_listener;
+
+static void (*tune) (unsigned load, unsigned load_full);
+
+static void sys_tune()
+{
+       unsigned load = core_load.sum + _task_cur->load.sum;
+       if (load > load_full)
+               load = load_full;
+       if (tune)
+               tune(load, load_full);
+}
+
+void load_dvfs(unsigned load, unsigned load_full)
+{
+       int sel = (clk_cpu->freq_n * load) / load_full;
+       clk_setf(clk_cpu, sel);
+}
+
+static inline unsigned normalize(unsigned load)
+{
+       return load * clk_cpu->freq[clk_cpu->idx];
+}
+
+static inline unsigned _decay(unsigned sum, unsigned rtc_ticks)
+{
+       unsigned tmr_ticks = rtc_ticks >> tmr_rtcs2tick;
+       return (sum >> (tmr_ticks >> LOAD_TICKING_SHIFT));
+}
+
+static inline void decay(load_t * load, unsigned now)
+{
+       load->sum = _decay(load->sum, now - load->ts);
+       load->ts = now;
+}
+
+static void _switch(task_switch_t * o, task_t * tn)
+{
+       unsigned now = soc_rtcs();
+       if (task_is_idle(_task_cur)) {
+               //SMP:
+               tmr_on_irq(&tmr, load_ticking);
+               _task_cur->load.sum += now - _task_cur->load.ts;
+       } else if (clk_cpu) {
+               _task_cur->load.sum += normalize(now - _task_cur->load.ts);
+       }
+       if (task_is_idle(tn)) {
+               //SMP:
+               tmr_of(&tmr);
+               tn->load.ts = now;
+       } else if (clk_cpu) {
+               if (core_load.sum > tn->load.sum)
+                       core_load.sum -= tn->load.sum;
+               else
+                       core_load.sum = 0;
+               decay(&tn->load, now);
+       }
+}
+
+static inline int task_switch_active(task_switch_t * o)
+{
+       return o->notify == _switch;
+}
+
+void _wake(task_t * t)
+{
+       decay(&t->load, soc_rtcs());
+       core_load.sum += t->load.sum;
+       sys_tune();
+}
+
+static int load_tick(void *p)
+{
+       unsigned iflag = irq_lock();
+       unsigned now = soc_rtcs();
+       // decay cpu load
+       decay(&core_load, now);
+       // decay task_cur load
+       decay(&_task_cur->load, now);
+       // add sample task_cur to avg
+       _task_cur->load.sum += normalize(now - _task_cur->load.ts);
+       sys_tune();
+       irq_restore(iflag);
+       return load_ticking;
+}
+
+static inline unsigned full_load(clk_t * clk)
+{
+       unsigned i, sum;
+       unsigned max_freq = clk->freq[clk->freq_n - 1];
+       unsigned max_sample = load_ticking << tmr_rtcs2tick;
+       sum = 0;
+       for (i = 0; i < FULL_ITERATION; i++)
+               sum = _decay(sum, max_sample) + max_sample * max_freq;
+       return sum;
+}
+
+void load_init(clk_t * _clk_cpu, int load_ticking_scale, load_tune_f _tune)
+{
+       clk_cpu = _clk_cpu;
+       tune = _tune;
+       load_ticking = (load_ticking_scale << LOAD_TICKING_SHIFT);
+       load_full = full_load(clk_cpu);
+       tmr_init(&tmr, 0, load_tick);
+       if (!task_switch_active(&switch_listener)) {
+               task_switch_init(&switch_listener, _switch, 0);
+               task_switch_listen(&switch_listener);
+       }
+       sch_wake_notify = _wake;
+       core_load.ts = soc_rtcs();
+       tmr_on_irq(&tmr, load_ticking);
+}
+
+#if CFG_OSUTIL
+
+static tmr_t ut_tmr;
+
+//SMP: cpudata
+load_ut_t load_ut;
+
+// call in tmr task context
+static int ut_tick(void *p)
+{
+       unsigned now, iflag;
+       task_t *idle = core_idle();
+       load_ut_t *ut = &load_ut;
+       iflag = irq_lock();
+       now = soc_rtcs();
+       ut->idle = idle->load.sum;
+       ut->all = (now - ut->ut_sta);
+       ut->ut_sta = now;
+       idle->load.sum = 0;
+       irq_restore(iflag);
+       return ut->sample_ticks;
+}
+
+//SMP: cpuid
+void load_ut_init(int sample_ticks)
+{
+       load_ut_t *ut = &load_ut;
+       ut->ut_sta = soc_rtcs();
+       ut->sample_ticks = sample_ticks;
+       if (!task_switch_active(&switch_listener)) {
+               task_switch_init(&switch_listener, _switch, 0);
+               task_switch_listen(&switch_listener);
+       }
+       tmr_init(&ut_tmr, 0, ut_tick);
+       tmr_on(&ut_tmr, sample_ticks);
+}
+#endif
-- 
2.5.0


Other related posts:

  • » [hypercos] [PATCH 3/4] core: Add task load & core utilization tracking - Howard Chen