static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, const char *buf, size_t count) { unsigned int input; int ret; ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; update_sampling_rate(input); return count; }
static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, size_t count) { unsigned int input; int ret; ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; update_sampling_rate(dbs_data, input); return count; }
/* * Every sampling_rate, we check, if current idle time is less than 20% * (default), then we try to increase frequency. Every sampling_rate, we look * for the lowest frequency which can sustain the load while keeping idle time * over 30%. If such a frequency exist, we try to decrease to this frequency. * * Any frequency increase takes it to the maximum frequency. Frequency reduction * happens at minimum steps of 5% (default) of current frequency */ static void od_check_cpu(int cpu, unsigned int load_freq) { struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; dbs_info->freq_lo = 0; /* Check for frequency increase */ #ifdef CONFIG_ARCH_HI6XXX if(load_freq > od_tuners->od_6xxx_up_threshold * policy->cur) { unsigned int freq_next; /* If increase speed, apply sampling_down_factor */ if (policy->cur < policy->max) dbs_info->rate_mult = od_tuners->sampling_down_factor; if (load_freq > od_tuners->up_threshold * policy->cur) freq_next = policy->max; else freq_next = load_freq / od_tuners->od_6xxx_up_threshold; dbs_freq_increase(policy, freq_next); return; } #else if (load_freq > od_tuners->up_threshold * policy->cur) { /* If switching to max speed, apply sampling_down_factor */ if (policy->cur < policy->max) dbs_info->rate_mult = od_tuners->sampling_down_factor; dbs_freq_increase(policy, policy->max); return; } #endif /* Check for frequency decrease */ /* if we cannot reduce the frequency anymore, break out early */ if (policy->cur == policy->min) return; /* * The optimal frequency is the frequency that is the lowest that can * support the current CPU usage without triggering the up policy. To be * safe, we focus 10 points under the threshold. */ #ifdef CONFIG_ARCH_HI6XXX if (load_freq < od_tuners->od_6xxx_down_threshold * policy->cur) { unsigned int freq_next; freq_next = load_freq / od_tuners->od_6xxx_down_threshold; #else if (load_freq < od_tuners->adj_up_threshold * policy->cur) { unsigned int freq_next; freq_next = load_freq / od_tuners->adj_up_threshold; #endif /* No longer fully busy, reset rate_mult */ dbs_info->rate_mult = 1; if (freq_next < policy->min) freq_next = policy->min; if (!od_tuners->powersave_bias) { __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); return; } freq_next = od_ops.powersave_bias_target(policy, freq_next, CPUFREQ_RELATION_L); __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); } } static void od_dbs_timer(struct work_struct *work) { struct od_cpu_dbs_info_s *dbs_info = container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work); unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; int delay = 0, sample_type = core_dbs_info->sample_type; bool modify_all = true; mutex_lock(&core_dbs_info->cdbs.timer_mutex); if (!need_load_eval(&core_dbs_info->cdbs, od_tuners->sampling_rate)) { modify_all = false; goto max_delay; } /* Common NORMAL_SAMPLE setup */ core_dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { delay = core_dbs_info->freq_lo_jiffies; __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy, core_dbs_info->freq_lo, CPUFREQ_RELATION_H); } else { dbs_check_cpu(dbs_data, cpu); if (core_dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ core_dbs_info->sample_type = OD_SUB_SAMPLE; delay = core_dbs_info->freq_hi_jiffies; } } max_delay: if (!delay) delay = delay_for_sampling_rate(od_tuners->sampling_rate * core_dbs_info->rate_mult); gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all); mutex_unlock(&core_dbs_info->cdbs.timer_mutex); } /************************** sysfs interface ************************/ static struct common_dbs_data od_dbs_cdata; /** * update_sampling_rate - update sampling rate effective immediately if needed. * @new_rate: new sampling rate * * If new rate is smaller than the old, simply updating * dbs_tuners_int.sampling_rate might not be appropriate. For example, if the * original sampling_rate was 1 second and the requested new sampling rate is 10 * ms because the user needs immediate reaction from ondemand governor, but not * sure if higher frequency will be required or not, then, the governor may * change the sampling rate too late; up to 1 second later. Thus, if we are * reducing the sampling rate, we need to make the new value effective * immediately. */ static void update_sampling_rate(struct dbs_data *dbs_data, unsigned int new_rate) { struct od_dbs_tuners *od_tuners = dbs_data->tuners; int cpu; od_tuners->sampling_rate = new_rate = max(new_rate, dbs_data->min_sampling_rate); for_each_online_cpu(cpu) { struct cpufreq_policy *policy; struct od_cpu_dbs_info_s *dbs_info; unsigned long next_sampling, appointed_at; policy = cpufreq_cpu_get(cpu); if (!policy) continue; if (policy->governor != &cpufreq_gov_ondemand) { cpufreq_cpu_put(policy); continue; } dbs_info = &per_cpu(od_cpu_dbs_info, cpu); cpufreq_cpu_put(policy); mutex_lock(&dbs_info->cdbs.timer_mutex); if (!delayed_work_pending(&dbs_info->cdbs.work)) { mutex_unlock(&dbs_info->cdbs.timer_mutex); continue; } next_sampling = jiffies + usecs_to_jiffies(new_rate); appointed_at = dbs_info->cdbs.work.timer.expires; if (time_before(next_sampling, appointed_at)) { mutex_unlock(&dbs_info->cdbs.timer_mutex); cancel_delayed_work_sync(&dbs_info->cdbs.work); mutex_lock(&dbs_info->cdbs.timer_mutex); gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, usecs_to_jiffies(new_rate), true); } mutex_unlock(&dbs_info->cdbs.timer_mutex); } } static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, size_t count) { unsigned int input; int ret; ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; update_sampling_rate(dbs_data, input); return count; }
PROCESS_THREAD(sdfclient, ev, data) { PROCESS_BEGIN(); // registers local ipv6 address udphelper_registerlocaladdress(0); // delay for initializing rpl routing tree static struct etimer timer_rpldelay; etimer_set(&timer_rpldelay, CLOCK_SECOND * RPLINITTIME); PROCESS_WAIT_UNTIL(etimer_expired(&timer_rpldelay)); /* * * start SDF !!! * */ time_init = time(); printf("Started SDF-Client at %dx (", SPEEDMULTIPLIER); uip_ipaddr_t ip; udphelper_print_address(udphelper_address_local(&ip)); printf(")\n"); // init (after rpl dag creation!) battery_init(); consumptionrate_init(); // bind udp socket to port udp = udphelper_bind(SDF_PORT); // save sink ip udphelper_address_sink(&ip_sink); // timer for energy neutral consumption rate static struct etimer timer_consumptionrate; etimer_set(&timer_consumptionrate, CLOCK_SECOND * 86400 / SPEEDMULTIPLIER); // timer for updating the sampling rate static struct etimer timer_updatesamplingrate; etimer_set(&timer_updatesamplingrate, CLOCK_SECOND * SDF_SAMPLINGRATE_UPDATEINTERVAL / SPEEDMULTIPLIER); // timer for transmitting sampling rate to children static struct etimer timer_samplingrate_transmit; etimer_set(&timer_samplingrate_transmit, CLOCK_SECOND * 2 / SPEEDMULTIPLIER); etimer_stop(&timer_samplingrate_transmit); // started by update_sampling_rate() // timer for taking samples and transmitting them static struct etimer timer_samples; etimer_stop(&timer_samples); // started by update_sampling_rate() // init node with first calculation of sampling rate update_sampling_rate(&timer_samples, &timer_samplingrate_transmit, 1); while(1) { PROCESS_WAIT_EVENT(); // take an energy neutral consumptionrate sample // (this has to be the first conditin! consumptionrate should be taken everytime // before samplingrate is calculated, so samplingrate can use the new consumptionrate // sample to calculate a more accurate sampling rate) if(etimer_expired(&timer_consumptionrate)) { consumptionrate_sample(); etimer_restart(&timer_consumptionrate); } // update SDF sampling rate if(etimer_expired(&timer_updatesamplingrate)) { // no real calculation when not in init phase and parent is not sink // (mote will keep last samplingrate as long as a new samplingrate is received) if((time() - time_init) / SDF_INITIALIZATIONPHASE == 0 || udphelper_address_equals(udphelper_address_parent(&ip_parent), &ip_sink)) { update_sampling_rate(&timer_samples, &timer_samplingrate_transmit, 1); } else { update_sampling_rate(&timer_samples, &timer_samplingrate_transmit, 0); } etimer_restart(&timer_updatesamplingrate); } // new SDF sampling rate control message if(ev == tcpip_event && uip_newdata()) { // for some reason the real tmote skys in TUDμNet have routing problems not existent in cooja simulator // solution: test if sampling rate update was sent by known parent // (prevents multiple recalculations on incorrect routing tables) static uip_ipaddr_t ip_sender; if(udphelper_address_equals(udphelper_address_parent(&ip_parent), udphelper_packet_senderaddress(&ip_sender))) { last_parent_samlingrate = str2int(udphelper_packet_data()); update_sampling_rate(&timer_samples, &timer_samplingrate_transmit, 1); etimer_restart(&timer_updatesamplingrate); // new interval for samplingrate is set by rpl parent } } // transmit SDF sampling rate to childs // (etimer_stop() seems to not work, so a condition has been added to filter out // invalid etimer events) if(etimer_expired(&timer_samplingrate_transmit) && samplingrate_children_transmitted < samplingrate_children_count) { // For some reason directly sending the messages within this process block has some // random message losses. The contiki example ipv6/rpl-udp/udp-client.c uses the // backoff timer (ctimer) and magically it works without any message lost. // (backoff timer should not be speed up by SPEEDMULTIPLIER!) ctimer_set(&backofftimer_send_samplingrate, CLOCK_SECOND / 8, send_samplingrate, &timer_samplingrate_transmit); } // take a sample and transmit it // (etimer_stop() seems to not work, so a condition has been added to filter out // invalid etimer events) if(etimer_expired(&timer_samples) && ++sampled <= samplingrate) { // For some reason directly sending the messages within this process block has some // random message losses. The contiki example ipv6/rpl-udp/udp-client.c uses the // backoff timer (ctimer) and magically it works without any message lost. // (backoff timer should not be speed up by SPEEDMULTIPLIER!) ctimer_set(&backofftimer_send_sample, CLOCK_SECOND / 8, send_packet, &timer_samples); } } PROCESS_END(); }