[haiku-commits] BRANCH pdziepak-github.scheduler [d897a47] src/system/kernel src/system/kernel/arch/x86 headers/private/kernel src/system/kernel/scheduler

  • From: pdziepak-github.scheduler <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 18 Nov 2013 05:15:35 +0100 (CET)

added 3 changesets to branch 'refs/remotes/pdziepak-github/scheduler'
old head: 288a2664a2de429f159d746beaab87373184cd3d
new head: d897a478d7c01054aad29b23f7f545073c797530
overview: https://github.com/pdziepak/Haiku/compare/288a266...d897a47

----------------------------------------------------------------------------

6a164da: kernel: Track load produced by interrupt handlers

955c7ed: kernel: Measure time spent in interrupt handlers

d897a47: kernel: Allow reassigning IRQs to logical processors

                                    [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ]

----------------------------------------------------------------------------

16 files changed, 332 insertions(+), 69 deletions(-)
headers/private/kernel/arch/int.h              |   1 +
headers/private/kernel/arch/x86/arch_int.h     |   1 +
headers/private/kernel/arch/x86/arch_smp.h     |  14 ++
headers/private/kernel/cpu.h                   |   9 +-
headers/private/kernel/int.h                   |  29 +++-
headers/private/kernel/load_tracking.h         |  55 ++++++++
src/system/kernel/arch/x86/32/descriptors.cpp  |   2 +-
src/system/kernel/arch/x86/arch_int.cpp        |   8 ++
src/system/kernel/arch/x86/arch_smp.cpp        |  11 +-
src/system/kernel/arch/x86/ioapic.cpp          |  48 +++++--
src/system/kernel/arch/x86/pic.cpp             |   5 +-
src/system/kernel/arch/x86/timers/x86_apic.cpp |   3 +-
src/system/kernel/cpu.cpp                      |   3 +
src/system/kernel/int.cpp                      | 154 ++++++++++++++++++++-
src/system/kernel/scheduler/scheduler.cpp      |  52 +------
src/system/kernel/system_info.cpp              |   6 +-

############################################################################

Commit:      6a164daad43169daf0a407fb1f6b0484671ff466
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Nov 18 00:17:44 2013 UTC

kernel: Track load produced by interrupt handlers

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/int.h b/headers/private/kernel/int.h
index b3642c4..215deb0 100644
--- a/headers/private/kernel/int.h
+++ b/headers/private/kernel/int.h
@@ -19,6 +19,16 @@
 struct kernel_args;
 
 
+enum interrupt_type {
+       INTERRUPT_TYPE_EXCEPTION,
+       INTERRUPT_TYPE_IRQ,
+       INTERRUPT_TYPE_LOCAL_IRQ,
+       INTERRUPT_TYPE_SYSCALL,
+       INTERRUPT_TYPE_ICI,
+       INTERRUPT_TYPE_UNKNOWN
+};
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -53,7 +63,8 @@ are_interrupts_enabled(void)
 #define restore_interrupts(status)     arch_int_restore_interrupts(status)
 
 
-status_t reserve_io_interrupt_vectors(long count, long startVector);
+status_t reserve_io_interrupt_vectors(long count, long startVector,
+       enum interrupt_type type);
 status_t allocate_io_interrupt_vectors(long count, long *startVector);
 void free_io_interrupt_vectors(long count, long startVector);
 
diff --git a/headers/private/kernel/load_tracking.h 
b/headers/private/kernel/load_tracking.h
new file mode 100644
index 0000000..5b45c29
--- /dev/null
+++ b/headers/private/kernel/load_tracking.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Paweł Dziepak, pdziepak@xxxxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_LOAD_TRACKING_H
+#define _KERNEL_LOAD_TRACKING_H
+
+
+const int32 kMaxLoad = 1000;
+const bigtime_t kLoadMeasureInterval = 50000;
+const bigtime_t kIntervalInaccuracy = kLoadMeasureInterval / 4;
+
+
+static int32
+compute_load(bigtime_t& measureTime, bigtime_t& measureActiveTime, int32& load)
+{
+       bigtime_t now = system_time();
+
+       if (measureTime == 0) {
+               measureTime = now;
+               return -1;
+       }
+
+       bigtime_t deltaTime = now - measureTime;
+
+       if (deltaTime < kLoadMeasureInterval)
+               return -1;
+
+       int32 oldLoad = load;
+       ASSERT(oldLoad >= 0 && oldLoad <= kMaxLoad);
+
+       int32 newLoad = measureActiveTime * kMaxLoad;
+       newLoad /= max_c(deltaTime, 1);
+       newLoad = max_c(min_c(newLoad, kMaxLoad), 0);
+
+       measureActiveTime = 0;
+       measureTime = now;
+
+       deltaTime += kIntervalInaccuracy;
+       int n = deltaTime / kLoadMeasureInterval;
+       ASSERT(n > 0);
+
+       if (n > 10)
+               load = newLoad;
+       else {
+               newLoad *= (1 << n) - 1;
+               load = (load + newLoad) / (1 << n);
+               ASSERT(load >= 0 && load <= kMaxLoad);
+       }
+
+       return oldLoad;
+}
+
+
+#endif // _KERNEL_LOAD_TRACKING_H
diff --git a/src/system/kernel/arch/x86/32/descriptors.cpp 
b/src/system/kernel/arch/x86/32/descriptors.cpp
index 465aab7..d215dc0 100644
--- a/src/system/kernel/arch/x86/32/descriptors.cpp
+++ b/src/system/kernel/arch/x86/32/descriptors.cpp
@@ -311,7 +311,7 @@ x86_descriptors_init(kernel_args* args)
        set_trap_gate(0, 98, &trap98);  // for performance testing only
        set_trap_gate(0, 99, &trap99);  // syscall interrupt
 
-       reserve_io_interrupt_vectors(2, 98);
+       reserve_io_interrupt_vectors(2, 98, INTERRUPT_TYPE_SYSCALL);
 
        // configurable msi or msi-x interrupts
        set_interrupt_gate(0, 100, &trap100);
diff --git a/src/system/kernel/arch/x86/arch_smp.cpp 
b/src/system/kernel/arch/x86/arch_smp.cpp
index 8c2bc75..f9a56ba 100644
--- a/src/system/kernel/arch/x86/arch_smp.cpp
+++ b/src/system/kernel/arch/x86/arch_smp.cpp
@@ -90,7 +90,8 @@ arch_smp_init(kernel_args *args)
 
        if (args->num_cpus > 1) {
                // I/O interrupts start at ARCH_INTERRUPT_BASE, so all 
interrupts are shifted
-               reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE);
+               reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE,
+                       INTERRUPT_TYPE_ICI);
                install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, 
&x86_ici_interrupt, NULL, B_NO_LOCK_VECTOR);
                install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, 
&x86_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR);
                install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, 
&x86_spurious_interrupt, NULL, B_NO_LOCK_VECTOR);
diff --git a/src/system/kernel/arch/x86/ioapic.cpp 
b/src/system/kernel/arch/x86/ioapic.cpp
index 28d5ba8..87dd94c 100644
--- a/src/system/kernel/arch/x86/ioapic.cpp
+++ b/src/system/kernel/arch/x86/ioapic.cpp
@@ -774,7 +774,7 @@ ioapic_init(kernel_args* args)
        current = sIOAPICs;
        while (current != NULL) {
                reserve_io_interrupt_vectors(current->max_redirection_entry + 1,
-                       current->global_interrupt_base);
+                       current->global_interrupt_base, INTERRUPT_TYPE_IRQ);
                current = current->next;
        }
 
diff --git a/src/system/kernel/arch/x86/pic.cpp 
b/src/system/kernel/arch/x86/pic.cpp
index 7e08631..96cd171 100644
--- a/src/system/kernel/arch/x86/pic.cpp
+++ b/src/system/kernel/arch/x86/pic.cpp
@@ -231,7 +231,7 @@ pic_init()
 
        TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts));
 
-       reserve_io_interrupt_vectors(16, 0);
+       reserve_io_interrupt_vectors(16, 0, INTERRUPT_TYPE_EXCEPTION);
 
        // make the pic controller the current one
        arch_int_set_interrupt_controller(picController);
diff --git a/src/system/kernel/arch/x86/timers/x86_apic.cpp 
b/src/system/kernel/arch/x86/timers/x86_apic.cpp
index 3569e75..6ac3e59 100644
--- a/src/system/kernel/arch/x86/timers/x86_apic.cpp
+++ b/src/system/kernel/arch/x86/timers/x86_apic.cpp
@@ -106,7 +106,8 @@ apic_timer_init(struct kernel_args *args)
 
        sApicTicsPerSec = args->arch_args.apic_time_cv_factor;
 
-       reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE);
+       reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE,
+               INTERRUPT_TYPE_LOCAL_IRQ);
        install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE,
                &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
 
diff --git a/src/system/kernel/int.cpp b/src/system/kernel/int.cpp
index 6f9de63..df35b67 100644
--- a/src/system/kernel/int.cpp
+++ b/src/system/kernel/int.cpp
@@ -20,6 +20,7 @@
 #include <arch/int.h>
 #include <boot/kernel_args.h>
 #include <elf.h>
+#include <load_tracking.h>
 #include <util/AutoLock.h>
 #include <util/kqueue.h>
 #include <smp.h>
@@ -51,6 +52,13 @@ struct io_vector {
        spinlock                        vector_lock;
        int32                           enable_count;
        bool                            no_lock_vector;
+       interrupt_type          type;
+
+       spinlock                        load_lock;
+       bigtime_t                       last_measure_time;
+       bigtime_t                       last_measure_active;
+       int32                           load;
+
 #if DEBUG_INTERRUPTS
        int64                           handled_count;
        int64                           unhandled_count;
@@ -116,6 +124,29 @@ dump_int_statistics(int argc, char **argv)
 #endif
 
 
+static int
+dump_int_load(int argc, char** argv)
+{
+       static const char* typeNames[]
+               = { "exception", "irq", "local irq", "syscall", "ici", 
"unknown" };
+
+       for (int i = 0; i < NUM_IO_VECTORS; i++) {
+               if (!B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock)
+                       && sVectors[i].handler_list == NULL
+                       && sVectors[i].enable_count == 0)
+                       continue;
+
+               kprintf("int %3d, type %s, enabled %" B_PRId32 ", load %" 
B_PRId32
+                       "%%%s\n", i, typeNames[min_c(sVectors[i].type,
+                                       INTERRUPT_TYPE_UNKNOWN)],
+                       sVectors[i].enable_count, sVectors[i].load / 10,
+                       B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock) ? ", 
ACTIVE" : "");
+       }
+
+       return 0;
+}
+
+
 //     #pragma mark - private kernel API
 
 
@@ -145,6 +176,13 @@ int_init_post_vm(kernel_args* args)
                B_INITIALIZE_SPINLOCK(&sVectors[i].vector_lock);
                sVectors[i].enable_count = 0;
                sVectors[i].no_lock_vector = false;
+               sVectors[i].type = INTERRUPT_TYPE_UNKNOWN;
+
+               B_INITIALIZE_SPINLOCK(&sVectors[i].load_lock);
+               sVectors[i].last_measure_time = 0;
+               sVectors[i].last_measure_active = 0;
+               sVectors[i].load = 0;
+
 #if DEBUG_INTERRUPTS
                sVectors[i].handled_count = 0;
                sVectors[i].unhandled_count = 0;
@@ -159,6 +197,9 @@ int_init_post_vm(kernel_args* args)
                "list interrupt statistics");
 #endif
 
+       add_debugger_command("int_load", &dump_int_load,
+               "list interrupt usage statistics");
+
        return arch_int_init_post_vm(args);
 }
 
@@ -179,6 +220,17 @@ int_init_post_device_manager(kernel_args* args)
 }
 
 
+static void
+update_int_load(int i)
+{
+       if (!try_acquire_spinlock(&sVectors[i].load_lock))
+               return;
+       compute_load(sVectors[i].last_measure_time, 
sVectors[i].last_measure_active,
+               sVectors[i].load);
+       release_spinlock(&sVectors[i].load_lock);
+}
+
+
 /*!    Actually process an interrupt via the handlers registered for that
        vector (IRQ).
 */
@@ -189,6 +241,8 @@ int_io_interrupt_handler(int vector, bool levelTriggered)
        struct io_handler* io;
        bool handled = false;
 
+       bigtime_t start = system_time();
+
        if (!sVectors[vector].no_lock_vector)
                acquire_spinlock(&sVectors[vector].vector_lock);
 
@@ -267,6 +321,12 @@ int_io_interrupt_handler(int vector, bool levelTriggered)
        if (!sVectors[vector].no_lock_vector)
                release_spinlock(&sVectors[vector].vector_lock);
 
+       SpinLocker locker(sVectors[vector].load_lock);
+       sVectors[vector].last_measure_active += system_time() - start;
+       locker.Unlock();
+
+       update_int_load(vector);
+
        if (levelTriggered)
                return status;
 
@@ -435,7 +495,7 @@ remove_io_interrupt_handler(long vector, interrupt_handler 
handler, void *data)
        vectors using allocate_io_interrupt_vectors() instead.
 */
 status_t
-reserve_io_interrupt_vectors(long count, long startVector)
+reserve_io_interrupt_vectors(long count, long startVector, interrupt_type type)
 {
        MutexLocker locker(&sIOInterruptVectorAllocationLock);
 
@@ -448,6 +508,7 @@ reserve_io_interrupt_vectors(long count, long startVector)
                        return B_BUSY;
                }
 
+               sVectors[startVector + i].type = type;
                sAllocatedIOInterruptVectors[startVector + i] = true;
        }
 
diff --git a/src/system/kernel/scheduler/scheduler.cpp 
b/src/system/kernel/scheduler/scheduler.cpp
index d8a3d98..86760d5 100644
--- a/src/system/kernel/scheduler/scheduler.cpp
+++ b/src/system/kernel/scheduler/scheduler.cpp
@@ -23,6 +23,7 @@
 #include <kernel.h>
 #include <kscheduler.h>
 #include <listeners.h>
+#include <load_tracking.h>
 #include <scheduler_defs.h>
 #include <smp.h>
 #include <thread.h>
@@ -61,10 +62,9 @@ const bigtime_t kMinimalWaitTime = kThreadQuantum / 4;
 
 const bigtime_t kCacheExpire = 100000;
 
-const int kTargetLoad = 550;
-const int kHighLoad = 700;
-const int kMaxLoad = 1000;
-const int kLoadDifference = 200;
+const int kTargetLoad = kMaxLoad * 55 / 100;
+const int kHighLoad = kMaxLoad * 70 / 100;
+const int kLoadDifference = kMaxLoad * 20 / 100;
 
 static bigtime_t sDisableSmallTaskPacking;
 static int32 sSmallTaskCore;
@@ -924,50 +924,6 @@ should_rebalance(Thread* thread)
 }
 
 
-static inline int
-compute_load(bigtime_t& measureTime, bigtime_t& measureActiveTime, int32& load)
-{
-       const bigtime_t kLoadMeasureInterval = 50000;
-       const bigtime_t kIntervalInaccuracy = kLoadMeasureInterval / 4;
-
-       bigtime_t now = system_time();
-
-       if (measureTime == 0) {
-               measureTime = now;
-               return -1;
-       }
-
-       bigtime_t deltaTime = now - measureTime;
-
-       if (deltaTime < kLoadMeasureInterval)
-               return -1;
-
-       int oldLoad = load;
-       ASSERT(oldLoad >= 0 && oldLoad <= kMaxLoad);
-
-       int newLoad = measureActiveTime * kMaxLoad;
-       newLoad /= max_c(deltaTime, 1);
-       newLoad = max_c(min_c(newLoad, kMaxLoad), 0);
-
-       measureActiveTime = 0;
-       measureTime = now;
-
-       deltaTime += kIntervalInaccuracy;
-       int n = deltaTime / kLoadMeasureInterval;
-       ASSERT(n > 0);
-
-       if (n > 10)
-               load = newLoad;
-       else {
-               newLoad *= (1 << n) - 1;
-               load = (load + newLoad) / (1 << n);
-               ASSERT(load >= 0 && load <= kMaxLoad);
-       }
-
-       return oldLoad;
-}
-
-
 static inline void
 compute_cpu_load(int32 cpu)
 {

############################################################################

Commit:      955c7edec2e0d6f52e5245ce449804cede5de34b
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Nov 18 00:50:37 2013 UTC

kernel: Measure time spent in interrupt handlers

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h
index c1524b1..7d1dcd3 100644
--- a/headers/private/kernel/cpu.h
+++ b/headers/private/kernel/cpu.h
@@ -60,6 +60,8 @@ typedef struct cpu_ent {
 
        // keeping track of CPU activity
        bigtime_t               active_time;
+       bigtime_t               irq_time;
+       bigtime_t               interrupt_time;
        bigtime_t               last_kernel_time;
        bigtime_t               last_user_time;
 
diff --git a/src/system/kernel/int.cpp b/src/system/kernel/int.cpp
index df35b67..6e1b1fd 100644
--- a/src/system/kernel/int.cpp
+++ b/src/system/kernel/int.cpp
@@ -243,6 +243,10 @@ int_io_interrupt_handler(int vector, bool levelTriggered)
 
        bigtime_t start = system_time();
 
+       // exceptions and syscalls have their own handlers
+       ASSERT(sVectors[vector].type != INTERRUPT_TYPE_EXCEPTION
+               && sVectors[vector].type != INTERRUPT_TYPE_SYSCALL);
+
        if (!sVectors[vector].no_lock_vector)
                acquire_spinlock(&sVectors[vector].vector_lock);
 
@@ -322,9 +326,13 @@ int_io_interrupt_handler(int vector, bool levelTriggered)
                release_spinlock(&sVectors[vector].vector_lock);
 
        SpinLocker locker(sVectors[vector].load_lock);
-       sVectors[vector].last_measure_active += system_time() - start;
+       bigtime_t deltaTime = system_time() - start;
+       sVectors[vector].last_measure_active += deltaTime;
        locker.Unlock();
 
+       atomic_add64(&get_cpu_struct()->interrupt_time, deltaTime);
+       if (sVectors[vector].type == INTERRUPT_TYPE_IRQ)
+               atomic_add64(&get_cpu_struct()->irq_time, deltaTime);
        update_int_load(vector);
 
        if (levelTriggered)
diff --git a/src/system/kernel/system_info.cpp 
b/src/system/kernel/system_info.cpp
index a97cdca..d6a9fab 100644
--- a/src/system/kernel/system_info.cpp
+++ b/src/system/kernel/system_info.cpp
@@ -50,10 +50,12 @@ dump_info(int argc, char **argv)
                __VERSION__);
        kprintf("revision: %s\n\n", get_haiku_revision());
 
-       kprintf("cpu count: %" B_PRId32 ", active times:\n", 
smp_get_num_cpus());
+       kprintf("cpu count: %" B_PRId32 "\n", smp_get_num_cpus());
 
        for (int32 i = 0; i < smp_get_num_cpus(); i++)
-               kprintf("  [%" B_PRId32 "] %" B_PRId64 "\n", i + 1, 
gCPU[i].active_time);
+               kprintf("  [%" B_PRId32 "] active time: %12" B_PRId64 ", 
interrupt"
+                       " time: %12" B_PRId64 ", irq time: %12" B_PRId64 "\n", 
i + 1,
+                       gCPU[i].active_time, gCPU[i].interrupt_time, 
gCPU[i].irq_time);
 
        // ToDo: Add page_faults
        kprintf("pages:\t\t%" B_PRIuPHYSADDR " (%" B_PRIuPHYSADDR " max)\n",

############################################################################

Commit:      d897a478d7c01054aad29b23f7f545073c797530
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon Nov 18 03:55:25 2013 UTC

kernel: Allow reassigning IRQs to logical processors

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/arch/int.h 
b/headers/private/kernel/arch/int.h
index 9ebe6b0..6d4afc6 100644
--- a/headers/private/kernel/arch/int.h
+++ b/headers/private/kernel/arch/int.h
@@ -34,6 +34,7 @@ void arch_int_enable_io_interrupt(int irq);
 void arch_int_disable_io_interrupt(int irq);
 void arch_int_configure_io_interrupt(int irq, uint32 config);
 bool arch_int_are_interrupts_enabled(void);
+void arch_int_assign_to_cpu(int32 irq, int32 cpu);
 
 #ifdef __cplusplus
 }
diff --git a/headers/private/kernel/arch/x86/arch_int.h 
b/headers/private/kernel/arch/x86/arch_int.h
index da49437..5de0dcb 100644
--- a/headers/private/kernel/arch/x86/arch_int.h
+++ b/headers/private/kernel/arch/x86/arch_int.h
@@ -68,6 +68,7 @@ typedef struct interrupt_controller_s {
        bool    (*is_spurious_interrupt)(int32 num);
        bool    (*is_level_triggered_interrupt)(int32 num);
        bool    (*end_of_interrupt)(int32 num);
+       void    (*assign_interrupt_to_cpu)(int32 num, int32 cpu);
 } interrupt_controller;
 
 
diff --git a/headers/private/kernel/arch/x86/arch_smp.h 
b/headers/private/kernel/arch/x86/arch_smp.h
index 5b2d654..4eef8eb 100644
--- a/headers/private/kernel/arch/x86/arch_smp.h
+++ b/headers/private/kernel/arch/x86/arch_smp.h
@@ -99,4 +99,18 @@ enum {
        MP_INTR_TYPE_ExtINT,
 };
 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint32 x86_get_cpu_apic_id(int32 cpu);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
 #endif /* _KERNEL_ARCH_x86_ARCH_SMP_H */
diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h
index 7d1dcd3..4a70428 100644
--- a/headers/private/kernel/cpu.h
+++ b/headers/private/kernel/cpu.h
@@ -11,6 +11,7 @@
 
 #include <setjmp.h>
 
+#include <int.h>
 #include <smp.h>
 #include <timer.h>
 #include <arch/cpu.h>
@@ -79,8 +80,12 @@ typedef struct cpu_ent {
        int                             topology_id[CPU_TOPOLOGY_LEVELS];
        int                             cache_id[CPU_MAX_CACHE_LEVEL];
 
+       // IRQs assigned to this CPU
+       struct list             irqs;
+       spinlock                irqs_lock;
+
        // arch-specific stuff
-       arch_cpu_info arch;
+       arch_cpu_info   arch;
 } cpu_ent __attribute__((aligned(64)));
 
 
diff --git a/headers/private/kernel/int.h b/headers/private/kernel/int.h
index 215deb0..6922aa0 100644
--- a/headers/private/kernel/int.h
+++ b/headers/private/kernel/int.h
@@ -12,6 +12,8 @@
 #include <KernelExport.h>
 #include <arch/int.h>
 
+#include <util/list.h>
+
 // private install_io_interrupt_handler() flags
 #define B_NO_LOCK_VECTOR       0x100
 #define B_NO_HANDLED_INFO      0x200
@@ -28,6 +30,18 @@ enum interrupt_type {
        INTERRUPT_TYPE_UNKNOWN
 };
 
+struct irq_assignment {
+       list_link       link;
+       uint32          irq;
+
+       spinlock        load_lock;
+       bigtime_t       last_measure_time;
+       bigtime_t       last_measure_active;
+       int32           load;
+
+       int32           cpu;
+};
+
 
 #ifdef __cplusplus
 extern "C" {
@@ -68,4 +82,6 @@ status_t reserve_io_interrupt_vectors(long count, long 
startVector,
 status_t allocate_io_interrupt_vectors(long count, long *startVector);
 void free_io_interrupt_vectors(long count, long startVector);
 
+void assign_io_interrupt_to_cpu(long vector, int32 cpu);
+
 #endif /* _KERNEL_INT_H */
diff --git a/src/system/kernel/arch/x86/arch_int.cpp 
b/src/system/kernel/arch/x86/arch_int.cpp
index 3591f90..abcaf5f 100644
--- a/src/system/kernel/arch/x86/arch_int.cpp
+++ b/src/system/kernel/arch/x86/arch_int.cpp
@@ -389,6 +389,14 @@ arch_int_are_interrupts_enabled(void)
 }
 
 
+void
+arch_int_assign_to_cpu(int32 irq, int32 cpu)
+{
+       if (sCurrentPIC->assign_interrupt_to_cpu != NULL)
+               sCurrentPIC->assign_interrupt_to_cpu(irq, cpu);
+}
+
+
 status_t
 arch_int_init(kernel_args* args)
 {
diff --git a/src/system/kernel/arch/x86/arch_smp.cpp 
b/src/system/kernel/arch/x86/arch_smp.cpp
index f9a56ba..340854b 100644
--- a/src/system/kernel/arch/x86/arch_smp.cpp
+++ b/src/system/kernel/arch/x86/arch_smp.cpp
@@ -70,6 +70,14 @@ x86_smp_error_interrupt(void *data)
 }
 
 
+uint32
+x86_get_cpu_apic_id(int32 cpu)
+{
+       ASSERT(cpu >= 0 && cpu < B_MAX_CPU_COUNT);
+       return sCPUAPICIds[cpu];
+}
+
+
 status_t
 arch_smp_init(kernel_args *args)
 {
diff --git a/src/system/kernel/arch/x86/ioapic.cpp 
b/src/system/kernel/arch/x86/ioapic.cpp
index 87dd94c..3f6c544 100644
--- a/src/system/kernel/arch/x86/ioapic.cpp
+++ b/src/system/kernel/arch/x86/ioapic.cpp
@@ -18,6 +18,7 @@
 
 #include <arch/x86/apic.h>
 #include <arch/x86/arch_int.h>
+#include <arch/x86/arch_smp.h>
 #include <arch/x86/pic.h>
 
 // to gain access to the ACPICA types
@@ -26,9 +27,9 @@
 
 //#define TRACE_IOAPIC
 #ifdef TRACE_IOAPIC
-#      define TRACE(x) dprintf x
+#      define TRACE(...) dprintf(__VA_ARGS__)
 #else
-#      define TRACE(x) ;
+#      define TRACE(...) (void)0
 #endif
 
 
@@ -243,6 +244,30 @@ ioapic_end_of_interrupt(int32 num)
 
 
 static void
+ioapic_assign_interrupt_to_cpu(int32 gsi, int32 cpu)
+{
+       if (gsi < ISA_INTERRUPT_COUNT && sSourceOverrides[gsi] != 0)
+               gsi = sSourceOverrides[gsi];
+
+       struct ioapic* ioapic = find_ioapic(gsi);
+       if (ioapic == NULL)
+               return;
+
+       uint32 apicid = x86_get_cpu_apic_id(cpu);
+
+       uint8 pin = gsi - ioapic->global_interrupt_base;
+       TRACE("ioapic_assign_interrupt_to_cpu: gsi %ld (io-apic %u pin %u) to"
+               " cpu %ld (apic_id %lu)\n", gsi, ioapic->number, pin, cpu, 
apicid);
+
+       uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin 
* 2);
+       entry &= ~(uint64(IO_APIC_DESTINATION_FIELD_MASK)
+                       << IO_APIC_DESTINATION_FIELD_SHIFT);
+       entry |= uint64(apicid) << IO_APIC_DESTINATION_FIELD_SHIFT;
+       ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, 
false);
+}
+
+
+static void
 ioapic_enable_io_interrupt(int32 gsi)
 {
        // If enabling an overriden source is attempted, enable the override 
entry
@@ -256,8 +281,8 @@ ioapic_enable_io_interrupt(int32 gsi)
                return;
 
        uint8 pin = gsi - ioapic->global_interrupt_base;
-       TRACE(("ioapic_enable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
-               gsi, ioapic->number, pin));
+       TRACE("ioapic_enable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
+               gsi, ioapic->number, pin);
 
        uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin 
* 2);
        entry &= ~IO_APIC_INTERRUPT_MASKED;
@@ -273,8 +298,8 @@ ioapic_disable_io_interrupt(int32 gsi)
                return;
 
        uint8 pin = gsi - ioapic->global_interrupt_base;
-       TRACE(("ioapic_disable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
-               gsi, ioapic->number, pin));
+       TRACE("ioapic_disable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
+               gsi, ioapic->number, pin);
 
        uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin 
* 2);
        entry |= IO_APIC_INTERRUPT_MASKED;
@@ -290,8 +315,8 @@ ioapic_configure_io_interrupt(int32 gsi, uint32 config)
                return;
 
        uint8 pin = gsi - ioapic->global_interrupt_base;
-       TRACE(("ioapic_configure_io_interrupt: gsi %ld -> io-apic %u pin %u; "
-               "config 0x%08lx\n", gsi, ioapic->number, pin, config));
+       TRACE("ioapic_configure_io_interrupt: gsi %ld -> io-apic %u pin %u; "
+               "config 0x%08lx\n", gsi, ioapic->number, pin, config);
 
        ioapic_configure_pin(*ioapic, pin, gsi, config,
                IO_APIC_DELIVERY_MODE_FIXED);
@@ -310,7 +335,7 @@ ioapic_map_ioapic(struct ioapic& ioapic, phys_addr_t 
physicalAddress)
                return ioapic.register_area;
        }
 
-       TRACE(("mapped io-apic %u to %p\n", ioapic.number, ioapic.registers));
+       TRACE("mapped io-apic %u to %p\n", ioapic.number, ioapic.registers);
 
        ioapic.version = ioapic_read_32(ioapic, IO_APIC_VERSION);
        if (ioapic.version == 0xffffffff) {
@@ -650,7 +675,8 @@ ioapic_init(kernel_args* args)
                &ioapic_configure_io_interrupt,
                &ioapic_is_spurious_interrupt,
                &ioapic_is_level_triggered_interrupt,
-               &ioapic_end_of_interrupt
+               &ioapic_end_of_interrupt,
+               &ioapic_assign_interrupt_to_cpu,
        };
 
        if (args->arch_args.apic == NULL)
diff --git a/src/system/kernel/arch/x86/pic.cpp 
b/src/system/kernel/arch/x86/pic.cpp
index 96cd171..a802ff3 100644
--- a/src/system/kernel/arch/x86/pic.cpp
+++ b/src/system/kernel/arch/x86/pic.cpp
@@ -196,7 +196,8 @@ pic_init()
                &pic_configure_io_interrupt,
                &pic_is_spurious_interrupt,
                &pic_is_level_triggered_interrupt,
-               &pic_end_of_interrupt
+               &pic_end_of_interrupt,
+               NULL
        };
 
        // Start initialization sequence for the master and slave PICs
diff --git a/src/system/kernel/cpu.cpp b/src/system/kernel/cpu.cpp
index b98ad77..433d567 100644
--- a/src/system/kernel/cpu.cpp
+++ b/src/system/kernel/cpu.cpp
@@ -99,6 +99,9 @@ cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
        memset(&gCPU[curr_cpu], 0, sizeof(gCPU[curr_cpu]));
        gCPU[curr_cpu].cpu_num = curr_cpu;
 
+       list_init(&gCPU[curr_cpu].irqs);
+       B_INITIALIZE_SPINLOCK(&gCPU[curr_cpu].irqs_lock);
+
        return arch_cpu_preboot_init_percpu(args, curr_cpu);
 }
 
diff --git a/src/system/kernel/int.cpp b/src/system/kernel/int.cpp
index 6e1b1fd..cfea6fe 100644
--- a/src/system/kernel/int.cpp
+++ b/src/system/kernel/int.cpp
@@ -1,4 +1,7 @@
 /*
+ * Copyright 2013, Paweł Dziepak, pdziepak@xxxxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+
  * Copyright 2011, Michael Lotz, mmlr@xxxxxxxx.
  * Distributed under the terms of the MIT License.
  *
@@ -54,10 +57,7 @@ struct io_vector {
        bool                            no_lock_vector;
        interrupt_type          type;
 
-       spinlock                        load_lock;
-       bigtime_t                       last_measure_time;
-       bigtime_t                       last_measure_active;
-       int32                           load;
+       irq_assignment          assigned_cpu;
 
 #if DEBUG_INTERRUPTS
        int64                           handled_count;
@@ -67,6 +67,7 @@ struct io_vector {
 #endif
 };
 
+static uint32 sLastCPU;
 static struct io_vector sVectors[NUM_IO_VECTORS];
 static bool sAllocatedIOInterruptVectors[NUM_IO_VECTORS];
 static mutex sIOInterruptVectorAllocationLock
@@ -137,10 +138,20 @@ dump_int_load(int argc, char** argv)
                        continue;
 
                kprintf("int %3d, type %s, enabled %" B_PRId32 ", load %" 
B_PRId32
-                       "%%%s\n", i, typeNames[min_c(sVectors[i].type,
+                       "%%", i, typeNames[min_c(sVectors[i].type,
                                        INTERRUPT_TYPE_UNKNOWN)],
-                       sVectors[i].enable_count, sVectors[i].load / 10,
-                       B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock) ? ", 
ACTIVE" : "");
+                       sVectors[i].enable_count, sVectors[i].assigned_cpu.load 
/ 10);
+
+               if (sVectors[i].type == INTERRUPT_TYPE_IRQ) {
+                       if (sVectors[i].assigned_cpu.cpu != -1)
+                               kprintf(", cpu %" B_PRId32, 
sVectors[i].assigned_cpu.cpu);
+                       else
+                               kprintf(", cpu -");
+               }
+
+               if (B_SPINLOCK_IS_LOCKED(&sVectors[i].vector_lock))
+                       kprintf(", ACTIVE");
+               kprintf("\n");
        }
 
        return 0;
@@ -178,10 +189,15 @@ int_init_post_vm(kernel_args* args)
                sVectors[i].no_lock_vector = false;
                sVectors[i].type = INTERRUPT_TYPE_UNKNOWN;
 
-               B_INITIALIZE_SPINLOCK(&sVectors[i].load_lock);
-               sVectors[i].last_measure_time = 0;
-               sVectors[i].last_measure_active = 0;
-               sVectors[i].load = 0;
+               irq_assignment* assigned_cpu = &sVectors[i].assigned_cpu;
+               assigned_cpu->irq = i;
+
+               B_INITIALIZE_SPINLOCK(&assigned_cpu->load_lock);
+               assigned_cpu->last_measure_time = 0;
+               assigned_cpu->last_measure_active = 0;
+               assigned_cpu->load = 0;
+
+               assigned_cpu->cpu = -1;
 
 #if DEBUG_INTERRUPTS
                sVectors[i].handled_count = 0;
@@ -223,11 +239,14 @@ int_init_post_device_manager(kernel_args* args)
 static void
 update_int_load(int i)
 {
-       if (!try_acquire_spinlock(&sVectors[i].load_lock))
+       if (!try_acquire_spinlock(&sVectors[i].assigned_cpu.load_lock))
                return;
-       compute_load(sVectors[i].last_measure_time, 
sVectors[i].last_measure_active,
-               sVectors[i].load);
-       release_spinlock(&sVectors[i].load_lock);
+
+       compute_load(sVectors[i].assigned_cpu.last_measure_time,
+               sVectors[i].assigned_cpu.last_measure_active,
+               sVectors[i].assigned_cpu.load);
+
+       release_spinlock(&sVectors[i].assigned_cpu.load_lock);
 }
 
 
@@ -325,9 +344,9 @@ int_io_interrupt_handler(int vector, bool levelTriggered)
        if (!sVectors[vector].no_lock_vector)
                release_spinlock(&sVectors[vector].vector_lock);
 
-       SpinLocker locker(sVectors[vector].load_lock);
+       SpinLocker locker(sVectors[vector].assigned_cpu.load_lock);
        bigtime_t deltaTime = system_time() - start;
-       sVectors[vector].last_measure_active += deltaTime;
+       sVectors[vector].assigned_cpu.last_measure_active += deltaTime;
        locker.Unlock();
 
        atomic_add64(&get_cpu_struct()->interrupt_time, deltaTime);
@@ -402,6 +421,23 @@ install_io_interrupt_handler(long vector, 
interrupt_handler handler, void *data,
        state = disable_interrupts();
        acquire_spinlock(&sVectors[vector].vector_lock);
 
+       // Initial attempt to balance IRQs, the scheduler will correct this
+       // if some cores end up being overloaded.
+       if (sVectors[vector].type == INTERRUPT_TYPE_IRQ
+               && sVectors[vector].handler_list == NULL) {
+
+               int32 cpuID = atomic_add(&sLastCPU, 1) % smp_get_num_cpus();
+               arch_int_assign_to_cpu(vector, cpuID);
+
+               ASSERT(sVectors[vector].assigned_cpu.cpu == -1);
+
+               sVectors[vector].assigned_cpu.cpu = cpuID;
+
+               cpu_ent* cpu = &gCPU[cpuID];
+               SpinLocker _(cpu->irqs_lock);
+               list_add_item(&cpu->irqs, &sVectors[vector].assigned_cpu);
+       }
+
        if ((flags & B_NO_HANDLED_INFO) != 0
                && sVectors[vector].handler_list != NULL) {
                // The driver registering this interrupt handler doesn't know
@@ -441,6 +477,7 @@ install_io_interrupt_handler(long vector, interrupt_handler 
handler, void *data,
                sVectors[vector].no_lock_vector = true;
 
        release_spinlock(&sVectors[vector].vector_lock);
+
        restore_interrupts(state);
 
        return B_OK;
@@ -486,6 +523,28 @@ remove_io_interrupt_handler(long vector, interrupt_handler 
handler, void *data)
                last = io;
        }
 
+       if (sVectors[vector].handler_list == NULL
+               && sVectors[vector].type == INTERRUPT_TYPE_IRQ) {
+
+               int32 oldCPU;
+               SpinLocker locker;
+               cpu_ent* cpu;
+
+               do {
+                       locker.Unlock();
+
+                       oldCPU = sVectors[vector].assigned_cpu.cpu;
+
+                       ASSERT(oldCPU != -1);
+                       cpu = &gCPU[oldCPU];
+
+                       locker.SetTo(cpu->irqs_lock, false);
+               } while (sVectors[vector].assigned_cpu.cpu != oldCPU);
+
+               sVectors[vector].assigned_cpu.cpu = -1;
+               list_remove_item(&cpu->irqs, &sVectors[vector].assigned_cpu);
+       }
+
        release_spinlock(&sVectors[vector].vector_lock);
        restore_interrupts(state);
 
@@ -596,3 +655,27 @@ free_io_interrupt_vectors(long count, long startVector)
                sAllocatedIOInterruptVectors[startVector + i] = false;
        }
 }
+
+
+void assign_io_interrupt_to_cpu(long vector, int32 newCPU)
+{
+       ASSERT(sVectors[vector].type == INTERRUPT_TYPE_IRQ);
+
+       int32 oldCPU = sVectors[vector].assigned_cpu.cpu;
+
+       ASSERT(oldCPU != -1);
+       cpu_ent* cpu = &gCPU[oldCPU];
+
+       SpinLocker locker(cpu->irqs_lock);
+       sVectors[vector].assigned_cpu.cpu = -1;
+       list_remove_item(&cpu->irqs, &sVectors[vector].assigned_cpu);
+       locker.Unlock();
+
+       cpu = &gCPU[newCPU];
+       locker.SetTo(cpu->irqs_lock, false);
+       sVectors[vector].assigned_cpu.cpu = newCPU;
+       arch_int_assign_to_cpu(vector, newCPU);
+       list_add_item(&cpu->irqs, &sVectors[vector].assigned_cpu);
+       locker.Unlock();
+}
+
diff --git a/src/system/kernel/system_info.cpp 
b/src/system/kernel/system_info.cpp
index d6a9fab..d6713b0 100644
--- a/src/system/kernel/system_info.cpp
+++ b/src/system/kernel/system_info.cpp
@@ -53,8 +53,8 @@ dump_info(int argc, char **argv)
        kprintf("cpu count: %" B_PRId32 "\n", smp_get_num_cpus());
 
        for (int32 i = 0; i < smp_get_num_cpus(); i++)
-               kprintf("  [%" B_PRId32 "] active time: %12" B_PRId64 ", 
interrupt"
-                       " time: %12" B_PRId64 ", irq time: %12" B_PRId64 "\n", 
i + 1,
+               kprintf("  [%" B_PRId32 "] active time: %10" B_PRId64 ", 
interrupt"
+                       " time: %10" B_PRId64 ", irq time: %10" B_PRId64 "\n", 
i + 1,
                        gCPU[i].active_time, gCPU[i].interrupt_time, 
gCPU[i].irq_time);
 
        // ToDo: Add page_faults


Other related posts:

  • » [haiku-commits] BRANCH pdziepak-github.scheduler [d897a47] src/system/kernel src/system/kernel/arch/x86 headers/private/kernel src/system/kernel/scheduler - pdziepak-github . scheduler