我正在参加一门课程,其中我们有malloc的自定义实现,取自here-write-a-simple-memory" rel="nofollow noreferrer">this article,malloc的实现可以看到here,此外,我们还有这个程序来测试实现本身(它只是进行了大量内存分配)

#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;
}

问题是,每当我运行它时,在WSL 2上都需要大约30秒的时间.我朋友的计算机(配备M3 Pro)大约需要1秒,我教授的M2 Air也是如此.当然,我认为这是WSL的问题,所以我很快启动到Ubuntu 23,运行该程序,并发现它所需的时间与WSL 2相同.然后我决定在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文件,以及运行它的脚本,这就是我用于测试的内容.如果你们能够测试代码及其速度,并帮助我解决这个问题,我将不胜感激.

EDIT 我们确认它确实在MacOS上使用了我们的实际实现,我们补充道:

int x = x/0;
printf("%d", x);

到代码,在Linux上它崩溃了,但奇怪的是,在MacOS上它只打印0,我不知道这是否是正常行为,但无论哪种方式,它肯定在使用我们的实现,因为它要么崩溃,要么打印0.

[What I have tried]

try 过其他计算机和操作系统,但都是一样的(由于明显的原因,Windows除外)

try 过不同的编译命令,包括原始文章中使用LD_PREADD的命令,但它们仍然非常慢,并且会中断终端会话上的其他程序,而LD_LIBRARY_PATH似乎没有这样做.

添加 destruct 我们的malloc实现的代码(请参阅上面的编辑)这一事实进一步证明,运行我们版本的MacOS大约需要1秒,但即使是10年前的笔记本电脑,在运行实际的malloc()时也会在0.0秒内完成(使用time命令),所以MacO肯定运行我们版本的malloc().

推荐答案

程序的运行时间受到您获得的随机数的影响:

  1. 值为niter(迭代次数!)
  2. 每个循环的值为size.
  3. 值为toss(无论您是否 Select free).

您混淆了randrandom个电话[为什么?].

在某些系统(例如linux/glibc)上,rand呼叫random,但其他系统则不.

此外,在linux/glibc上,rand_r是简单的线性全等生成器,randnot rand_r(&seed)

参见:Linear Congruential Generator

因此,为了获得一致的结果,您将受到给定系统randrandom的实施的摆布!


try 将所有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的重构版本:

  1. 它使用上面的xrand实现
  2. 它具有调试printf和时间戳,因此您可以查看性能如何受到影响.
  3. 它允许使用-R<seed>参数来查看随机种子如何影响性能.
  4. 调用程序without参数的segfault已修复.
/*
 * 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;
}

C++相关问答推荐

为什么在传输 Big Data 时共享内存段的运行时间比管道更长?

找出文件是否包含给定的文件签名

空指针的运行时强制转换

C:fopen是如何实现二进制模式和文本模式的?

如何调试LD_PRELOAD库中的构造函数?

带有sigLongjMP中断I/O的异常处理程序

在CLANG中调试预处理器宏

VS代码';S C/C++扩展称C23真关键字和假关键字未定义

每次除以或乘以整数都会得到0.0000

I2C外设在单次交易后出现故障

如何使用唯一数字对整型进行分区

在vfork()之后,链接器如何在不 destruct 父内存的情况下解析execve()?

在函数外部使用内联ASM时无法指定操作数

将 struct 数组写入二进制文件时发生Valgrind错误

哪些C++功能可以在外部C块中使用

GCC认为这是一个VLA是对的吗?

令人困惑的返回和 scanf 问题相关

const struct 成员的 typedef 中的灵活数组大小

为什么 Linux 共享库 .so 在内存中可能比在磁盘上大?

段错误try 访问静态字符串,但仅有时取决于构建环境