确定代码更改与历史数据中性能加速/减速的算法?

机器算法验证 统计学意义 t检验
2022-04-04 17:44:51

我在一个大型编程团队工作,我对程序中所做的每一项更改都运行了一套性能测试,这些测试基本上测量了运行测试所需的时间。对于每一次代码更改,我们都会运行这些测试,并通过执行两个样本的 t 测试(针对之前代码更改的结果)来计算更改是否导致测试运行速度变慢。这工作得很好,但问题是我们只有少量的样本数据点,通常每次测试 5 个,每次代码更改。我们跟踪性能大约有 400 个单独的测量值,因此我们在结果中看到了一些噪音(即 t 检验将产生一个小的 p 值,因为代码更改实际上并没有更快/更慢)。

尽管我们在每次代码更改上都有少量的样本点,但我们有一个非常大的结果历史记录。我想用这些历史数据来帮助我们,但我不知道该怎么做。我担心的一个问题是,任何代码更改都可能导致测试运行得更快或更慢,所以只是盲目地汇总历史数据会产生糟糕的结果。是否有任何统计测试可以帮助我解决这个问题?

更多信息:大多数时候代码更改对性能没有任何影响,而那些确实导致性能测试运行更快或更慢的代码更改仅在 400 次测试中这样做。这意味着对于任何给定的测试,在更改实际上使测试运行更快或更慢之前,可能需要进行数百次代码更改。

为了澄清,我想弄清楚代码更改何时会导致测试运行得更快或更慢。我有什么选择?

3个回答

以下内容并不是您问题的真正答案,但可能对您的问题有所帮助:

您提到的困难之一是您正在进行约 400 次 t 检验,因此最终会得到许多虚假的小 p 值。在这里使用的一件有用的事情是“错误发现率”(FDR)分析,它试图确定小 p 值的哪一部分与空值一致。如果我正在解决您的问题,我很确定我会使用一些 FDR 方法。

FDR 控制是一个很大的话题(http://en.wikipedia.org/wiki/False_discovery_rate),所以我不会尝试完全描述它,但如果您有兴趣,这里有一些链接可以帮助您入门:

这里有些东西并不完全是对原始问题的回答,但可能很有价值,也可能作为对问题背后问题的回答,其效果是:“我如何充分利用我的编程加速我的代码?”

我敢打赌,你可以修改一个部分,然后重新运行几次,这比重写部分内容要快得多。如果是这种情况,那么随机插入随机长度的暂停,并记录放置的两个部分、插入的暂停长度以及对整体运行时间的影响,您可以确定代码的一部分的延迟如何传播到代码的其余部分。

是否知道哪些部分对整体加速您的目标影响最大?“随机”干预是解决此类问题的合理方法吗?

祝你好运。

首先,您想知道总测试时间是否有统计上的显着变化。其次,如果发生了变化,哪些测试发生了变化?

这就是我要做的:在每个代码状态中计算每个时间变量的平均值。然后为每个时间变量计算其均值的标准差。这种可变性度量是您如何合并整个测试历史中的信息。

接下来使用 -tests 检查前一个代码状态的变化(零假设是当前状态的平均时间等于前一个状态的平均值)。t

主要测试只是总体时间是否发生变化,因此您无需检查联合假设,简单的检验就足够了。如果总时间发生了变化,那么我将为单独的测试计算统计量,以查看哪些测试对变化负责。tt

一个用 R 写的粗略例子:

# Hypothetical time data over 100 states:
state <- rep(1:100, each = 5)
t1 <- 1 + runif(500)
t2 <- 2 + runif(500)
t3 <- 3 + runif(500)
total_time <- t1 + t2 + t3
d <- data.frame(state, total_time, t1, t2, t3)

# Suppose current state is 100, then we want to compare it to state 99
# while taking into account information on variability based on all historical data.

# Means within historical code states:
d_means <- aggregate(d, by=list(d$state), mean)

# Standard deviation of means up to current state:
d_stdev <- sapply(d_means[d_means$state < 100, ], sd)

# Central limit theorem tells us means are approx. normally distributed.
# So we can use t-tests.

# Test if total testing time has changed in current state:
previous <- subset(d_means, state == 99)
current  <- subset(d_means, state == 100)
t_total_time <- (current$total_time - previous$total_time) / d_stdev[['total_time']]

# Now, for example, if abs(t_total_time) > 1.96, then time change is statistically
# significant at roughly 5% level.

# Check each test to see which ones have statistically significant change from
# previous state:
t_test_1 <- (current$t1 - previous$t1) / d_stdev[['t1']]
t_test_2 <- (current$t2 - previous$t2) / d_stdev[['t2']]
t_test_3 <- (current$t3 - previous$t3) / d_stdev[['t3']]

print(t_total_time)
print(t_test_1)
print(t_test_2)
print(t_test_3)