【问题标题】:Fast to compile efficient sort algorithm (for JIT compilation)快速编译高效排序算法(用于 JIT 编译)
【发布时间】:2012-05-22 04:03:03
【问题描述】:

我正在构建一个编译器,它将 c++ 代码生成为字符数组,该数组由 JIT 编译器 Clang 转换为 LLVM-IR,然后进一步 JIT 转换为可执行代码(然后执行)。

我正在处理大量数据,在某一时刻,我需要对 custom 数据类型的数组进行排序。数据类型由我的编译器动态构建,并且对于每个 JIT 编译都不同。通常这些元素会通过其中的一些数字按字典顺序进行比较,但是,在极少数情况下,比较可能会更复杂(在一些指针和花哨的字符串比较之后)。

现在我的问题是: 什么是一种有效的排序算法,它可以由 llvm very fast 编译,同时在执行时 very fast? 有没有可以同时快速编译和快速运行的算法?

我的第一个想法是对比较函数进行 JIT 处理并将其作为指针提供给 qsort()(我可以链接到 LLVM 中的外部编译函数)。 然而,qsort 在执行时效率低得惊人。 由于它的模板和 stl-blubbla-sugar,使用 std::sort 的替代方法在编译时效率非常低。

我为以下结构的执行做了一些性能测试:

struct MyStruct {
int x;
long z;
bool operator<(const struct MyStruct& other) const { return (x < other.x) || (x==other.x&&z<other.z); }
}

1MB 数据运行时间:

  • std::sort: 5 毫秒
  • qsort:14 毫秒
  • 自写:6 毫秒

1GB 数据运行时间:

  • std::sort: 8.9 秒
  • qsort:24 秒
  • 自写:10.1 秒

很遗憾,我现在没有 JIT 编译时间,但以后会发布。

目前看来我自己编写的排序比 qsort 或 std::sort 要好,但我更愿意使用一些库实现。

您对现有的排序实现有什么建议,既可以快速执行又可以编译? 或者是否有任何其他可能在快速排序的同时加快编译速度(仅编译比较功能或类似功能)?

顺便说一下,这是我自己写的(从http://alienryderflex.com/quicksort/偷来的)排序例程(对于JITing,我不会使用模板类型,而是直接用自定义类型替换它,包括“

template< typename Type >
void self_written_sort(Type *arr, int elements) {
    #define  MAX_LEVELS  64
    Type piv;
    int beg[MAX_LEVELS], end[MAX_LEVELS], i=0, L, R, swap ;
  beg[0]=0; end[0]=elements;
  while (i>=0) {
    L=beg[i]; R=end[i]-1;
    if (L<R) {
      piv=arr[L];
      while (L<R) {
        while (arr[R]>=piv && L<R) R--; if (L<R) arr[L++]=arr[R];
        while (piv<=arr[L] && L<R) L++; if (L<R) arr[R--]=arr[L]; }
      arr[L]=piv; beg[i+1]=L+1; end[i+1]=end[i]; end[i++]=L;
      if (end[i]-beg[i]>end[i-1]-beg[i-1]) {
        swap=beg[i]; beg[i]=beg[i-1]; beg[i-1]=swap;
        swap=end[i]; end[i]=end[i-1]; end[i-1]=swap; }}
    else {
      i--;
}}}

【问题讨论】:

  • “我自己写的排序比 qsort 或 std::sort 好” - 但根据你发布的结果,std::sort 在这两种情况下都赢了......
  • 另外,虽然我可以想象 STL source 代码编译速度可能很慢(由于所有模板/#include 向导),但我无法想象相应的IR 在复杂性(以及因此的 JIT 速度)方面与其他任何东西都显着不同。还是说您是在运行时编译 C++ 源代码 代码本身?
  • 你确定每次都需要真正编译算法吗(我的意思是每次都只链接它)?如果您只需要链接它,那么算法本身可以随心所欲地复杂(和运行时优化)。
  • 我认为mergesort可以用非常小的代码实现。
  • @Oli Charlesworth:c++ 源代码确实每次都在运行时编译(使用 Clang)。 to dialer:这实际上是我的问题。如果我不每次都编译整个算法,编译器可能无法相应地内联比较/和或复制函数。对 nightcracker:mergesort 可能是我会考虑的一个想法。尽管如此,它还是使用了额外的内存(复制输入),这并不好。

标签: c++ algorithm sorting llvm clang


【解决方案1】:

我会首先尝试将函数指针传递给std::sort,然后以qsort 的方式使用它:

  • 算法本身是预编译的
  • 比较函数是 JIT 并动态传递的

我认为它仍然优于qsort,因为该算法会有意义地操纵内存,并且只会调用比较(真的)。

【讨论】:

  • 好主意,我会试试这个。所以这意味着我还将使用 int(const void*,const void*) 函数 ptr 作为 qsort (实际上 bool(const void*,const void*) as std::sort 仅使用“less”),但将其传递给标准::排序。我会在测试后立即发布性能数据。
  • 据我了解,std::sort 之所以比qsort 更有优势,是因为比较谓词可以内联。
  • @eci:不,您将使用bool(T const&amp;, T const&amp;) 函数。 C++ 是类型化的。此外,您可能希望“识别”常用比较器并切换到预优化代码(例如 &lt;)。
  • @OliCharlesworth:这是优点之一,但其他一些优点包括所有其他操作(实时移动内存)也被键入。显然,内联 对小型比较器来说是值得优化的。
  • @MatthieuM。当我使用 bool(T const&, T const&) 时,我需要重新编译(JIT)类型 T 的排序算法,这将非常昂贵,尤其是对于 std::sort 的模板和代码糖。我认为你最初的答案是想避免这种情况(并使用一些固定的比较函数和一个可以处理所有东西的签名(void*,void*),这样我们就可以预编译除比较器之外的所有东西)。
猜你喜欢
  • 2017-10-26
  • 1970-01-01
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 2010-10-06
  • 2011-07-17
  • 1970-01-01
相关资源
最近更新 更多