我正在学习一门课程,其中我们有一个malloc的自定义实现,取自这篇文章,malloc的实现可以在这里看到,此外,我们还有这个测试实现本身的程序(它只是进行了大量的内存分配)
#include <stdlib.h>
#define MAXITERS 100000
#define MAXSIZE 1024
int main(int argc, char* argv[]) {
float pfree = atof(argv[1]);
int niter = rand() % MAXITERS;
for(int i = 0; i < niter; i++ ) {
int size = rand() % MAXSIZE;
void* p = malloc(size * sizeof(char));
float toss = (float)random() / RAND_MAX;
if ( toss > pfree )
free(p);
}
return 0;
}
问题是,每当我运行它时,在 WSL2 上都会花费大约 30 秒。我朋友的电脑(配备 M3 Pro)大约需要 1 秒,我教授的 M2 Air 也花了大约 1 秒。自然,我认为这是 WSL 的问题,因此我快速启动到 Ubuntu 23,运行该程序,发现它与 WSl2 花费相同的时间。然后我决定在 Fedora 39 中运行它,并得到了相同的结果。
这是我们正在使用的编译命令,我认为这可能是某些事情变得奇怪的原因。
gcc -Wno-deprecated-declarations -o libmemalloc.so -fPIC -shared memalloc.c
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
gcc testalloc.c -o testalloc -L. -lmemalloc
./testalloc 0.5
原始说明没有附带 LD_LIBRARY_PATH 的 “export” 关键字,因为我的教授在 MacOS 上工作并且它似乎在那里工作,但是,在 Linux 上,没有它它们就无法工作。这可能是问题所在吗?导出功能与 MacOS 版本是否不同?
我会将包含我们正在运行的代码的 .zip 文件以及运行它的脚本上传到此存储库,这就是我用于测试的脚本。如果你们可以测试代码及其速度,并帮助我解决这个问题,我将不胜感激。
编辑 我们确认它确实是在 MacOS 上使用我们的实际实现,正如我们所补充的:
int x = x/0;
printf("%d", x);
对于代码,在 Linux 上它崩溃了,但奇怪的是,在 MacOS 上它只打印 0,我不知道这是否是正常行为,但无论哪种方式,它肯定使用我们的实现,因为它要么崩溃,要么打印 0 .
[我尝试过的]
尝试过其他计算机和操作系统,都一样(出于明显原因,Windows 除外)
尝试了不同的编译命令,包括原始文章中使用 LD_PRELOAD 的编译命令,但它们仍然非常慢,并且会破坏终端会话上的其他程序,而 LD_LIBRARY_PATH 似乎不会这样做。
添加破坏我们的 malloc 实现的代码(参见上面的编辑),运行我们的版本的 MacOS 大约需要 1~ 秒,但即使是 10 年前的笔记本电脑,在运行实际的 malloc() 时,这一事实进一步证明了这一点它在 0.0 秒内完成(使用 time 命令),因此 MacO 肯定正在运行我们版本的 malloc()。
程序的运行时间受到您获得的随机数的影响:
niter
的值(迭代次数!!!)size
的值。toss
的价值(无论您是否执行free
)。您正在混合
rand
和 random
调用 [为什么?]。
在某些系统上(例如
linux/glibc
),rand
会调用 random
,但其他系统则不会。
此外,在
linux/glibc
上,rand_r
是一个简单的线性同余生成器,而 rand
不是 rand_r(&seed)
参见:线性同余发生器
因此,为了获得一致的结果,您将受到给定系统实现
rand
和 random
! 的影响
尝试将所有
rand*
调用替换为:(例如)xrand
。这是基于“标准”数字的 LCG:
static unsigned int xrand_seed;
int
xrand_r(unsigned int *seed)
{
int val = *seed;
val = (val * 1103515245) + 12345;
*seed = val;
return val & 0x7FFFFFFF;
}
int
xrand(void)
{
return xrand_r(&xrand_seed);
}
这是
testalloc.c
的重构版本:
xrand
实现printf
和时间戳,以便您可以看到性能如何受到影响。-R<seed>
参数来查看随机种子如何影响性能。/*
* a simple application to exercise malloc() and free() calls
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define MAXITERS 100000
#define MAXSIZE 1024
#if DEBUG
#define dbgprt(_fmt...) \
do { \
dbgstamp(); \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
double tsczero;
double
tscgetf(void)
{
struct timespec ts;
double sec;
clock_gettime(CLOCK_MONOTONIC,&ts);
sec = ts.tv_nsec;
sec /= 1e9;
sec += ts.tv_sec;
sec -= tsczero;
return sec;
}
void
dbgstamp(void)
{
double tsc = tscgetf();
static unsigned long long seqno;
printf("[%llu/%.9f] ",seqno++,tsc);
}
static unsigned int xrand_seed;
int
xrand_r(unsigned int *seed)
{
int val = *seed;
val = (val * 1103515245) + 12345;
*seed = val;
return val & 0x7FFFFFFF;
}
int
xrand(void)
{
return xrand_r(&xrand_seed);
}
int
main(int argc, char *argv[])
{
--argc;
++argv;
tsczero = tscgetf();
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'R':
xrand_seed = atoll(cp);
break;
}
}
dbgprt("main: R=%u\n",xrand_seed);
double pfree;
if (argc > 1)
pfree = atof(argv[1]);
else
pfree = 0.5;
dbgprt("main: pfree=%g\n",pfree);
int niter = xrand() % MAXITERS;
dbgprt("main: niter=%d\n",niter);
for (int i = 0; i < niter; i++) {
dbgprt("main: ENTER i=%d/%d\n",i,niter);
int size = xrand() % MAXSIZE;
dbgprt("main: RAND size=%d\n",size);
void *p = malloc(size * sizeof(char));
dbgprt("main: RET p=%p\n",p);
double toss = (double) xrand() / RAND_MAX;
if (toss > pfree) {
dbgprt("main: FREE\n");
free(p);
}
dbgprt("main: EXIT\n");
}
printf("Successful\n");
return 0;
}