Loading drivers/devfreq/arm-memlat-mon.c +90 −73 Original line number Diff line number Diff line Loading @@ -47,22 +47,32 @@ struct event_data { unsigned long prev_count; }; struct memlat_hwmon_data { struct cpu_pmu_stats { struct event_data events[NUM_EVENTS]; ktime_t prev_ts; bool init_pending; unsigned long cache_miss_event; unsigned long inst_event; }; static DEFINE_PER_CPU(struct memlat_hwmon_data, pm_data); struct cpu_grp_info { cpumask_t cpus; cpumask_t inited_cpus; unsigned long cache_miss_event; unsigned long inst_event; struct cpu_pmu_stats *cpustats; struct memlat_hwmon hw; struct notifier_block arm_memlat_cpu_notif; struct list_head mon_list; }; static unsigned long compute_freq(struct memlat_hwmon_data *hw_data, #define to_cpustats(cpu_grp, cpu) \ (&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)]) #define to_devstats(cpu_grp, cpu) \ (&cpu_grp->hw.core_stats[cpu - cpumask_first(&cpu_grp->cpus)]) #define to_cpu_grp(hwmon) container_of(hwmon, struct cpu_grp_info, hw) static LIST_HEAD(memlat_mon_list); static DEFINE_MUTEX(list_lock); static unsigned long compute_freq(struct cpu_pmu_stats *cpustats, unsigned long cyc_cnt) { ktime_t ts; Loading @@ -70,10 +80,10 @@ static unsigned long compute_freq(struct memlat_hwmon_data *hw_data, unsigned long freq = 0; ts = ktime_get(); diff = ktime_to_us(ktime_sub(ts, hw_data->prev_ts)); diff = ktime_to_us(ktime_sub(ts, cpustats->prev_ts)); if (!diff) diff = 1; hw_data->prev_ts = ts; cpustats->prev_ts = ts; freq = cyc_cnt; do_div(freq, diff); Loading @@ -99,69 +109,59 @@ static inline unsigned long read_event(struct event_data *event) static void read_perf_counters(int cpu, struct cpu_grp_info *cpu_grp) { int cpu_idx; struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu); struct memlat_hwmon *hw = &cpu_grp->hw; struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); struct dev_stats *devstats = to_devstats(cpu_grp, cpu); unsigned long cyc_cnt; if (hw_data->init_pending) return; cpu_idx = cpu - cpumask_first(&cpu_grp->cpus); hw->core_stats[cpu_idx].inst_count = read_event(&hw_data->events[INST_IDX]); hw->core_stats[cpu_idx].mem_count = read_event(&hw_data->events[CM_IDX]); cyc_cnt = read_event(&hw_data->events[CYC_IDX]); hw->core_stats[cpu_idx].freq = compute_freq(hw_data, cyc_cnt); devstats->inst_count = read_event(&cpustats->events[INST_IDX]); devstats->mem_count = read_event(&cpustats->events[CM_IDX]); cyc_cnt = read_event(&cpustats->events[CYC_IDX]); devstats->freq = compute_freq(cpustats, cyc_cnt); } static unsigned long get_cnt(struct memlat_hwmon *hw) { int cpu; struct cpu_grp_info *cpu_grp = container_of(hw, struct cpu_grp_info, hw); struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); for_each_cpu(cpu, &cpu_grp->cpus) for_each_cpu(cpu, &cpu_grp->inited_cpus) read_perf_counters(cpu, cpu_grp); return 0; } static void delete_events(struct memlat_hwmon_data *hw_data) static void delete_events(struct cpu_pmu_stats *cpustats) { int i; for (i = 0; i < NUM_EVENTS; i++) { hw_data->events[i].prev_count = 0; perf_event_release_kernel(hw_data->events[i].pevent); cpustats->events[i].prev_count = 0; perf_event_release_kernel(cpustats->events[i].pevent); } } static void stop_hwmon(struct memlat_hwmon *hw) { int cpu, idx; struct memlat_hwmon_data *hw_data; struct cpu_grp_info *cpu_grp = container_of(hw, struct cpu_grp_info, hw); int cpu; struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); struct dev_stats *devstats; get_online_cpus(); for_each_cpu(cpu, &cpu_grp->cpus) { hw_data = &per_cpu(pm_data, cpu); if (hw_data->init_pending) hw_data->init_pending = false; else delete_events(hw_data); for_each_cpu(cpu, &cpu_grp->inited_cpus) { delete_events(to_cpustats(cpu_grp, cpu)); /* Clear governor data */ idx = cpu - cpumask_first(&cpu_grp->cpus); hw->core_stats[idx].inst_count = 0; hw->core_stats[idx].mem_count = 0; hw->core_stats[idx].freq = 0; devstats = to_devstats(cpu_grp, cpu); devstats->inst_count = 0; devstats->mem_count = 0; devstats->freq = 0; } mutex_lock(&list_lock); if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) list_del(&cpu_grp->mon_list); mutex_unlock(&list_lock); cpumask_clear(&cpu_grp->inited_cpus); put_online_cpus(); unregister_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif); Loading @@ -173,7 +173,7 @@ static struct perf_event_attr *alloc_attr(void) attr = kzalloc(sizeof(struct perf_event_attr), GFP_KERNEL); if (!attr) return ERR_PTR(-ENOMEM); return attr; attr->type = PERF_TYPE_RAW; attr->size = sizeof(struct perf_event_attr); Loading @@ -183,37 +183,38 @@ static struct perf_event_attr *alloc_attr(void) return attr; } static int set_events(struct memlat_hwmon_data *hw_data, int cpu) static int set_events(struct cpu_grp_info *cpu_grp, int cpu) { struct perf_event *pevent; struct perf_event_attr *attr; int err; struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); /* Allocate an attribute for event initialization */ attr = alloc_attr(); if (IS_ERR(attr)) return PTR_ERR(attr); if (!attr) return -ENOMEM; attr->config = hw_data->inst_event; attr->config = cpu_grp->inst_event; pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); if (IS_ERR(pevent)) goto err_out; hw_data->events[INST_IDX].pevent = pevent; perf_event_enable(hw_data->events[INST_IDX].pevent); cpustats->events[INST_IDX].pevent = pevent; perf_event_enable(cpustats->events[INST_IDX].pevent); attr->config = hw_data->cache_miss_event; attr->config = cpu_grp->cache_miss_event; pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); if (IS_ERR(pevent)) goto err_out; hw_data->events[CM_IDX].pevent = pevent; perf_event_enable(hw_data->events[CM_IDX].pevent); cpustats->events[CM_IDX].pevent = pevent; perf_event_enable(cpustats->events[CM_IDX].pevent); attr->config = CYC_EV; pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); if (IS_ERR(pevent)) goto err_out; hw_data->events[CYC_IDX].pevent = pevent; perf_event_enable(hw_data->events[CYC_IDX].pevent); cpustats->events[CYC_IDX].pevent = pevent; perf_event_enable(cpustats->events[CYC_IDX].pevent); kfree(attr); return 0; Loading @@ -228,15 +229,24 @@ static int arm_memlat_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) { unsigned long cpu = (unsigned long)hcpu; struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu); struct cpu_grp_info *cpu_grp, *tmp; if ((action != CPU_ONLINE) || !hw_data->init_pending) if (action != CPU_ONLINE) return NOTIFY_OK; if (set_events(hw_data, cpu)) pr_warn("Failed to create perf event for CPU%lu\n", cpu); hw_data->init_pending = false; mutex_lock(&list_lock); list_for_each_entry_safe(cpu_grp, tmp, &memlat_mon_list, mon_list) { if (!cpumask_test_cpu(cpu, &cpu_grp->cpus) || cpumask_test_cpu(cpu, &cpu_grp->inited_cpus)) continue; if (set_events(cpu_grp, cpu)) pr_warn("Failed to create perf ev for CPU%lu\n", cpu); else cpumask_set_cpu(cpu, &cpu_grp->inited_cpus); if (cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) list_del(&cpu_grp->mon_list); } mutex_unlock(&list_lock); return NOTIFY_OK; } Loading @@ -244,29 +254,32 @@ static int arm_memlat_cpu_callback(struct notifier_block *nb, static int start_hwmon(struct memlat_hwmon *hw) { int cpu, ret = 0; struct memlat_hwmon_data *hw_data; struct cpu_grp_info *cpu_grp = container_of(hw, struct cpu_grp_info, hw); struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); register_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif); get_online_cpus(); for_each_cpu(cpu, &cpu_grp->cpus) { hw_data = &per_cpu(pm_data, cpu); ret = set_events(hw_data, cpu); ret = set_events(cpu_grp, cpu); if (ret) { if (!cpu_online(cpu)) { hw_data->init_pending = true; ret = 0; } else { pr_warn("Perf event init failed on CPU%d\n", cpu); break; } } else { cpumask_set_cpu(cpu, &cpu_grp->inited_cpus); } } mutex_lock(&list_lock); if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) list_add_tail(&cpu_grp->mon_list, &memlat_mon_list); mutex_unlock(&list_lock); put_online_cpus(); return ret; } Loading Loading @@ -328,6 +341,11 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) if (!hw->core_stats) return -ENOMEM; cpu_grp->cpustats = devm_kzalloc(dev, hw->num_cores * sizeof(*(cpu_grp->cpustats)), GFP_KERNEL); if (!cpu_grp->cpustats) return -ENOMEM; ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev", &cachemiss_ev); if (ret) { Loading @@ -335,6 +353,7 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) L2DM_EV); cachemiss_ev = L2DM_EV; } cpu_grp->cache_miss_event = cachemiss_ev; ret = of_property_read_u32(dev->of_node, "qcom,inst-ev", &inst_ev); if (ret) { Loading @@ -342,12 +361,10 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) INST_EV); inst_ev = INST_EV; } cpu_grp->inst_event = inst_ev; for_each_cpu(cpu, &cpu_grp->cpus) { hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu; (&per_cpu(pm_data, cpu))->cache_miss_event = cachemiss_ev; (&per_cpu(pm_data, cpu))->inst_event = inst_ev; } for_each_cpu(cpu, &cpu_grp->cpus) to_devstats(cpu_grp, cpu)->id = cpu; hw->start_hwmon = &start_hwmon; hw->stop_hwmon = &stop_hwmon; Loading Loading
drivers/devfreq/arm-memlat-mon.c +90 −73 Original line number Diff line number Diff line Loading @@ -47,22 +47,32 @@ struct event_data { unsigned long prev_count; }; struct memlat_hwmon_data { struct cpu_pmu_stats { struct event_data events[NUM_EVENTS]; ktime_t prev_ts; bool init_pending; unsigned long cache_miss_event; unsigned long inst_event; }; static DEFINE_PER_CPU(struct memlat_hwmon_data, pm_data); struct cpu_grp_info { cpumask_t cpus; cpumask_t inited_cpus; unsigned long cache_miss_event; unsigned long inst_event; struct cpu_pmu_stats *cpustats; struct memlat_hwmon hw; struct notifier_block arm_memlat_cpu_notif; struct list_head mon_list; }; static unsigned long compute_freq(struct memlat_hwmon_data *hw_data, #define to_cpustats(cpu_grp, cpu) \ (&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)]) #define to_devstats(cpu_grp, cpu) \ (&cpu_grp->hw.core_stats[cpu - cpumask_first(&cpu_grp->cpus)]) #define to_cpu_grp(hwmon) container_of(hwmon, struct cpu_grp_info, hw) static LIST_HEAD(memlat_mon_list); static DEFINE_MUTEX(list_lock); static unsigned long compute_freq(struct cpu_pmu_stats *cpustats, unsigned long cyc_cnt) { ktime_t ts; Loading @@ -70,10 +80,10 @@ static unsigned long compute_freq(struct memlat_hwmon_data *hw_data, unsigned long freq = 0; ts = ktime_get(); diff = ktime_to_us(ktime_sub(ts, hw_data->prev_ts)); diff = ktime_to_us(ktime_sub(ts, cpustats->prev_ts)); if (!diff) diff = 1; hw_data->prev_ts = ts; cpustats->prev_ts = ts; freq = cyc_cnt; do_div(freq, diff); Loading @@ -99,69 +109,59 @@ static inline unsigned long read_event(struct event_data *event) static void read_perf_counters(int cpu, struct cpu_grp_info *cpu_grp) { int cpu_idx; struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu); struct memlat_hwmon *hw = &cpu_grp->hw; struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); struct dev_stats *devstats = to_devstats(cpu_grp, cpu); unsigned long cyc_cnt; if (hw_data->init_pending) return; cpu_idx = cpu - cpumask_first(&cpu_grp->cpus); hw->core_stats[cpu_idx].inst_count = read_event(&hw_data->events[INST_IDX]); hw->core_stats[cpu_idx].mem_count = read_event(&hw_data->events[CM_IDX]); cyc_cnt = read_event(&hw_data->events[CYC_IDX]); hw->core_stats[cpu_idx].freq = compute_freq(hw_data, cyc_cnt); devstats->inst_count = read_event(&cpustats->events[INST_IDX]); devstats->mem_count = read_event(&cpustats->events[CM_IDX]); cyc_cnt = read_event(&cpustats->events[CYC_IDX]); devstats->freq = compute_freq(cpustats, cyc_cnt); } static unsigned long get_cnt(struct memlat_hwmon *hw) { int cpu; struct cpu_grp_info *cpu_grp = container_of(hw, struct cpu_grp_info, hw); struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); for_each_cpu(cpu, &cpu_grp->cpus) for_each_cpu(cpu, &cpu_grp->inited_cpus) read_perf_counters(cpu, cpu_grp); return 0; } static void delete_events(struct memlat_hwmon_data *hw_data) static void delete_events(struct cpu_pmu_stats *cpustats) { int i; for (i = 0; i < NUM_EVENTS; i++) { hw_data->events[i].prev_count = 0; perf_event_release_kernel(hw_data->events[i].pevent); cpustats->events[i].prev_count = 0; perf_event_release_kernel(cpustats->events[i].pevent); } } static void stop_hwmon(struct memlat_hwmon *hw) { int cpu, idx; struct memlat_hwmon_data *hw_data; struct cpu_grp_info *cpu_grp = container_of(hw, struct cpu_grp_info, hw); int cpu; struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); struct dev_stats *devstats; get_online_cpus(); for_each_cpu(cpu, &cpu_grp->cpus) { hw_data = &per_cpu(pm_data, cpu); if (hw_data->init_pending) hw_data->init_pending = false; else delete_events(hw_data); for_each_cpu(cpu, &cpu_grp->inited_cpus) { delete_events(to_cpustats(cpu_grp, cpu)); /* Clear governor data */ idx = cpu - cpumask_first(&cpu_grp->cpus); hw->core_stats[idx].inst_count = 0; hw->core_stats[idx].mem_count = 0; hw->core_stats[idx].freq = 0; devstats = to_devstats(cpu_grp, cpu); devstats->inst_count = 0; devstats->mem_count = 0; devstats->freq = 0; } mutex_lock(&list_lock); if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) list_del(&cpu_grp->mon_list); mutex_unlock(&list_lock); cpumask_clear(&cpu_grp->inited_cpus); put_online_cpus(); unregister_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif); Loading @@ -173,7 +173,7 @@ static struct perf_event_attr *alloc_attr(void) attr = kzalloc(sizeof(struct perf_event_attr), GFP_KERNEL); if (!attr) return ERR_PTR(-ENOMEM); return attr; attr->type = PERF_TYPE_RAW; attr->size = sizeof(struct perf_event_attr); Loading @@ -183,37 +183,38 @@ static struct perf_event_attr *alloc_attr(void) return attr; } static int set_events(struct memlat_hwmon_data *hw_data, int cpu) static int set_events(struct cpu_grp_info *cpu_grp, int cpu) { struct perf_event *pevent; struct perf_event_attr *attr; int err; struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); /* Allocate an attribute for event initialization */ attr = alloc_attr(); if (IS_ERR(attr)) return PTR_ERR(attr); if (!attr) return -ENOMEM; attr->config = hw_data->inst_event; attr->config = cpu_grp->inst_event; pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); if (IS_ERR(pevent)) goto err_out; hw_data->events[INST_IDX].pevent = pevent; perf_event_enable(hw_data->events[INST_IDX].pevent); cpustats->events[INST_IDX].pevent = pevent; perf_event_enable(cpustats->events[INST_IDX].pevent); attr->config = hw_data->cache_miss_event; attr->config = cpu_grp->cache_miss_event; pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); if (IS_ERR(pevent)) goto err_out; hw_data->events[CM_IDX].pevent = pevent; perf_event_enable(hw_data->events[CM_IDX].pevent); cpustats->events[CM_IDX].pevent = pevent; perf_event_enable(cpustats->events[CM_IDX].pevent); attr->config = CYC_EV; pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); if (IS_ERR(pevent)) goto err_out; hw_data->events[CYC_IDX].pevent = pevent; perf_event_enable(hw_data->events[CYC_IDX].pevent); cpustats->events[CYC_IDX].pevent = pevent; perf_event_enable(cpustats->events[CYC_IDX].pevent); kfree(attr); return 0; Loading @@ -228,15 +229,24 @@ static int arm_memlat_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) { unsigned long cpu = (unsigned long)hcpu; struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu); struct cpu_grp_info *cpu_grp, *tmp; if ((action != CPU_ONLINE) || !hw_data->init_pending) if (action != CPU_ONLINE) return NOTIFY_OK; if (set_events(hw_data, cpu)) pr_warn("Failed to create perf event for CPU%lu\n", cpu); hw_data->init_pending = false; mutex_lock(&list_lock); list_for_each_entry_safe(cpu_grp, tmp, &memlat_mon_list, mon_list) { if (!cpumask_test_cpu(cpu, &cpu_grp->cpus) || cpumask_test_cpu(cpu, &cpu_grp->inited_cpus)) continue; if (set_events(cpu_grp, cpu)) pr_warn("Failed to create perf ev for CPU%lu\n", cpu); else cpumask_set_cpu(cpu, &cpu_grp->inited_cpus); if (cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) list_del(&cpu_grp->mon_list); } mutex_unlock(&list_lock); return NOTIFY_OK; } Loading @@ -244,29 +254,32 @@ static int arm_memlat_cpu_callback(struct notifier_block *nb, static int start_hwmon(struct memlat_hwmon *hw) { int cpu, ret = 0; struct memlat_hwmon_data *hw_data; struct cpu_grp_info *cpu_grp = container_of(hw, struct cpu_grp_info, hw); struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); register_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif); get_online_cpus(); for_each_cpu(cpu, &cpu_grp->cpus) { hw_data = &per_cpu(pm_data, cpu); ret = set_events(hw_data, cpu); ret = set_events(cpu_grp, cpu); if (ret) { if (!cpu_online(cpu)) { hw_data->init_pending = true; ret = 0; } else { pr_warn("Perf event init failed on CPU%d\n", cpu); break; } } else { cpumask_set_cpu(cpu, &cpu_grp->inited_cpus); } } mutex_lock(&list_lock); if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) list_add_tail(&cpu_grp->mon_list, &memlat_mon_list); mutex_unlock(&list_lock); put_online_cpus(); return ret; } Loading Loading @@ -328,6 +341,11 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) if (!hw->core_stats) return -ENOMEM; cpu_grp->cpustats = devm_kzalloc(dev, hw->num_cores * sizeof(*(cpu_grp->cpustats)), GFP_KERNEL); if (!cpu_grp->cpustats) return -ENOMEM; ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev", &cachemiss_ev); if (ret) { Loading @@ -335,6 +353,7 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) L2DM_EV); cachemiss_ev = L2DM_EV; } cpu_grp->cache_miss_event = cachemiss_ev; ret = of_property_read_u32(dev->of_node, "qcom,inst-ev", &inst_ev); if (ret) { Loading @@ -342,12 +361,10 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) INST_EV); inst_ev = INST_EV; } cpu_grp->inst_event = inst_ev; for_each_cpu(cpu, &cpu_grp->cpus) { hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu; (&per_cpu(pm_data, cpu))->cache_miss_event = cachemiss_ev; (&per_cpu(pm_data, cpu))->inst_event = inst_ev; } for_each_cpu(cpu, &cpu_grp->cpus) to_devstats(cpu_grp, cpu)->id = cpu; hw->start_hwmon = &start_hwmon; hw->stop_hwmon = &stop_hwmon; Loading