diff --git a/lib/internal/Magento/Framework/Module/Dir/Reader.php b/lib/internal/Magento/Framework/Module/Dir/Reader.php
index 7a8b1f11ef184654ee6e8318438610f552907809..353f7e51c590687823303f68aef2cd7899d2452f 100644
--- a/lib/internal/Magento/Framework/Module/Dir/Reader.php
+++ b/lib/internal/Magento/Framework/Module/Dir/Reader.php
@@ -46,6 +46,13 @@ class Reader
      */
     protected $readFactory;
 
+    /**
+     * Found configuration files grouped by configuration types (filename).
+     *
+     * @var array
+     */
+    private $fileIterators = [];
+
     /**
      * @param Dir $moduleDirs
      * @param ModuleListInterface $moduleList
@@ -65,24 +72,42 @@ class Reader
     }
 
     /**
-     * Go through all modules and find configuration files of active modules
+     * Go through all modules and find configuration files of active modules.
      *
      * @param string $filename
      * @return FileIterator
      */
     public function getConfigurationFiles($filename)
     {
-        return $this->fileIteratorFactory->create($this->getFiles($filename, Dir::MODULE_ETC_DIR));
+        return $this->getFilesIterator($filename, Dir::MODULE_ETC_DIR);
     }
 
     /**
-     * Go through all modules and find composer.json files of active modules
+     * Go through all modules and find composer.json files of active modules.
      *
      * @return FileIterator
      */
     public function getComposerJsonFiles()
     {
-        return $this->fileIteratorFactory->create($this->getFiles('composer.json'));
+        return $this->getFilesIterator('composer.json');
+    }
+
+    /**
+     * Retrieve iterator for files with $filename from components located in component $subDir.
+     *
+     * @param string $filename
+     * @param string $subDir
+     *
+     * @return FileIterator
+     */
+    private function getFilesIterator($filename, $subDir = '')
+    {
+        if (!isset($this->fileIterators[$subDir][$filename])) {
+            $this->fileIterators[$subDir][$filename] = $this->fileIteratorFactory->create(
+                $this->getFiles($filename, $subDir)
+            );
+        }
+        return $this->fileIterators[$subDir][$filename];
     }
 
     /**
@@ -96,9 +121,9 @@ class Reader
     {
         $result = [];
         foreach ($this->modulesList->getNames() as $moduleName) {
-            $moduleEtcDir = $this->getModuleDir($subDir, $moduleName);
-            $file = $moduleEtcDir . '/' . $filename;
-            $directoryRead = $this->readFactory->create($moduleEtcDir);
+            $moduleSubDir = $this->getModuleDir($subDir, $moduleName);
+            $file = $moduleSubDir . '/' . $filename;
+            $directoryRead = $this->readFactory->create($moduleSubDir);
             $path = $directoryRead->getRelativePath($file);
             if ($directoryRead->isExist($path)) {
                 $result[] = $file;
@@ -159,5 +184,6 @@ class Reader
     public function setModuleDir($moduleName, $type, $path)
     {
         $this->customModuleDirs[$moduleName][$type] = $path;
+        $this->fileIterators = [];
     }
 }
diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
index 65c0b090d6334a0ef6f6ffaa2a3c8b229389d073..3f577d9b3118755c88a575954c317d7ef140fb5e 100644
--- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
@@ -140,17 +140,9 @@ class DiCompileCommand extends Command
             'library' => $libraryPaths,
             'generated_helpers' => $generationPath
         ];
-        $excludedModulePaths = [];
-        foreach ($modulePaths as $appCodePath) {
-            $excludedModulePaths[] = '#^' . $appCodePath . '/Test#';
-        }
-        $excludedLibraryPaths = [];
-        foreach ($libraryPaths as $libraryPath) {
-            $excludedLibraryPaths[] = '#^' . $libraryPath . '/([\\w]+/)?Test#';
-        }
         $this->excludedPathsList = [
-            'application' => $excludedModulePaths,
-            'framework' => $excludedLibraryPaths
+            'application' => $this->getExcludedModulePaths($modulePaths),
+            'framework' => $this->getExcludedLibraryPaths($libraryPaths),
         ];
         $this->configureObjectManager($output);
 
@@ -205,6 +197,54 @@ class DiCompileCommand extends Command
         }
     }
 
+    /**
+     * Build list of module path regexps which should be excluded from compilation
+     *
+     * @param string[] $modulePaths
+     * @return string[]
+     */
+    private function getExcludedModulePaths(array $modulePaths)
+    {
+        $modulesByBasePath = [];
+        foreach ($modulePaths as $modulePath) {
+            $moduleDir = basename($modulePath);
+            $vendorPath = dirname($modulePath);
+            $vendorDir = basename($vendorPath);
+            $basePath = dirname($vendorPath);
+            $modulesByBasePath[$basePath][$vendorDir][] = $moduleDir;
+        }
+
+        $basePathsRegExps = [];
+        foreach ($modulesByBasePath as $basePath => $vendorPaths) {
+            $vendorPathsRegExps = [];
+            foreach ($vendorPaths as $vendorDir => $vendorModules) {
+                $vendorPathsRegExps[] = $vendorDir
+                    . '/(?:' . join('|', $vendorModules) . ')';
+            }
+            $basePathsRegExps[] = $basePath
+                . '/(?:' . join('|', $vendorPathsRegExps) . ')';
+        }
+
+        $excludedModulePaths = [
+            '#^(?:' . join('|', $basePathsRegExps) . ')/Test#',
+        ];
+        return $excludedModulePaths;
+    }
+
+    /**
+     * Build list of library path regexps which should be excluded from compilation
+     *
+     * @param string[] $libraryPaths
+     * @return string[]
+     */
+    private function getExcludedLibraryPaths(array $libraryPaths)
+    {
+        $excludedLibraryPaths = [
+            '#^(?:' . join('|', $libraryPaths) . ')/([\\w]+/)?Test#',
+        ];
+        return $excludedLibraryPaths;
+    }
+
     /**
      * Delete directories by their code from "var" directory
      *