Clang PCH performance worse than with headers?
Asked Answered
U

0

2

I have a set of headers included to source files which is rarely/never changed. Parsing/reparsing of frequently changed source file which uses the headers (IDE use case) takes too long (few seconds). As a way to increase the performance i'd like to use Clang PCHs. Note i'm having libclang (not the most recent version) compiled in Release mode (99% sure) running on Android.

I've followed the answer to a similar question but i have 3 times worse performance with PCH compared to header parsing (with an artificial header with 100000 of #define macros):

2020-08-11 12:03:53.265 19767-19788 W/TranslationUnitTest: PCH parse time: 0.462277
2020-08-11 12:03:53.265 19767-19788 W/TranslationUnitTest: 0 diagnostics
2020-08-11 12:03:55.768 19767-19788 W/TranslationUnitTest: Source parse time: 1.456947
2020-08-11 12:03:55.768 19767-19788 W/TranslationUnitTest: 0 diagnostics

Java source code (running it in Android Instrumentation test):

final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();

// create PCH
dir = new File(context.getCacheDir(), String.valueOf(Math.abs(new Random().nextLong())));
dir.mkdirs();

deeperHeaderFile = new File(dir, "deeperHeader.h");
StringBuilder sb = new StringBuilder("#define VAL 1 ");
for (int i=0; i<100000; i++) {
    sb.append("\n");
    sb.append("#define VAL" + i + " " + i);
}
setFileContent(deeperHeaderFile, sb.toString());

headerFile = new File(dir, "header.hxx");
setFileContent(headerFile, "#include \"deeperHeader.h\"");

pchFile = new File(dir, "header.pch");

sourceFile = new File(dir, "source.cpp");
setFileContent(sourceFile, "#include \"header.hxx\"\nint main() { return VAL; }");

// C++ test
Clang.testPch(
    pchFile.getAbsolutePath(),
    headerFile.getAbsolutePath(),
    deeperHeaderFile.getAbsolutePath(),
    sourceFile.getAbsolutePath());

C++ source code:

class Timer {
public:
    Timer () {
      reset();
    }

    double get () {
      struct timeval now;
      gettimeofday (&now, NULL);

      return now.tv_sec - start_.tv_sec + 1e-6 * (now.tv_usec - start_.tv_usec);
    }

    void reset () {
      gettimeofday (&start_, NULL);
    }

private:
    struct timeval start_;
};

void displayDiagnostics(CXTranslationUnit TU) {
  if (TU == 0) {
    std::cerr << "Parsing error!" << std::endl;
    return;
  }

  int numDiagnostics = clang_getNumDiagnostics (TU);

  __android_log_print(ANDROID_LOG_WARN, TAG, "%d diagnostics", numDiagnostics);

  for (int i=0 ; i<numDiagnostics ; ++i) {
    auto diagnostic = clang_getDiagnostic(TU, i);
    auto string = clang_formatDiagnostic(diagnostic, clang_defaultDiagnosticDisplayOptions());
    auto cString = clang_getCString(string);

    __android_log_print(ANDROID_LOG_WARN, TAG, "diag #%d: %s", i, cString);

    clang_disposeString(string);
    clang_disposeDiagnostic(diagnostic);
  }
}

JNIEXPORT void JNICALL Clang_testPch(
    JNIEnv *env, jclass clazz,
    jstring jPchFilename, jstring jHeaderFilename, jstring jDeeperHeaderFilename, jstring jSourceFilename) {

  char *cPchFilename = string_copy(env, jPchFilename);
  char *cHeaderFilename = string_copy(env, jHeaderFilename);
  char *cDeeperHeaderFilename = string_copy(env, jDeeperHeaderFilename);
  char *cSourceFilename = string_copy(env, jSourceFilename);

  auto Idx = clang_createIndex (0, 0);
  CXTranslationUnit TU;
  Timer t;

  {
    char const *args[] = { "-xc++", cHeaderFilename };
    int nargs = 2;

    t.reset();
    TU = clang_parseTranslationUnit(Idx, 0, args, nargs, 0, 0, CXTranslationUnit_ForSerialization);
    auto pchParsetime = t.get();
    __android_log_print(ANDROID_LOG_WARN, TAG, "PCH parse time: %f", pchParsetime);
    displayDiagnostics(TU);
    clang_saveTranslationUnit(TU, cPchFilename, clang_defaultSaveOptions(TU));
    clang_disposeTranslationUnit(TU);
  }

  {
    char const *args[] = { "-include-pch", cPchFilename, cSourceFilename };
    int nargs = 3;

    t.reset();
    TU = clang_createTranslationUnitFromSourceFile(Idx, 0, nargs, args, 0, 0);
    auto parseTime = t.get();
    __android_log_print(ANDROID_LOG_WARN, TAG, "Source parse time: %f", parseTime);
    displayDiagnostics(TU);
    clang_disposeTranslationUnit(TU);
  }

  // release
  delete []cPchFilename;
  delete []cHeaderFilename;
  delete []cDeeperHeaderFilename;
  delete []cSourceFilename;
}

I believe it does not make a difference that the files are written in Java (the original reason is that i have clang bindings and Java code has the same [bad] performance, so i changed the code to be tested in C++).

Do i miss anything? Any silly mistakes? Any suggestions?

Unmeaning answered 11/8, 2020 at 8:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.