C AIX下用于排序哈希值的128位比较(64位)

C AIX下用于排序哈希值的128位比较(64位),c,aix,C,Aix,我需要使用xlC\r编译器在AIX(64位)下对类似以下结构的数组进行排序: struct digest_line { uint64_t first; uint64_t second; }; 现在我正在做一个漫长的过程(比较第一个元素,如果它们相等,比较第二个元素)。有没有更快的方法来比较这些值 Edit:我忘了提到我正在使用AIX的qsort()函数。根据qsort的手册页,比较函数的定义如下 int (*ComparisonPointer)(const void*, co

我需要使用xlC\r编译器在AIX(64位)下对类似以下结构的数组进行排序:

struct digest_line {
    uint64_t first;
    uint64_t second;
};
现在我正在做一个漫长的过程(比较第一个元素,如果它们相等,比较第二个元素)。有没有更快的方法来比较这些值

Edit:我忘了提到我正在使用AIX的
qsort()
函数。根据
qsort
的手册页,比较函数的定义如下

int  (*ComparisonPointer)(const void*, const void*);
这(对我来说)意味着我不能只返回
int64\t
值,而是类似这样的值:

int compare_digests(const void *a, const void *b)
{
        struct digest_line *aa = (struct digest_line *) a;
        struct digest_line *bb = (struct digest_line *) b;

        int64_t ret = aa->first - bb->first;
        if (!ret) {
                ret = aa->second - bb->second;
        }
        return (ret == 0) ? 0 : (ret > 0) ? 1 : -1;
}

这看起来不像。。。正确的。我一直在想一定有更好的方法。

在任何平台上,最好的选择可能就是使用
memcmp
。这应该在任何合适的体系结构上进行高度优化(和内联)。查看汇编程序应该会告诉您编译器是否正在进行一些巧妙的优化。然后,基准测试可以告诉您哪个版本是最好的,因为对齐问题也可能发挥作用,并且取决于您拥有的数据类型

我手头没有你的架构,所以我很快就用gcc检查了我的旧i686。以下函数的汇编程序

int compare(struct digest* a, struct digest* b) {
  return memcmp(a, b, sizeof *a);
}
看起来很不错


Edit:Jonathan的评论是正确的,他认为这不一定给出128位模式的数字顺序。但是,只要您只对一致的顺序感兴趣,以便将顺序:)带入您的摘要,这在所有平台上都应该可以。AFAIR AIX平台是big-endian平台,因此它在那里应该特别有效。

您的代码有问题,因为您正在对未签名的数据进行签名比较。使用以下备选方案之一:

更正统 这要快得多

int compare_digests(const void *a, const void *b)
{
        const struct digest_line *aa = (const struct digest_line *) a;
        const struct digest_line *bb = (const struct digest_line *) b;

        if (aa->first > bb->first)
            return +1;
        else if (aa->first < bb->first)
            return -1;
        else if (aa->second > bb->second)
            return +1;
        else if (aa->second < bb->second)
            return -1;
        else
            return 0;
}
值和指针版本之间的差异很大(0.077s是标准偏差的许多倍),指针版本更快。因此,使用传统的基于指针的比较器版本。“Null”时间使用一个comparator函数,该函数只返回0,而不进行任何比较

代表性输出线:

Value:   0.730634 (less =  51517909, more =  48482090, equl =         1)
Pointer: 0.684107 (less =  51517909, more =  48482090, equl =         1)
Null:    0.351807 (less =         0, more =         0, equl = 100000000)
测试代码 这两个比较器重命名为
compare_digests_val()
,用于比较值,重命名为
compare_digests_ptr()
,用于比较指针。时钟类型和
clk.*
函数是一个高分辨率的定时器包,在我测试的平台上使用
gettimeofday()
。显然,在增量和累积统计数据的循环中有相当大的开销,但这仅仅意味着比较器中的差异更为显著

static int compare_digests_nul(const void *a, const void *b)
{
    return 0;
}

static void time_comparisons(const char *tag, int (*compare)(const void *, const void *))
{
    struct digest_line a = { 0, 0 };
    struct digest_line b = { 0, 0 };
    int less = 0;
    int more = 0;
    int equl = 0;
    Clock clk;
    char buffer[32];
    clk_init(&clk);
    clk_start(&clk);
    for (int i = 0; i < 100000000; i++)
    {
        int j = (*compare)(&a, &b);
        if (j < 0)
            less++;
        else if (j > 0)
            more++;
        else
            equl++;
        a.first  += 1234567890123ULL;
        a.second += 2345678901234ULL;
        b.first  += 7654321098765ULL;
        b.second += 8765432109876ULL;
    }
    clk_stop(&clk);
    printf("%-8s %s (less = %9d, more = %9d, equl = %9d)\n", tag,
           clk_elapsed_us(&clk, buffer, sizeof(buffer)),
           less, more, equl);
}

int main(void)
{
    for (int i = 0; i < 20; i++)
    {
        time_comparisons("Value:",   compare_digests_val);
        time_comparisons("Pointer:", compare_digests_ptr);
        time_comparisons("Null:",    compare_digests_nul);
    }
    return 0;
}
static int compare\u digests\u numl(const void*a,const void*b)
{
返回0;
}
静态无效时间比较(常量字符*标记,整数(*比较)(常量无效*,常量无效*)
{
结构摘要_行a={0,0};
结构摘要_行b={0,0};
整数小于等于0;
int more=0;
int equal=0;
时钟时钟;
字符缓冲区[32];
clk_init(&clk);
clk_启动(&clk);
对于(int i=0;i<100000000;i++)
{
int j=(*比较)(&a和&b);
if(j<0)
less++;
否则,如果(j>0)
更多++;
其他的
equal++;
a、 第一个+=1234567890123ULL;
a、 秒+=2345678901234ULL;
b、 第一个+=7654321098765ULL;
b、 秒+=8765432109876ULL;
}
时钟停止(&clk);
printf(“%-8s%s(少=%9d,多=%9d,相等=%9d)\n”,标记,
时钟(时钟、缓冲区、sizeof(缓冲区)),
少、多、等);
}
内部主(空)
{
对于(int i=0;i<20;i++)
{
时间比较(“值:”,比较摘要值);
时间比较(“指针:”,比较摘要\u ptr);
时间比较(“空:”,比较摘要);
}
返回0;
}

qsort()比较函数需要提供排序,而不仅仅是“相等或不相等”的结果。即使没有
,无论是在little endian platofrms还是在big endian平台上(我认为little endian,如Intel),这都会失败,因此它肯定是不可移植的。@Jonathan,我认为OP不需要数字排序。很抱歉,这是用于摘要的,通常您只需要一些一致的东西。我需要一致的排序,以便在大型摘要文件之间执行类似于差异的操作。memcmp()看起来是一种有效的方法。为什么要创建结构的本地副本?使用
const-struct-digest_-line*aa=a
then
aa->first
似乎更好。至少,它是一个完全有效的替代方案,当然我通常使用指针而不是局部变量。我不确定这两个符号的性能是否有一个可测量的差异,是否有一个像样的优化编译器。是的,我已经纠正了比较函数中的有符号-无符号问题。这看起来是正确的,非常感谢您的测试。
Value:   0.730634 (less =  51517909, more =  48482090, equl =         1)
Pointer: 0.684107 (less =  51517909, more =  48482090, equl =         1)
Null:    0.351807 (less =         0, more =         0, equl = 100000000)
static int compare_digests_nul(const void *a, const void *b)
{
    return 0;
}

static void time_comparisons(const char *tag, int (*compare)(const void *, const void *))
{
    struct digest_line a = { 0, 0 };
    struct digest_line b = { 0, 0 };
    int less = 0;
    int more = 0;
    int equl = 0;
    Clock clk;
    char buffer[32];
    clk_init(&clk);
    clk_start(&clk);
    for (int i = 0; i < 100000000; i++)
    {
        int j = (*compare)(&a, &b);
        if (j < 0)
            less++;
        else if (j > 0)
            more++;
        else
            equl++;
        a.first  += 1234567890123ULL;
        a.second += 2345678901234ULL;
        b.first  += 7654321098765ULL;
        b.second += 8765432109876ULL;
    }
    clk_stop(&clk);
    printf("%-8s %s (less = %9d, more = %9d, equl = %9d)\n", tag,
           clk_elapsed_us(&clk, buffer, sizeof(buffer)),
           less, more, equl);
}

int main(void)
{
    for (int i = 0; i < 20; i++)
    {
        time_comparisons("Value:",   compare_digests_val);
        time_comparisons("Pointer:", compare_digests_ptr);
        time_comparisons("Null:",    compare_digests_nul);
    }
    return 0;
}