/* * Hiperdispatch: * Dynamically calculates the optimum number of high capacity COREs * by considering the state the system is in. When hiperdispatch decides * that a capacity update is necessary, it schedules a topology update. * During topology updates the CPU capacities are always re-adjusted. * * There is two places where CPU capacities are being accessed within * hiperdispatch. * -> hiperdispatch's reoccuring work function reads CPU capacities to * determine high capacity CPU count. * -> during a topology update hiperdispatch's adjustment function * updates CPU capacities. * These two can run on different CPUs in parallel which can cause * hiperdispatch to make wrong decisions. This can potentially cause * some overhead by leading to extra rebuild_sched_domains() calls * for correction. Access to capacities within hiperdispatch has to be * serialized to prevent the overhead. * * Hiperdispatch decision making revolves around steal time. * HD_STEAL_THRESHOLD value is taken as reference. Whenever steal time * crosses the threshold value hiperdispatch falls back to giving high * capacities to entitled CPUs. When steal time drops below the * threshold boundary, hiperdispatch utilizes all CPUs by giving all * of them high capacity. * * The theory behind HD_STEAL_THRESHOLD is related to the SMP thread * performance. Comparing the throughput of; * - single CORE, with N threads, running N tasks * - N separate COREs running N tasks, * using individual COREs for individual tasks yield better * performance. This performance difference is roughly ~30% (can change * between machine generations) * * Hiperdispatch tries to hint scheduler to use individual COREs for * each task, as long as steal time on those COREs are less than 30%, * therefore delaying the throughput loss caused by using SMP threads.
*/
static cpumask_t hd_vl_coremask; /* Mask containing all vertical low COREs */ static cpumask_t hd_vmvl_cpumask; /* Mask containing vertical medium and low CPUs */ staticint hd_high_capacity_cores; /* Current CORE count with high capacity */ staticint hd_entitled_cores; /* Total vertical high and medium CORE count */ staticint hd_online_cores; /* Current online CORE count */
staticunsignedlong hd_previous_steal; /* Previous iteration's CPU steal timer total */ staticunsignedlong hd_high_time; /* Total time spent while all cpus have high capacity */ staticunsignedlong hd_low_time; /* Total time spent while vl cpus have low capacity */ static atomic64_t hd_adjustments; /* Total occurrence count of hiperdispatch adjustments */
/* * Check if hiperdispatch is active, if not set the prev to 0. * This way it is possible to differentiate the first update iteration after * enabling hiperdispatch.
*/ if (hd_entitled_cores == 0 || hd_enabled == 0) {
prev = ktime_set(0, 0); return;
}
now = ktime_get(); if (ktime_after(prev, 0)) { if (hd_high_capacity_cores == hd_online_cores)
hd_high_time += ktime_ms_delta(now, prev); else
hd_low_time += ktime_ms_delta(now, prev);
}
prev = now;
}
staticvoid hd_update_capacities(void)
{ int cpu, upscaling_cores; unsignedlong capacity;
mutex_lock(&smp_cpu_state_mutex); /* * If online cores are less or equal to entitled cores hiperdispatch * does not need to make any adjustments, call a topology update to * disable hiperdispatch. * Normally this check is handled on topology update, but during cpu * unhotplug, topology and cpu mask updates are done in reverse * order, causing hd_enable_hiperdispatch() to get stale data.
*/ if (hd_online_cores <= hd_entitled_cores) {
topology_schedule_update();
mutex_unlock(&smp_cpu_state_mutex); return;
}
steal_percentage = hd_steal_avg(hd_calculate_steal_percentage()); if (steal_percentage < hd_steal_threshold)
new_cores = hd_online_cores; else
new_cores = hd_entitled_cores; if (hd_high_capacity_cores != new_cores) {
trace_s390_hd_rebuild_domains(hd_high_capacity_cores, new_cores);
hd_high_capacity_cores = new_cores;
atomic64_inc(&hd_adjustments);
topology_schedule_update();
}
trace_s390_hd_work_fn(steal_percentage, hd_entitled_cores, hd_high_capacity_cores);
mutex_unlock(&smp_cpu_state_mutex);
schedule_delayed_work(&hd_capacity_work, HD_DELAY_INTERVAL);
}
dev = bus_get_dev_root(&cpu_subsys); if (!dev) return; if (sysfs_create_group(&dev->kobj, &hd_attr_group))
pr_warn("Unable to create hiperdispatch attribute group\n");
put_device(dev);
}
staticint __init hd_init(void)
{ if (IS_ENABLED(CONFIG_HIPERDISPATCH_ON)) {
hd_set_hiperdispatch_mode(1);
topology_schedule_update();
} if (!register_sysctl("s390", hiperdispatch_ctl_table))
pr_warn("Failed to register s390.hiperdispatch sysctl attribute\n");
hd_create_debugfs_counters();
hd_create_attributes(); return 0;
}
late_initcall(hd_init);
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.