Linux内核win_minmax代码解读

  • Post author:
  • Post category:linux




目标

  • 维护一段win时间内的三个best最大值或者最小值,以最大值为例
  • 值大小上,1st best > 2nd best > 3rd best
  • 采集时间,1st best < 2nd best < 3rd best

    注:win时间,表示一个窗口时间,或者说一段时间



代码分析

以最大值为例进行分析



基本结构体

一个样本,包含一个时间值和一个大小,其中时间值没有单位,由调用者决定,只要保证和win时间的单位一致即可,所以可以是秒,可以是10s

/* A single data point for our parameterized min-max tracker */
struct minmax_sample {
	u32	t;	/* time measurement was taken */
	u32	v;	/* value measured */
};

状态跟踪结构体,三个样本

/* State for the parameterized min-max tracker */
struct minmax {
	struct minmax_sample s[3];
};



重置

static inline u32 minmax_reset(struct minmax *m, u32 t, u32 meas)
{
	struct minmax_sample val = { .t = t, .v = meas };

	m->s[2] = m->s[1] = m->s[0] = val;
	return m->s[0].v;
}

将三个best值全部设置为传入的时间值和样本值。



更新最大值

/* Check if new measurement updates the 1st, 2nd or 3rd choice max. */
u32 minmax_running_max(struct minmax *m, u32 win, u32 t, u32 meas)
{
	struct minmax_sample val = { .t = t, .v = meas };

	if (unlikely(val.v >= m->s[0].v) ||	  /* found new max? */
	    unlikely(val.t - m->s[2].t > win))	  /* nothing left in window? */
		return minmax_reset(m, t, meas);  /* forget earlier samples */

	if (unlikely(val.v >= m->s[1].v))
		m->s[2] = m->s[1] = val;
	else if (unlikely(val.v >= m->s[2].v))
		m->s[2] = val;

	return minmax_subwin_update(m, win, &val);
}

用流程图表示:

Created with Raphaël 2.2.0 开始 样本值大于等于1st best? 重置状态跟踪 刷新时间 结束 样本时间是否超过3rd best win时间大小? 样本值大于等于2nd best? 3rd best = 2nd best = 样本 样本值大于等于3rd best? 3rd best = 样本 yes no yes no yes no yes



刷新时间

/* As time advances, update the 1st, 2nd, and 3rd choices. */
static u32 minmax_subwin_update(struct minmax *m, u32 win,
				const struct minmax_sample *val)
{
	u32 dt = val->t - m->s[0].t;

	if (unlikely(dt > win)) {
		/*
		 * Passed entire window without a new val so make 2nd
		 * choice the new val & 3rd choice the new 2nd choice.
		 * we may have to iterate this since our 2nd choice
		 * may also be outside the window (we checked on entry
		 * that the third choice was in the window).
		 */
		m->s[0] = m->s[1];
		m->s[1] = m->s[2];
		m->s[2] = *val;
		if (unlikely(val->t - m->s[0].t > win)) {
			m->s[0] = m->s[1];
			m->s[1] = m->s[2];
			m->s[2] = *val;
		}
	} else if (unlikely(m->s[1].t == m->s[0].t) && dt > win/4) {
		/*
		 * We've passed a quarter of the window without a new val
		 * so take a 2nd choice from the 2nd quarter of the window.
		 */
		m->s[2] = m->s[1] = *val;
	} else if (unlikely(m->s[2].t == m->s[1].t) && dt > win/2) {
		/*
		 * We've passed half the window without finding a new val
		 * so take a 3rd choice from the last half of the window
		 */
		m->s[2] = *val;
	}
	return m->s[0].v;
}

用流程图表示:

Created with Raphaël 2.2.0 开始 计算样本值时间距离1st best的时间 时间差大于win时间 更新所有best 1st best时间值是否大于win时间 更新1st best 更新2nd best 更新3rd best 返回最大值 结束 1st best==2nd best && dt > win/4 2nd best == 3rd best && dt > win/2 yes no yes yes no yes

有几个问题

  • 为什么更新两次全部更新之后不再比较3rd与样本值?
  • 因为在更新最大值的第一步流程中就比较过新样本和3rdbest的时间戳,所以这里保证了3rdbest的时间戳和样本的时间戳差值肯定在win时间内
  • 如果2nd的值未设置过,则需要等待win的0.25倍时间
  • 如果3rd的值未设置过,则需要等待win的0.5倍时间



总结

  • win_minmax维护了win时间内的最优值
  • 当1st best已经不属于当前时间的win窗口时间内时,会由2nd best顶上,甚至3rd best顶上

————-


探花原创



版权声明:本文为weixin_45490038原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。