summaryrefslogtreecommitdiff
path: root/core/nds32/task.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/nds32/task.c')
-rw-r--r--core/nds32/task.c132
1 files changed, 130 insertions, 2 deletions
diff --git a/core/nds32/task.c b/core/nds32/task.c
index 3c7358abe6..df7743ed82 100644
--- a/core/nds32/task.c
+++ b/core/nds32/task.c
@@ -48,6 +48,18 @@ static const char * const task_names[] = {
};
#undef TASK
+#ifdef CONFIG_TASK_PROFILING
+static int task_will_switch;
+static uint64_t exc_sub_time;
+static uint64_t task_start_time; /* Time task scheduling started */
+static uint64_t exc_start_time; /* Time of task->exception transition */
+static uint64_t exc_end_time; /* Time of exception->task transition */
+static uint64_t exc_total_time; /* Total time in exceptions */
+static uint32_t svc_calls; /* Number of service calls */
+static uint32_t task_switches; /* Number of times active task changed */
+static uint32_t irq_dist[CONFIG_IRQ_COUNT]; /* Distribution of IRQ calls */
+#endif
+
extern int __task_start(void);
#ifndef CONFIG_LOW_POWER_IDLE
@@ -168,6 +180,9 @@ static uint32_t tasks_ready = (1 << TASK_ID_HOOKS);
static int start_called; /* Has task swapping started */
+/* interrupt number of sw interrupt */
+static int sw_int_num;
+
static inline task_ *__task_id_to_ptr(task_id_t id)
{
return tasks + id;
@@ -237,6 +252,14 @@ int task_start_called(void)
return start_called;
}
+int get_sw_int(void)
+{
+ /* If this is a SW interrupt */
+ if (get_itype() & 8)
+ return sw_int_num;
+ return 0;
+}
+
/**
* Scheduling system call
*
@@ -251,6 +274,7 @@ void syscall_handler(int desched, task_id_t resched, int swirq)
set_ipc(get_ipc() + 4);
/* call the regular IRQ handler */
handler();
+ sw_int_num = 0;
return;
}
@@ -266,13 +290,27 @@ void syscall_handler(int desched, task_id_t resched, int swirq)
/* trigger a re-scheduling on exit */
need_resched = 1;
+#ifdef CONFIG_TASK_PROFILING
+ svc_calls++;
+#endif
+
/* adjust IPC to return *after* the syscall instruction */
set_ipc(get_ipc() + 4);
}
task_ *next_sched_task(void)
{
- return __task_id_to_ptr(__fls(tasks_ready));
+ task_ *new_task = __task_id_to_ptr(__fls(tasks_ready));
+
+#ifdef CONFIG_TASK_PROFILING
+ if (current_task != new_task) {
+ current_task->runtime +=
+ (exc_start_time - exc_end_time - exc_sub_time);
+ task_will_switch = 1;
+ }
+#endif
+
+ return new_task;
}
static inline void __schedule(int desched, int resched, int swirq)
@@ -284,6 +322,67 @@ static inline void __schedule(int desched, int resched, int swirq)
asm("syscall 0" : : "r"(p0), "r"(p1), "r"(p2));
}
+void update_exc_start_time(void)
+{
+#ifdef CONFIG_TASK_PROFILING
+ exc_start_time = get_time().val;
+#endif
+}
+
+void start_irq_handler(void)
+{
+#ifdef CONFIG_TASK_PROFILING
+ int irq;
+
+ /* save r0, r1, and r2 for syscall */
+ asm volatile ("smw.adm $r0, [$sp], $r2, 0");
+
+ update_exc_start_time();
+
+ irq = get_sw_int();
+ if (!irq)
+ irq = IT83XX_INTC_AIVCT - 16;
+
+ /*
+ * Track IRQ distribution. No need for atomic add, because an IRQ
+ * can't pre-empt itself.
+ */
+ if ((irq > 0) && (irq < ARRAY_SIZE(irq_dist)))
+ irq_dist[irq]++;
+
+ /* restore r0, r1, and r2 */
+ asm volatile ("lmw.bim $r0, [$sp], $r2, 0");
+#endif
+}
+
+void end_irq_handler(void)
+{
+#ifdef CONFIG_TASK_PROFILING
+ uint64_t t, p;
+
+ /*
+ * save r0 and fp (fp for restore r0-r5, r15, fp, lp and sp
+ * while interrupt exit.
+ */
+ asm volatile ("smw.adm $r0, [$sp], $r0, 8");
+
+ t = get_time().val;
+ p = t - exc_start_time;
+
+ exc_total_time += p;
+ exc_sub_time += p;
+ if (task_will_switch) {
+ task_will_switch = 0;
+ exc_sub_time = 0;
+ exc_end_time = t;
+ task_switches++;
+ }
+
+ /* restore r0 and fp */
+ asm volatile ("lmw.bim $r0, [$sp], $r0, 8");
+#endif
+}
+
static uint32_t __wait_evt(int timeout_us, task_id_t resched)
{
task_ *tsk = current_task;
@@ -380,8 +479,10 @@ void task_clear_pending_irq(int irq)
void task_trigger_irq(int irq)
{
int cpu_int = chip_trigger_irq(irq);
- if (cpu_int > 0)
+ if (cpu_int > 0) {
+ sw_int_num = irq;
__schedule(0, 0, cpu_int);
+ }
}
/*
@@ -490,8 +591,32 @@ void task_print_list(void)
int command_task_info(int argc, char **argv)
{
+#ifdef CONFIG_TASK_PROFILING
+ int total = 0;
+ int i;
+#endif
+
task_print_list();
+#ifdef CONFIG_TASK_PROFILING
+ ccputs("IRQ counts by type:\n");
+ cflush();
+ for (i = 0; i < ARRAY_SIZE(irq_dist); i++) {
+ if (irq_dist[i]) {
+ ccprintf("%4d %8d\n", i, irq_dist[i]);
+ total += irq_dist[i];
+ }
+ }
+
+ ccprintf("Service calls: %11d\n", svc_calls);
+ ccprintf("Total exceptions: %11d\n", total + svc_calls);
+ ccprintf("Task switches: %11d\n", task_switches);
+ ccprintf("Task switching started: %11.6ld s\n", task_start_time);
+ ccprintf("Time in tasks: %11.6ld s\n",
+ get_time().val - task_start_time);
+ ccprintf("Time in exceptions: %11.6ld s\n", exc_total_time);
+#endif
+
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(taskinfo, command_task_info,
@@ -564,6 +689,9 @@ void task_pre_init(void)
int task_start(void)
{
+#ifdef CONFIG_TASK_PROFILING
+ task_start_time = exc_end_time = get_time().val;
+#endif
start_called = 1;
return __task_start();