diff options
author | John M. Calandrino <jmc@jupiter-cs.cs.unc.edu> | 2007-02-09 14:32:01 -0500 |
---|---|---|
committer | John M. Calandrino <jmc@jupiter-cs.cs.unc.edu> | 2007-02-09 14:32:01 -0500 |
commit | 372757f9ec10a83c6663955ae5bf7c5c18e204e7 (patch) | |
tree | a7d9396b96e99903c6ac3301b20a649e778fb32c /arch/i386 | |
parent | 9da64b82a7b271b695ee3d392fe2e7738c6d75ee (diff) |
Added support for periodic resynchronization of aligned quanta.
Support added with some small modifications. Staggered quanta are still
synchronized only once, it might not be necessary to re-stagger quanta
at all. This seems to be running okay but is not guaranteed to be bug-free,
and still needs to be checked for alignment accuracy.
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/apic.c | 69 |
1 files changed, 38 insertions, 31 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 7ffc2fb9a3..1df9229e20 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c | |||
@@ -1198,24 +1198,29 @@ EXPORT_SYMBOL(switch_ipi_to_APIC_timer); | |||
1198 | #undef APIC_DIVISOR | 1198 | #undef APIC_DIVISOR |
1199 | 1199 | ||
1200 | /* JOHN: Begin added code, starting with quantum sync function. */ | 1200 | /* JOHN: Begin added code, starting with quantum sync function. */ |
1201 | #define STAGGER 1 | 1201 | #define STAGGER 0 |
1202 | #define WAIT_TO_SYNC 30000 /* 30s after boot (later: between syncs?) */ | 1202 | #define WAIT_TO_SYNC 30000 /* time between syncs and before 1st sync */ |
1203 | #define QSYNC_TIME (INITIAL_JIFFIES+msecs_to_jiffies(WAIT_TO_SYNC)) | 1203 | static atomic_t qsync_time = ATOMIC_INIT(INITIAL_JIFFIES); |
1204 | /* later: change from define to variable, update? */ | ||
1205 | static atomic_t quantum_sync_barrier = ATOMIC_INIT(0); | 1204 | static atomic_t quantum_sync_barrier = ATOMIC_INIT(0); |
1206 | /* used to implement simple barrier */ | 1205 | static atomic_t barrier_use_count = ATOMIC_INIT(1); |
1207 | static DEFINE_PER_CPU(int, synched) = 0; | 1206 | static atomic_t sync_done = ATOMIC_INIT(0); |
1208 | 1207 | ||
1209 | /* | 1208 | /* |
1210 | * This function is called to align all quanta, and to stagger quanta if | 1209 | * This function is called to align all quanta, and to stagger quanta if |
1211 | * necessary. It relies on a barrier to synchronize all processors, so | 1210 | * necessary. It relies on a barrier to synchronize all processors, so |
1212 | * that they all reset their APIC timers at the same time. | 1211 | * that they all reset their APIC timers at the same time. If quanta |
1212 | * should be staggered, the appropriate stagger delay is then added at | ||
1213 | * each processor. Staggered quanta are synchronized only once (it is | ||
1214 | * only important that quanta remain relatively misaligned, not that they | ||
1215 | * remain equally spaced forever). Aligned quanta, however, are | ||
1216 | * periodically realigned, which in most cases should not result | ||
1217 | * in substantial timing issues after the first alignment. | ||
1213 | */ | 1218 | */ |
1214 | void synchronize_quanta(void) | 1219 | void synchronize_quanta(void) |
1215 | { | 1220 | { |
1216 | int cpu = smp_processor_id(); | 1221 | int cpu = smp_processor_id(); |
1217 | int total_cpus = num_online_cpus(); | 1222 | int total_cpus = num_online_cpus(); |
1218 | int stagger_interval = jiffies_to_usecs(1)/total_cpus; | 1223 | int stagger_interval = jiffies_to_usecs(1) / total_cpus; |
1219 | 1224 | ||
1220 | /* | 1225 | /* |
1221 | * Disable APIC timer, wait for all other processors to reach barrier, | 1226 | * Disable APIC timer, wait for all other processors to reach barrier, |
@@ -1223,7 +1228,8 @@ void synchronize_quanta(void) | |||
1223 | */ | 1228 | */ |
1224 | disable_APIC_timer(); | 1229 | disable_APIC_timer(); |
1225 | atomic_inc(&quantum_sync_barrier); | 1230 | atomic_inc(&quantum_sync_barrier); |
1226 | while (atomic_read(&quantum_sync_barrier) < total_cpus) | 1231 | while (atomic_read(&quantum_sync_barrier) < |
1232 | atomic_read(&barrier_use_count) * total_cpus) | ||
1227 | { | 1233 | { |
1228 | /* Delay, otherwise atomic_inc's cannot occur. */ | 1234 | /* Delay, otherwise atomic_inc's cannot occur. */ |
1229 | udelay(1); | 1235 | udelay(1); |
@@ -1231,17 +1237,26 @@ void synchronize_quanta(void) | |||
1231 | __setup_APIC_LVTT(calibration_result); | 1237 | __setup_APIC_LVTT(calibration_result); |
1232 | enable_APIC_timer(); | 1238 | enable_APIC_timer(); |
1233 | 1239 | ||
1234 | /* Add necessary stagger for this CPU, if required. */ | 1240 | /* |
1241 | * Add necessary stagger for this CPU, if required. Do _not_ | ||
1242 | * update qsync_time. Otherwise, we update the qsync_time | ||
1243 | * and increment the barrier count, which allows the barrier to | ||
1244 | * be "reused" (at least, until overflow occurs in roughly X*2^29 | ||
1245 | * seconds, or roughly X*17 years -- for a 30 second wait interval, | ||
1246 | * this means 510 years until overflow, which seems safe). | ||
1247 | */ | ||
1235 | if (STAGGER) { | 1248 | if (STAGGER) { |
1236 | int stagger_us = cpu*stagger_interval; | 1249 | int stagger_us = cpu * stagger_interval; |
1237 | disable_APIC_timer(); | 1250 | disable_APIC_timer(); |
1238 | udelay(stagger_us); | 1251 | udelay(stagger_us); |
1239 | __setup_APIC_LVTT(calibration_result); | 1252 | __setup_APIC_LVTT(calibration_result); |
1240 | enable_APIC_timer(); | 1253 | enable_APIC_timer(); |
1254 | atomic_inc(&sync_done); | ||
1255 | } else if (cpu == 0) { | ||
1256 | /* The first CPU updates qsync_time and "resets" barrier */ | ||
1257 | atomic_add(msecs_to_jiffies(WAIT_TO_SYNC), &qsync_time); | ||
1258 | atomic_inc(&barrier_use_count); | ||
1241 | } | 1259 | } |
1242 | |||
1243 | /* Set "synched" flag so this code is not executed again. */ | ||
1244 | per_cpu(synched, cpu) = 1; | ||
1245 | } | 1260 | } |
1246 | /* JOHN: end added code. */ | 1261 | /* JOHN: end added code. */ |
1247 | 1262 | ||
@@ -1257,10 +1272,6 @@ void synchronize_quanta(void) | |||
1257 | 1272 | ||
1258 | inline void smp_local_timer_interrupt(void) | 1273 | inline void smp_local_timer_interrupt(void) |
1259 | { | 1274 | { |
1260 | /* JOHN: begin added code. */ | ||
1261 | int cpu = smp_processor_id(); | ||
1262 | /* JOHN: end added code. */ | ||
1263 | |||
1264 | profile_tick(CPU_PROFILING); | 1275 | profile_tick(CPU_PROFILING); |
1265 | #ifdef CONFIG_SMP | 1276 | #ifdef CONFIG_SMP |
1266 | update_process_times(user_mode_vm(get_irq_regs())); | 1277 | update_process_times(user_mode_vm(get_irq_regs())); |
@@ -1268,23 +1279,19 @@ inline void smp_local_timer_interrupt(void) | |||
1268 | 1279 | ||
1269 | /* JOHN: begin added code. | 1280 | /* JOHN: begin added code. |
1270 | * | 1281 | * |
1271 | * Synchronize quanta, if it hasn't been done already. | 1282 | * Synchronize quanta if we have reached qsync_time plus wait |
1272 | * To keep the interrupt handler code as efficient as possible | 1283 | * interval. For staggered quanta, this only happens once, |
1273 | * in the common case, we check a flag and only check the | 1284 | * i.e., sync_done is only set in the staggered case. For aligned |
1274 | * jiffy count if the flag is not set. When the jiffy count is | 1285 | * quanta, this value is updated so that realignments |
1275 | * high enough to ensure that all local APIC timers are | 1286 | * occur periodically. |
1276 | * up and running, as indicated by reaching QSYNC_TIME, | ||
1277 | * the synchronization occurs, and the flag is set so we never enter | ||
1278 | * this code again (unless this is changed so that quanta are | ||
1279 | * periodically re-synchronized?). | ||
1280 | * The synchronization code itself is placed in its own | 1287 | * The synchronization code itself is placed in its own |
1281 | * (non-inline) function, to avoid issues with creating an inline | 1288 | * (non-inline) function, to avoid issues with creating an inline |
1282 | * function that is too large. | 1289 | * function that is too large. |
1283 | */ | 1290 | */ |
1284 | if (unlikely(!per_cpu(synched, cpu))) { | 1291 | if (unlikely(!atomic_read(&sync_done) && |
1285 | if (jiffies > QSYNC_TIME) { | 1292 | jiffies > atomic_read(&qsync_time) + |
1286 | synchronize_quanta(); | 1293 | msecs_to_jiffies(WAIT_TO_SYNC))) { |
1287 | } | 1294 | synchronize_quanta(); |
1288 | } | 1295 | } |
1289 | /* JOHN: end added code. */ | 1296 | /* JOHN: end added code. */ |
1290 | 1297 | ||