From 6a541fd692b3047507849d98395924e8f48f596c Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 14 Aug 2018 18:30:47 +0200 Subject: [PATCH] Clang: Add sources manager Indexing source files multiple times is unneeded overhead in many cases. The source manager is a support class to handle that cases. Change-Id: Id737eaa9a691c54563279562833493a221eb3431 Reviewed-by: Ivan Donchevskii --- .../source/clangrefactoringbackend-source.pri | 3 +- .../source/sourcesmanager.h | 106 +++++++++++++ tests/unit/unittest/sourcesmanager-test.cpp | 139 ++++++++++++++++++ tests/unit/unittest/unittest.pro | 3 +- 4 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 src/tools/clangrefactoringbackend/source/sourcesmanager.h create mode 100644 tests/unit/unittest/sourcesmanager-test.cpp diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index c0d8efe87ac..30a651a81c1 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -22,7 +22,8 @@ HEADERS += \ $$PWD/projectpartartefact.h \ $$PWD/filestatuscache.h \ $$PWD/indexdataconsumer.h \ - $$PWD/projectpartqueue.h + $$PWD/projectpartqueue.h \ + $$PWD/sourcesmanager.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ diff --git a/src/tools/clangrefactoringbackend/source/sourcesmanager.h b/src/tools/clangrefactoringbackend/source/sourcesmanager.h new file mode 100644 index 00000000000..25451b676a4 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/sourcesmanager.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +namespace ClangBackEnd { + +class SourcesManager +{ + struct FilePathIdTime + { + FilePathIdTime(FilePathId filePathId, std::time_t modifiedTime) + : filePathId(filePathId), + modifiedTime(modifiedTime) + {} + FilePathId filePathId; + std::time_t modifiedTime = 0; + }; + +public: + bool alreadyParsed(FilePathId filePathId, std::time_t modifiedTime) + { + auto found = std::lower_bound(m_modifiedTimeStamps.cbegin(), + m_modifiedTimeStamps.cend(), + filePathId, + [] (FilePathIdTime entry, FilePathId filePathId) { + return entry.filePathId < filePathId; + }); + + bool upToDate = found != m_modifiedTimeStamps.end() && found->filePathId == filePathId + && modifiedTime <= found->modifiedTime; + + if (!upToDate) + addOrUpdateNewEntry(filePathId, modifiedTime); + + return upToDate ; + } + + void updateModifiedTimeStamps() + { + std::vector mergedModifiedTimeStamps; + mergedModifiedTimeStamps.reserve(m_newModifiedTimeStamps.size() + m_modifiedTimeStamps.size()); + + auto compare = [](FilePathIdTime first, FilePathIdTime second) { + return first.filePathId < second.filePathId; + }; + + std::set_union(m_newModifiedTimeStamps.begin(), + m_newModifiedTimeStamps.end(), + m_modifiedTimeStamps.begin(), + m_modifiedTimeStamps.end(), + std::back_inserter(mergedModifiedTimeStamps), + compare); + + m_modifiedTimeStamps = std::move(mergedModifiedTimeStamps); + m_newModifiedTimeStamps.clear(); + } + +private: + void addOrUpdateNewEntry(FilePathId filePathId, std::time_t modifiedTime) + { + auto found = std::lower_bound(m_newModifiedTimeStamps.begin(), + m_newModifiedTimeStamps.end(), + filePathId, + [] (FilePathIdTime entry, FilePathId filePathId) { + return entry.filePathId < filePathId; + }); + + if (found != m_newModifiedTimeStamps.end() && found->filePathId == filePathId) + found->modifiedTime = modifiedTime; + else + m_newModifiedTimeStamps.emplace(found, filePathId, modifiedTime); + } + +private: + std::vector m_modifiedTimeStamps; + std::vector m_newModifiedTimeStamps; +}; + +} diff --git a/tests/unit/unittest/sourcesmanager-test.cpp b/tests/unit/unittest/sourcesmanager-test.cpp new file mode 100644 index 00000000000..f20cb1b143f --- /dev/null +++ b/tests/unit/unittest/sourcesmanager-test.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include + +namespace { + +class SourcesManager : public testing::Test +{ +protected: + ClangBackEnd::SourcesManager sources; +}; + +TEST_F(SourcesManager, TouchFilePathIdFirstTime) +{ + ASSERT_FALSE(sources.alreadyParsed({1, 1}, 56)); +} + +TEST_F(SourcesManager, TouchFilePathIdTwoTimesWithSameTime) +{ + sources.alreadyParsed({1, 1}, 56); + + ASSERT_FALSE(sources.alreadyParsed({1, 1}, 56)); +} + +TEST_F(SourcesManager, TouchFilePathIdSecondTimeWithSameTime) +{ + sources.alreadyParsed({1, 1}, 56); + + sources.updateModifiedTimeStamps(); + + ASSERT_TRUE(sources.alreadyParsed({1, 1}, 56)); +} + +TEST_F(SourcesManager, TouchFilePathIdSecondTimeWithOlderTime) +{ + sources.alreadyParsed({1, 1}, 56); + + sources.updateModifiedTimeStamps(); + + ASSERT_TRUE(sources.alreadyParsed({1, 1}, 55)); +} + +TEST_F(SourcesManager, TouchFilePathIdSecondTimeWithNewerTime) +{ + sources.alreadyParsed({1, 1}, 56); + + sources.updateModifiedTimeStamps(); + + ASSERT_FALSE(sources.alreadyParsed({1, 1}, 57)); +} + +TEST_F(SourcesManager, MultipleFileIds) +{ + sources.alreadyParsed({1, 1}, 455); + sources.alreadyParsed({1, 4}, 56); + sources.alreadyParsed({1, 3}, 85); + sources.alreadyParsed({1, 6}, 56); + sources.alreadyParsed({1, 2}, 45); + + sources.updateModifiedTimeStamps(); + + ASSERT_TRUE(sources.alreadyParsed({1, 3}, 85)); +} + +TEST_F(SourcesManager, UpdateModifiedTimeStampsWithNewerTimeStamp) +{ + sources.alreadyParsed({1, 1}, 455); + sources.alreadyParsed({1, 4}, 56); + sources.alreadyParsed({1, 3}, 85); + sources.alreadyParsed({1, 6}, 56); + sources.alreadyParsed({1, 2}, 45); + sources.updateModifiedTimeStamps(); + + sources.alreadyParsed({1, 3}, 86); + sources.updateModifiedTimeStamps(); + + ASSERT_TRUE(sources.alreadyParsed({1, 3}, 86)); +} + +TEST_F(SourcesManager, DontUpdateModifiedTimeStampsWithOlderTimeStamp) +{ + sources.alreadyParsed({1, 1}, 455); + sources.alreadyParsed({1, 4}, 56); + sources.alreadyParsed({1, 3}, 85); + sources.alreadyParsed({1, 6}, 56); + sources.alreadyParsed({1, 2}, 45); + sources.updateModifiedTimeStamps(); + + sources.alreadyParsed({1, 3}, 84); + sources.updateModifiedTimeStamps(); + + ASSERT_TRUE(sources.alreadyParsed({1, 3}, 85)); +} + +TEST_F(SourcesManager, ZeroTime) +{ + sources.alreadyParsed({1, 1}, 0); + + sources.updateModifiedTimeStamps(); + + ASSERT_TRUE(sources.alreadyParsed({1, 1}, 0)); +} + +TEST_F(SourcesManager, TimeIsUpdated) +{ + sources.alreadyParsed({1, 1}, 56); + sources.alreadyParsed({1, 1}, 57); + + sources.updateModifiedTimeStamps(); + + ASSERT_TRUE(sources.alreadyParsed({1, 1}, 57)); +} + +} diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index b191d1a1d8b..c52896eedf0 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -94,7 +94,8 @@ SOURCES += \ highlightingresultreporter-test.cpp \ precompiledheaderstorage-test.cpp \ projectpartqueue-test.cpp \ - generatedfiles-test.cpp + generatedfiles-test.cpp \ + sourcesmanager-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \