---
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