4242except ImportError :
4343 WALK = os .walk
4444 try :
45- LIST = os .scandir # pylint: disable=no-name-in-module
45+ LIST = os .scandir # type: ignore # pylint: disable=no-name-in-module
4646 except AttributeError :
4747 LIST = os .listdir
4848
@@ -94,7 +94,7 @@ def filesBeneath(baseDir):
9494
9595
9696def childDirectories (path , absolute = True ):
97- supportsScandir = (LIST != os .listdir )
97+ supportsScandir = (LIST != os .listdir ) # pylint: disable=comparison-with-callable
9898 for entry in LIST (path ):
9999 if supportsScandir :
100100 if entry .is_dir ():
@@ -116,6 +116,44 @@ def normalizeBaseDir(baseDir):
116116 return None
117117
118118
119+ class SuspendTracker ():
120+ fileTracker = None
121+ def __init__ (self ):
122+ if not SuspendTracker .fileTracker :
123+ if windll .kernel32 .GetModuleHandleW ("FileTracker.dll" ):
124+ SuspendTracker .fileTracker = windll .FileTracker
125+ elif windll .kernel32 .GetModuleHandleW ("FileTracker32.dll" ):
126+ SuspendTracker .fileTracker = windll .FileTracker32
127+
128+ def __enter__ (self ):
129+ SuspendTracker .suspend ()
130+
131+ def __exit__ (self , typ , value , traceback ):
132+ SuspendTracker .resume ()
133+
134+ @staticmethod
135+ def suspend ():
136+ if SuspendTracker .fileTracker :
137+ SuspendTracker .fileTracker .SuspendTracking ()
138+
139+ @staticmethod
140+ def resume ():
141+ if SuspendTracker .fileTracker :
142+ SuspendTracker .fileTracker .ResumeTracking ()
143+
144+ def isTrackerEnabled ():
145+ return 'TRACKER_ENABLED' in os .environ
146+
147+ def untrackable (func ):
148+ if not isTrackerEnabled ():
149+ return func
150+
151+ def untrackedFunc (* args , ** kwargs ):
152+ with SuspendTracker ():
153+ return func (* args , ** kwargs )
154+
155+ return untrackedFunc
156+
119157@contextlib .contextmanager
120158def atomicWrite (fileName ):
121159 tempFileName = fileName + '.new'
@@ -163,7 +201,7 @@ def __str__(self):
163201 return repr (self .message )
164202
165203
166- class Manifest ( object ) :
204+ class Manifest :
167205 def __init__ (self , entries = None ):
168206 if entries is None :
169207 entries = []
@@ -182,7 +220,7 @@ def touchEntry(self, objectHash):
182220 self ._entries .insert (0 , self ._entries .pop (entryIndex ))
183221
184222
185- class ManifestSection ( object ) :
223+ class ManifestSection :
186224 def __init__ (self , manifestSectionDir ):
187225 self .manifestSectionDir = manifestSectionDir
188226 self .lock = CacheLock .forPath (self .manifestSectionDir )
@@ -193,6 +231,7 @@ def manifestPath(self, manifestHash):
193231 def manifestFiles (self ):
194232 return filesBeneath (self .manifestSectionDir )
195233
234+ @untrackable
196235 def setManifest (self , manifestHash , manifest ):
197236 manifestPath = self .manifestPath (manifestHash )
198237 printTraceStatement ("Writing manifest with manifestHash = {} to {}" .format (manifestHash , manifestPath ))
@@ -203,6 +242,7 @@ def setManifest(self, manifestHash, manifest):
203242 jsonobject = {'entries' : entries }
204243 json .dump (jsonobject , outFile , sort_keys = True , indent = 2 )
205244
245+ @untrackable
206246 def getManifest (self , manifestHash ):
207247 fileName = self .manifestPath (manifestHash )
208248 if not os .path .exists (fileName ):
@@ -231,7 +271,7 @@ def allSectionsLocked(repository):
231271 section .lock .release ()
232272
233273
234- class ManifestRepository ( object ) :
274+ class ManifestRepository :
235275 # Bump this counter whenever the current manifest file format changes.
236276 # E.g. changing the file format from {'oldkey': ...} to {'newkey': ...} requires
237277 # invalidation, such that a manifest that was stored using the old format is not
@@ -308,7 +348,7 @@ def getIncludesContentHashForHashes(listOfHashes):
308348 return HashAlgorithm (',' .join (listOfHashes ).encode ()).hexdigest ()
309349
310350
311- class CacheLock ( object ) :
351+ class CacheLock :
312352 """ Implements a lock for the object cache which
313353 can be used in 'with' statements. """
314354 INFINITE = 0xFFFFFFFF
@@ -364,7 +404,7 @@ def forPath(path):
364404 return CacheLock (lockName , timeoutMs )
365405
366406
367- class CompilerArtifactsSection ( object ) :
407+ class CompilerArtifactsSection :
368408 OBJECT_FILE = 'object'
369409 STDOUT_FILE = 'output.txt'
370410 STDERR_FILE = 'stderr.txt'
@@ -413,7 +453,7 @@ def getEntry(self, key):
413453 )
414454
415455
416- class CompilerArtifactsRepository ( object ) :
456+ class CompilerArtifactsRepository :
417457 def __init__ (self , compilerArtifactsRootDir ):
418458 self ._compilerArtifactsRootDir = compilerArtifactsRootDir
419459
@@ -501,7 +541,7 @@ def _normalizedCommandLine(cmdline):
501541 return [arg for arg in cmdline
502542 if not (arg [0 ] in "/-" and arg [1 :].startswith (argsToStrip ))]
503543
504- class CacheFileStrategy ( object ) :
544+ class CacheFileStrategy :
505545 def __init__ (self , cacheDirectory = None ):
506546 self .dir = cacheDirectory
507547 if not self .dir :
@@ -591,7 +631,7 @@ def clean(self, stats, maximumSize):
591631 stats .setNumCacheEntries (currentCompilerArtifactsCount )
592632
593633
594- class Cache ( object ) :
634+ class Cache :
595635 def __init__ (self , cacheDirectory = None ):
596636 if os .environ .get ("CLCACHE_MEMCACHED" ):
597637 from .storage import CacheFileWithMemcacheFallbackStrategy
@@ -644,7 +684,7 @@ def getManifest(self, manifestHash):
644684 return self .strategy .getManifest (manifestHash )
645685
646686
647- class PersistentJSONDict ( object ) :
687+ class PersistentJSONDict :
648688 def __init__ (self , fileName ):
649689 self ._dirty = False
650690 self ._dict = {}
@@ -676,7 +716,7 @@ def __eq__(self, other):
676716 return type (self ) is type (other ) and self .__dict__ == other .__dict__
677717
678718
679- class Configuration ( object ) :
719+ class Configuration :
680720 _defaultValues = {"MaximumCacheSize" : 1073741824 } # 1 GiB
681721
682722 def __init__ (self , configurationFile ):
@@ -701,7 +741,7 @@ def setMaximumCacheSize(self, size):
701741 self ._cfg ["MaximumCacheSize" ] = size
702742
703743
704- class Statistics ( object ) :
744+ class Statistics :
705745 CALLS_WITH_INVALID_ARGUMENT = "CallsWithInvalidArgument"
706746 CALLS_WITHOUT_SOURCE_FILE = "CallsWithoutSourceFile"
707747 CALLS_WITH_MULTIPLE_SOURCE_FILES = "CallsWithMultipleSourceFiles"
@@ -741,13 +781,15 @@ def __init__(self, statsFile):
741781 self ._stats = None
742782 self .lock = CacheLock .forPath (self ._statsFile )
743783
784+ @untrackable
744785 def __enter__ (self ):
745786 self ._stats = PersistentJSONDict (self ._statsFile )
746787 for k in Statistics .RESETTABLE_KEYS | Statistics .NON_RESETTABLE_KEYS :
747788 if k not in self ._stats :
748789 self ._stats [k ] = 0
749790 return self
750791
792+ @untrackable
751793 def __exit__ (self , typ , value , traceback ):
752794 # Does not write to disc when unchanged
753795 self ._stats .save ()
@@ -1026,7 +1068,7 @@ def printTraceStatement(msg: str) -> None:
10261068 print (os .path .join (scriptDir , "clcache.py" ) + " " + msg )
10271069
10281070
1029- class CommandLineTokenizer ( object ) :
1071+ class CommandLineTokenizer :
10301072 def __init__ (self , content ):
10311073 self .argv = []
10321074 self ._content = content
@@ -1154,7 +1196,7 @@ def extendCommandLineFromEnvironment(cmdLine, environment):
11541196 return cmdLine , remainingEnvironment
11551197
11561198
1157- class Argument ( object ) :
1199+ class Argument :
11581200 def __init__ (self , name ):
11591201 self .name = name
11601202
@@ -1192,7 +1234,7 @@ class ArgumentT4(Argument):
11921234 pass
11931235
11941236
1195- class CommandLineAnalyzer ( object ) :
1237+ class CommandLineAnalyzer :
11961238
11971239 @staticmethod
11981240 def _getParameterizedArgumentType (cmdLineArgument ):
@@ -1645,7 +1687,13 @@ def scheduleJobs(cache: Any, compiler: str, cmdLine: List[str], environment: Any
16451687
16461688 exitCode = 0
16471689 cleanupRequired = False
1648- with concurrent .futures .ThreadPoolExecutor (max_workers = jobCount (cmdLine )) as executor :
1690+
1691+ def poolExecutor (* args , ** kwargs ) -> concurrent .futures .Executor :
1692+ if isTrackerEnabled ():
1693+ return concurrent .futures .ProcessPoolExecutor (* args , ** kwargs )
1694+ return concurrent .futures .ThreadPoolExecutor (* args , ** kwargs )
1695+
1696+ with poolExecutor (max_workers = min (jobCount (cmdLine ), len (objectFiles ))) as executor :
16491697 jobs = []
16501698 for (srcFile , srcLanguage ), objFile in zip (sourceFiles , objectFiles ):
16511699 jobCmdLine = baseCmdLine + [srcLanguage + srcFile ]
0 commit comments