我正在閱讀glibc2.9
的源代碼。閱讀strcpy
函數的源代碼,性能不如我預期的那麼好。爲什麼glibc中strcpy的性能更差?
以下是strcpy
在glibc2.9
的源代碼:
char * strcpy (char *dest, const char* src)
{
reg_char c;
char *__unbounded s = (char *__unbounded) CHECK_BOUNDS_LOW (src);
const ptrdiff_t off = CHECK_BOUNDS_LOW (dest) - s - 1;
size_t n;
do {
c = *s++;
s[off] = c;
}
while (c != '\0');
n = s - src;
(void) CHECK_BOUNDS_HIGH (src + n);
(void) CHECK_BOUNDS_HIGH (dest + n);
return dest;
}
因爲我不知道使用偏移的原因,我通過比較下面的代碼上面的代碼做了一些性能測試:
char* my_strcpy(char *dest, const char *src)
{
char *d = dest;
register char c;
do {
c = *src++;
*d++ = c;
} while ('\0' != c);
return dest;
}
結果的strcpy
表現在我的測試是雪上加霜。我已經刪除了關於綁定指針的代碼。
爲什麼glibc
版本使用偏移?
以下是關於測試的介紹。
- 平臺:86(英特爾(R)奔騰(R)4),gcc版本4.4.2
- 編譯標誌:沒有標誌,因爲我不希望任何優化;該命令是
gcc test.c
。
我所使用的測試代碼如下:
#include <stdio.h>
#include <stdlib.h>
char* my_strcpy1(char *dest, const char *src)
{
char *d = dest;
register char c;
do {
c = *src++;
*d++ = c;
} while ('\0' != c);
return dest;
}
/* Copy SRC to DEST. */
char *
my_strcpy2 (dest, src)
char *dest;
const char *src;
{
register char c;
char * s = (char *)src;
const int off = dest - s - 1;
do
{
c = *s++;
s[off] = c;
}
while (c != '\0');
return dest;
}
int main()
{
const char str1[] = "test1";
const char str2[] = "test2";
char buf[100];
int i;
for (i = 0; i < 10000000; ++i) {
my_strcpy1(buf, str1);
my_strcpy1(buf, str2);
}
return 0;
}
當使用my_strcpy1
功能,輸出是:
[[email protected] test]#time ./a.out
real 0m0.519s
user 0m0.517s
sys 0m0.001s
[[email protected] test]#time ./a.out
real 0m0.520s
user 0m0.520s
sys 0m0.001s
[[email protected] test]#time ./a.out
real 0m0.519s
user 0m0.516s
sys 0m0.002s
當期運用my_strcpy2
,輸出爲:
[[email protected] test]#time ./a.out
real 0m0.647s
user 0m0.647s
sys 0m0.000s
[[email protected] test]#time ./a.out
real 0m0.642s
user 0m0.638s
sys 0m0.001s
[[email protected] test]#time ./a.out
real 0m0.639s
user 0m0.638s
sys 0m0.002s
我知道了用命令time
不是很準確。但我可以從用戶時間獲得答案。
更新:
To remove the cost used to calculate the offset, I removed some code and added a global variable.
#include <stdio.h>
#include <stdlib.h>
char* my_strcpy1(char *dest, const char *src)
{
char *d = dest;
register char c;
do {
c = *src++;
*d++ = c;
} while ('\0' != c);
return dest;
}
int off;
/* Copy SRC to DEST. */
char *
my_strcpy2 (dest, src)
char *dest;
const char *src;
{
register char c;
char * s = (char *)src;
do
{
c = *s++;
s[off] = c;
}
while (c != '\0');
return dest;
}
int main()
{
const char str1[] = "test1test1test1test1test1test1test1test1";
char buf[100];
off = buf-str1-1;
int i;
for (i = 0; i < 10000000; ++i) {
my_strcpy2(buf, str1);
}
return 0;
}
但my_strcpy2
的業績仍好於my_strcpy1
更糟。然後我檢查了彙編的代碼,但沒有得到答案。
我也放大串的大小和my_strcpy1
的業績仍好於my_strcpy2
護理來發表您的平臺,編譯器版本,優化標誌的細節和你有兩種功能得到了實際時間? – NPE
這是'strcpy'的C版本,你的平臺幾乎肯定有一個glibc使用的彙編版本。 –
「...我做了一些性能測試......」。你做了什麼測試?你確定你測試了代碼的優化版本?所有這些'CHECK_BOUNDS_HIGH'宏看起來像是用於調試代碼版本的額外安全檢查(當啓用「有界指針」支持時)。使用這些調試宏來測試性能是沒有意義的。 – AnT