为什么前几个字符串分配较慢?

时间:2014-07-03 13:46:37

标签: c string performance initialization

我一直用以下代码测量初始化字符串的速度,发现奇怪的事情:

#include <stdio.h>
#include <time.h>

#define START_COUNTING  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start)
#define END_COUNTING    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end)
#define NUM_OF_LOOPS    8192

long time_difference(struct timespec end, struct timespec beginning) {
    long long diff = (long long)end.tv_sec - (long long)beginning.tv_sec;
    return(end.tv_nsec - beginning.tv_nsec + ((diff > 0) ? 1000000L : 0));
}

long average(long numbers[NUM_OF_LOOPS]) {
    long long sum = 0;
    int i;

    for(i = 0; i < NUM_OF_LOOPS; i++)
        sum += numbers[i];

    return sum / NUM_OF_LOOPS;
}

int main(void) {
    struct timespec start;
    struct timespec end;
    long time_diffs[NUM_OF_LOOPS];
    int i;
    char * str = NULL;

    for(i = 0; i < NUM_OF_LOOPS; i++) {
        START_COUNTING;
        str = "T";
        END_COUNTING;
        time_diffs[i] = time_difference(end, start);
    }
    printf("%li ns - assigning 2 chars to a string\n", average(time_diffs));

    for(i = 0; i < NUM_OF_LOOPS; i++) {
        START_COUNTING;
        str = "Testing";
        END_COUNTING;
        time_diffs[i] = time_difference(end, start);
    }
    printf("%li ns - assigning 8 chars to a string\n", average(time_diffs));

    for(i = 0; i < NUM_OF_LOOPS; i++) {
        START_COUNTING;
        str = "Testing it here";
        END_COUNTING;
        time_diffs[i] = time_difference(end, start);
    }
    printf("%li ns - assigning 16 chars to a string\n", average(time_diffs));

    for(i = 0; i < NUM_OF_LOOPS; i++) {
        START_COUNTING;
        str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit nullam.";
        END_COUNTING;
        time_diffs[i] = time_difference(end, start);
    }
    printf("%li ns - assigning 64 chars to a string\n", average(time_diffs));

    for(i = 0; i < NUM_OF_LOOPS; i++) {
        START_COUNTING;
        str = ""; // String omitted because it would waste a lot of space
        END_COUNTING;
        time_diffs[i] = time_difference(end, start);
    }
    printf("%li ns - assigning 1024 chars to a string\n", average(time_diffs));

    return 0;
}

在分析它时,我总是想出这个结果:

1126 ns - assigning 2 chars to a string
828 ns - assigning 8 chars to a string
832 ns - assigning 16 chars to a string
834 ns - assigning 64 chars to a string
857 ns - assigning 1024 chars to a string

第一个结果,无论它是否分配2个字符,8个字符或多个字符总是明显慢于其余字符。我已经尝试在循环之前放置1个赋值,但它仍然没有太多改变结果。

有谁知道为什么分配给字符串的前几次更慢?我环顾四周,但只找到了因JIT编译器而发生的答案,但C并没有使用它们。

2 个答案:

答案 0 :(得分:2)

您的代码实际上并不复制任何字符数据,因为您只是设置指向字符串文字的指针。

因此,整个前提是错误的,并且“已分配”的字符数与所花费的时间之间没有相关性。

这是一个超微基准测试,并且非常难以实现,因为您实际上是在尝试测量单个指针大小分配所花费的时间,这实际上并不是很多代码。

速度差异可能是由缓存/内存延迟引起的。您可以阅读生成的代码,以确定str是否存储在寄存器中,当然也可以使用优化设置。

注意:您的测量方法,平均值,意味着开销(time_diffs数组)的缓存占用量 大于测试本身的高度,这可能是导致不规则,第一次time_diffs没有被缓存。

答案 1 :(得分:0)

这里有两个重要的项目: -

  • 不要使用调试代码来计时
  • 确保你实际上正在计划某事

第一个是显而易见的,第二个不是这样。例如,此代码: -

for(i = 0; i < NUM_OF_LOOPS; i++) {
    START_COUNTING;
    str = "T";
    END_COUNTING;
    time_diffs[i] = time_difference(end, start);
}

很可能是由优化编译器编译的: -

for(i = 0; i < NUM_OF_LOOPS; i++) {
    START_COUNTING;
    END_COUNTING;
    time_diffs[i] = time_difference(end, start);
}
str = "T";

第一个循环缓慢的原因,可能是缓存。 cpu必须从RAM / HD加载代码,这需要一段时间,特别是当你在那里进行函数调用时。尝试在定时循环之前放置它: -

    START_COUNTING;
    END_COUNTING;

希望代码进入缓存,为时序循环做好准备。