Constantine,
On 01.02.2015 22:25, Constantine wrote:
Good results, Dirk.
It's definitely worth to use posix_spawn.
When do you plan to integrate the experimental version into the mainline?
next step is switching the Node class to using __slots__, then we want to do a full release 2.4. After that, the version 2.5 will
contain the stubprocess/posix_spawn wrapper...if all goes well.
/> .. including some hacks to exploit the uniform structure of the benchmark
sources//../
What kind of hacks?
How do they affect performance?
I pre-expanded the CXXCOM action string like this:
DefaultEnvironment(tools=[])
env = Environment(tools=['g++','ar','link','fastcpp'],
CPPFLAGS=['-Wall'], CPPDEFINES=['LINUX'],
CPPPATH=[Dir('#')])
env['CXXCOM'] = 'g++ -o $TARGET -c -Wall -I. -DLINUX $SOURCES'
because it stays the same all the time. This shortcuts a lot of subst()ing of strings. As you can see, I also used the "fastcpp"
Tool which additionally replaces the default suffixes for CPP/object files with their actual strings.
For some classes like Action, I found several places where a lot of checking is done, in order to provide maximum flexibility. It's
normally allowed to pass a sequence of mixed strings and Nodes as "target" or "source" parameter. Here, I assume that it's always a
list of strings...so the check is commented out. For the full changes see the attached patch, they cut the complete reading/parsing
of all SConscripts down to 30 seconds.
This is only to show that the basic design of SCons is able to provide fast results, when turning the right knobs...and also to
identify the places where most of the runtime is spent. Whether to actually include some of my hacks, and in which form
(command-line option?, Tool?) would still have to be discussed.
Thank you for testing the clean targets case.
I haven't tested this case on large projects.
You should definitely have a look at this. It seems to get worse when the number of total files for the build increases. By the way,
do you support custom commands and generated files in Aqualid? Like, let's say:
- "foo.c" is compiled to the "foo" executable
- "foo" is then used to create the header "bar.h"
- "bar.h" is an implicit dependency of "bar.c"
- "bar.c" is compiled to "bar"
It would also be interesting to see how well Aqualid is doing in the build
system shootout:
https://github.com/ndmitchell/build-shootout
by Neil Mitchell. Have a look at it, if you find the time.
Best regards,
Dirk
# HG changeset patch
# Parent 35dbc21379ec919c648e12e8822962d6991a585b
diff -r 35dbc21379ec -r 23b208e01c06 src/engine/SCons/Action.py
--- a/src/engine/SCons/Action.py Sun Dec 21 13:13:44 2014 +0100
+++ b/src/engine/SCons/Action.py Sat Jan 31 00:33:20 2015 +0100
@@ -99,8 +99,6 @@
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import SCons.compat
-
import dis
import os
# compat layer imports "cPickle" for us if it's available.
@@ -112,7 +110,6 @@
import SCons.Debug
from SCons.Debug import logInstanceCreation
import SCons.Errors
-import SCons.Executor
import SCons.Util
import SCons.Subst
@@ -357,21 +354,6 @@
if isinstance(act, ActionBase):
return act
- if is_List(act):
- return CommandAction(act, **kw)
-
- if callable(act):
- try:
- gen = kw['generator']
- del kw['generator']
- except KeyError:
- gen = 0
- if gen:
- action_type = CommandGeneratorAction
- else:
- action_type = FunctionAction
- return action_type(act, kw)
-
if is_String(act):
var=SCons.Util.get_environment_var(act)
if var:
@@ -388,6 +370,22 @@
# The list of string commands may include a LazyAction, so we
# reprocess them via _do_create_list_action.
return _do_create_list_action(commands, kw)
+
+ if is_List(act):
+ return CommandAction(act, **kw)
+
+ if callable(act):
+ try:
+ gen = kw['generator']
+ del kw['generator']
+ except KeyError:
+ gen = 0
+ if gen:
+ action_type = CommandGeneratorAction
+ else:
+ action_type = FunctionAction
+ return action_type(act, kw)
+
# Catch a common error case with a nice message:
if isinstance(act, int) or isinstance(act, float):
raise TypeError("Don't know how to create an Action from a number (%s)"%act)
diff -r 35dbc21379ec -r 23b208e01c06 src/engine/SCons/Environment.py
--- a/src/engine/SCons/Environment.py Sun Dec 21 13:13:44 2014 +0100
+++ b/src/engine/SCons/Environment.py Sat Jan 31 00:33:20 2015 +0100
@@ -456,35 +456,38 @@
if not args:
return []
- args = SCons.Util.flatten(args)
+ #args = SCons.Util.flatten(args)
nodes = []
+ kw['raw'] = 1
for v in args:
if SCons.Util.is_String(v):
- n = None
- for l in lookup_list:
- n = l(v)
- if n is not None:
- break
- if n is not None:
- if SCons.Util.is_String(n):
- # n = self.subst(n, raw=1, **kw)
- kw['raw'] = 1
- n = self.subst(n, **kw)
- if node_factory:
- n = node_factory(n)
- if SCons.Util.is_List(n):
- nodes.extend(n)
- else:
- nodes.append(n)
- elif node_factory:
+# n = None
+# for l in lookup_list:
+# n = l(v)
+# if n is not None:
+# break
+# if n is not None:
+# if SCons.Util.is_String(n):
+# # n = self.subst(n, raw=1, **kw)
+# kw['raw'] = 1
+# n = self.subst(n, **kw)
+# if node_factory:
+# n = node_factory(n)
+# if SCons.Util.is_List(n):
+# nodes.extend(n)
+# else:
+# nodes.append(n)
+# elif node_factory:
+ if node_factory:
# v = node_factory(self.subst(v, raw=1, **kw))
- kw['raw'] = 1
- v = node_factory(self.subst(v, **kw))
- if SCons.Util.is_List(v):
- nodes.extend(v)
- else:
- nodes.append(v)
+ #kw['raw'] = 1
+ #v = node_factory(self.subst(v, **kw))
+ #if SCons.Util.is_List(v):
+ # nodes.extend(v)
+ #else:
+ # nodes.append(v)
+ nodes.append(node_factory(v))
else:
nodes.append(v)
diff -r 35dbc21379ec -r 23b208e01c06 src/engine/SCons/Executor.py
--- a/src/engine/SCons/Executor.py Sun Dec 21 13:13:44 2014 +0100
+++ b/src/engine/SCons/Executor.py Sat Jan 31 00:33:20 2015 +0100
@@ -577,20 +577,19 @@
nullenv = None
+import SCons.Util
+class NullEnvironment(SCons.Util.Null):
+ import SCons.CacheDir
+ _CacheDir_path = None
+ _CacheDir = SCons.CacheDir.CacheDir(None)
+ def get_CacheDir(self):
+ return self._CacheDir
def get_NullEnvironment():
"""Use singleton pattern for Null Environments."""
global nullenv
- import SCons.Util
- class NullEnvironment(SCons.Util.Null):
- import SCons.CacheDir
- _CacheDir_path = None
- _CacheDir = SCons.CacheDir.CacheDir(None)
- def get_CacheDir(self):
- return self._CacheDir
-
- if not nullenv:
+ if nullenv is None:
nullenv = NullEnvironment()
return nullenv
diff -r 35dbc21379ec -r 23b208e01c06 src/engine/SCons/Node/FS.py
--- a/src/engine/SCons/Node/FS.py Sun Dec 21 13:13:44 2014 +0100
+++ b/src/engine/SCons/Node/FS.py Sat Jan 31 00:33:20 2015 +0100
@@ -2322,23 +2322,13 @@
raise SCons.Errors.UserError(msg)
# There is no Node for this path name, and we're allowed
# to create it.
- # (note: would like to use p.rsplit('/',1) here but
- # that's not in python 2.3)
- # e.g.: dir_name, file_name = p.rsplit('/',1)
- last_slash = p.rindex('/')
- if (last_slash >= 0):
- dir_name = p[:last_slash]
- file_name = p[last_slash+1:]
- else:
- dir_name = p # shouldn't happen, just in case
- file_name = ''
-
+ dir_name, file_name = p.rsplit('/',1)
dir_node = self._lookup_abs(dir_name, Dir)
result = klass(file_name, dir_node, self.fs)
# Double-check on disk (as configured) that the Node we
# created matches whatever is out there in the real world.
- result.diskcheck_match()
+ #result.diskcheck_match()
self._lookupDict[k] = result
dir_node.entries[_my_normcase(file_name)] = result
@@ -2346,7 +2336,8 @@
else:
# There is already a Node for this path name. Allow it to
# complain if we were looking for an inappropriate type.
- result.must_be_same(klass)
+ pass
+ #result.must_be_same(klass)
return result
def __str__(self):
diff -r 35dbc21379ec -r 23b208e01c06 src/engine/SCons/Platform/posix.py
--- a/src/engine/SCons/Platform/posix.py Sun Dec 21 13:13:44 2014 +0100
+++ b/src/engine/SCons/Platform/posix.py Sat Jan 31 00:33:20 2015 +0100
@@ -36,6 +36,7 @@
import os
import os.path
import subprocess
+import stubprocess
import sys
import select
_______________________________________________
Scons-dev mailing list
[email protected]
https://pairlist2.pair.net/mailman/listinfo/scons-dev