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?