Use file mapping in moc.

The change reduces heap allocations by using file mapping instead of
reading a whole file into memory just to create a slightly modified
copy of it.

For this small test case:

 moc <<EOF
  class X : public QObject { Q_OBJECT Q_PROPERTY(int x) };
 EOF

massif shows improvement from:
peak cost: "26,8 KB"  heap "2,1 KB"  heap extra "0 B"  stacks
to:
peak cost: "11,3 KB"  heap "2,2 KB"  heap extra "0 B"  stacks

In general, depending on source file high peak memory usage is reduced
from few to few hundreds KB, especially that the allocation used to
happen for each include file too.

Change-Id: I9c1c848be848444156af25a991b67161fb9d8b29
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
bb10
Jędrzej Nowacki 2014-10-28 12:21:13 +01:00 committed by Jędrzej Nowacki
parent 8c77a7f77a
commit 053e8c41d7
2 changed files with 20 additions and 10 deletions

View File

@ -52,11 +52,12 @@ static QByteArray cleaned(const QByteArray &input)
QByteArray result;
result.reserve(input.size());
const char *data = input.constData();
const char *end = input.constData() + input.size();
char *output = result.data();
int newlines = 0;
while (*data) {
while (*data && is_space(*data))
while (data != end) {
while (data != end && is_space(*data))
++data;
bool takeLine = (*data == '#');
if (*data == '%' && *(data+1) == ':') {
@ -66,15 +67,15 @@ static QByteArray cleaned(const QByteArray &input)
if (takeLine) {
*output = '#';
++output;
do ++data; while (*data && is_space(*data));
do ++data; while (data != end && is_space(*data));
}
while (*data) {
while (data != end) {
// handle \\\n, \\\r\n and \\\r
if (*data == '\\') {
if (*(data + 1) == '\r') {
++data;
}
if (*data && (*(data + 1) == '\n' || (*data) == '\r')) {
if (data != end && (*(data + 1) == '\n' || (*data) == '\r')) {
++newlines;
data += 1;
if (*data != '\r')
@ -964,6 +965,13 @@ int Preprocessor::evaluateCondition()
return expression.value();
}
static QByteArray readOrMapFile(QFile *file)
{
const qint64 size = file->size();
char *rawInput = reinterpret_cast<char*>(file->map(0, size));
return rawInput ? QByteArray::fromRawData(rawInput, size) : file->readAll();
}
void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
{
currentFilenames.push(filename);
@ -1020,7 +1028,8 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
if (!file.open(QFile::ReadOnly))
continue;
QByteArray input = file.readAll();
QByteArray input = readOrMapFile(&file);
file.close();
if (input.isEmpty())
continue;
@ -1157,9 +1166,10 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
currentFilenames.pop();
}
Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file)
Symbols Preprocessor::preprocessed(const QByteArray &filename, QFile *file)
{
QByteArray input = file->readAll();
QByteArray input = readOrMapFile(file);
if (input.isEmpty())
return symbols;

View File

@ -57,7 +57,7 @@ typedef SubArray MacroName;
#endif
typedef QHash<MacroName, Macro> Macros;
class QIODevice;
class QFile;
class Preprocessor : public Parser
{
@ -67,7 +67,7 @@ public:
QList<QByteArray> frameworks;
QSet<QByteArray> preprocessedIncludes;
Macros macros;
Symbols preprocessed(const QByteArray &filename, QIODevice *device);
Symbols preprocessed(const QByteArray &filename, QFile *device);
void parseDefineArguments(Macro *m);