Beispiel #1
0
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;
}
Beispiel #4
0
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();
}