Выполнение разрыва в производительности между GCC и Clang - PullRequest
2 голосов
/ 08 ноября 2019

У меня есть следующий простой код, и когда я компилирую их в GCC и Clang, существует огромная разница в производительности между временем их выполнения, как вы можете видеть результаты и версии компиляторов ниже.

char* strchr_x(register const char* s, int c) {
  do {
    if (*s == c) {
      return (char*)s;
    }
  } while (*s++);

  return 0;
}
char* get(char* value, const char seperator) {
  int seperator_index = strchr(value, seperator) - value;
  char* result = malloc(seperator_index);
  memcpy(result, value, seperator_index);
  result[seperator_index] = '\0';

  return result;
}
int main() {
  const char seperator = ',';
  clock_t t = clock();

  for (size_t i = 0; i < 100000000; ++i) {
    free(get("127.0.0.1, 127.0.0.2:1111", seperator));
  }

  float elapsed_seconds = (((double)(clock() - t)) / CLOCKS_PER_SEC);
  printf("%f seconds.\n", elapsed_seconds);

  return 0;
}
gcc version 8.1.0 (Ubuntu 8.1.0-5ubuntu1~16.04)
# gcc main.c -O3 -o gcc-main
# 1.968750 seconds.

clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
# clang main.c -O3 -o clang-main
# 0.000000 seconds.

Кроме того, реализация 'strchr_x' точно такая же, как и в оригинальной реализации GCC. Вы можете увидеть это в https://github.com/gcc-mirror/gcc/blob/master/libiberty/strchr.c

Когда я использую метод 'strchr' в стандартной библиотеке;Время выполнения GCC уменьшилось до 0,015625 секунд.

Итак, мои вопросы:

  1. Почему существует огромная разница в производительности между моим 'strchr_x' и 'strchr' стандартной библиотеки в GCC?
  2. Почему существует огромный разрыв производительности между GCC и Clang?

Ответы [ 2 ]

3 голосов
/ 08 ноября 2019

Если вы возьмете свой код и подключите его к https://godbolt.org/, вы увидите, что Clang оптимизирует весь цикл for, что объясняет, почему он выполняется за 0 секунд. Вероятно, это происходит потому, что единственным побочным эффектом get является malloc, а результат освобождается немедленно.

РЕДАКТИРОВАТЬ: GCC действительно не очень хорошо работает с вашим кодом, кажется ... Я проверилснова сгенерировал ассемблер, и не только он не может удалить пустой цикл for (для strchr ()), но также не может удалить вызовы функций в теле цикла (для strchr_x ()).

В итоге все сводится к довольно странному поведению оптимизации, и ваш самый медленный пример на самом деле единственный, который вообще что-то делает. Я не знаю, , почему GCC так сильно терпит неудачу в вашем примере, но я определенно согласен, что вы должны сообщить об этом как об ошибке (возможно, даже о двух отдельных ошибках, так как это уже дает сбойпри использовании strchr (), и еще сложнее при использовании strchr_x (), хотя оба должны быть идентичны)

0 голосов
/ 08 ноября 2019

Краткий ответ на вопрос два - clang (LLVM) имеет лучшую оптимизацию кода и ссылок во время выполнения.

Теперь я приведу один пример из опыта. Подходит проект, на котором я работаю над обязательным тестированием на устройствах Raspberry Pi-3. Когда я компилировал с clang++, это заняло около 15 минут, а когда с gcc, после более чем 40 минут долгой ожидания компиляции, в самом конце во время компоновки, сборка просто исчерпала память! Почему? Опять же, clang предлагает лучшую оптимизацию временного кода компиляции и фоновое связывание.

Однако, это ЗАВИСИТ, вы не можете получить ту же разницу на разных уровнях Ox (попробуйте с O2, и вы увидите). Для большей справки я думаю, что эти две статьи дают некоторые подробные объяснения.

https://medium.com/@alitech_2017/gcc-vs-clang-llvm-an-in-depth-comparison-of-c-c-compilers-899ede2be378

https://clang.llvm.org/comparison.html

...