I think it is that Parts tries to use DB data smarter than SCons does. For me 
the understanding of the logic needed to validate that something is good or bad 
with MD5 I believe is the item that I had to learned from SCons. When we look 
at scons, it tries to keep it simple. This is good in general. The main logic 
SCons has is to:

1)      read all build script

a.       while reading files create nodes

b.      execute other logic ( ie scanning disk for Glob() etc

2)      once everything is read in turn targets into “node” objects

3)      for each target node, grab target node object and start building 
children ( uses cache info to determine if a node is out of date or not)

a.       if all children are up-to-date.. report everything up-to-date

This works great in general. But there are a few area that take a long time.


1)      Reading all the script take time. The question is why. Python is very 
fast reading source files and making byte code to be processed. What takes time 
is the execution of the python file as it read in. The structure for a 
scontruct is to have python read it and then execute it. While it is execute, 
time consuming items happen, such as scanning disk with a SCons Glob ( or a 
Parts Pattern) call. Another time taking item is creating the nodes. SCons does 
what it can to make this faster, but it takes time. It gets worse as the system 
has to allocate more memory.

2)      Given everything is loaded SCons processes the DAG to build stuff. It 
does not know if the target are up to date or not. SCons at this point has to 
process all the target nodes and its children. It takes time as SCons scans, 
subst, create build environments and check if there are different, etc 
everything as it would to do a build. In fact a do nothing build and a do 
something build only difference is if SCons will execute the build action or 
not. This is why it takes SCons so long to do say everything is up-to-date on 
do nothing build.

For me the interesting about SCons was that it had a DB/cache that can be used 
to make sure the build is good or bad. What it missed is that this information 
can be used to speed up the build as well. This is what Parts does. There are 
still a lot that can be done to be smarter in Parts ( in hindsight I should 
have done a few items differently). Given what we have at the moment Parts does 
this:

We read the SConstruct file. Each Parts call is noted, not nothing is read yet. 
Once the SConstruct is read, Parts uses a monkey patch to get called before 
SCons tries to build anything.

·         At this point Parts looks to see if a .parts-cache exists.

o   If it does not, we load each Parts normally, make our “Part” based targets 
SCons compatible and follow normal SCons logic, minus our hooks to do some 
extra stuff, such as store extra information in the Parts cache.

·         Given that it exists we load information in the cache ( this is 
general logic)

o    Parts looks to see what defining files have been modified. By this did are 
the set of Parts different in some way, are any Parts files different, are any 
Part configuration files, or files that define builders changed. This with a 
SCons based timestamp-md5 check is very fast. This tells me if anything that 
defined the main build tree we had from the last build might have changed. If 
anything changed we know we need to load these files and anything that might 
depend on it. There is more logic here to check dependency state changes etc.. 
This tells us that something might have changed that requires us to load these 
files. Items that could have changed are the build environment ( SCons will 
check this given we load the files) what we are building changed in some way ( 
ie source files changes, build files changes in what or how to build, etc). It 
is important that all Parts is doing here is a test to see if something changed 
so we cannot say with 100% certainty that something is not different. If still 
might be ok, but something changed so we will load it, to allow SCons to make 
the correct call.

o   The next check is to see if to check the nodes that are needed to build a 
given target. Since we know at this point if something that might have changes 
large section of the known DAG has changed, we only need to test any 
component/Parts that still looks up to date and would be part of the targets 
the user wants to build. So we use the stored Ninfo data to check the leaf node 
on up to known point of stuff being possibly out of date to see if we need to 
load a part or not. This case is what happens most of the time when a developer 
does a build as a source file changed. This for Parts is hard coded to use the 
SCons timestamp-MD5 sig logic as it is the fastest of the group and does not 
lose correctness, as if a timestamp is out of data, we then do a MD5 check to 
make sure it is really out of date. This takes the longest  when nothing 
changed as it has to test all known nodes for the targets in question to be 
able to say it is up-to-date. The logic that many miss is the it can generally 
stop once we find something is out of date as we don’t have to check all the 
other node for a given component. We don’t care if more of them are out of 
date, we know something is out of date so mark this parts to be loaded.

o   At this point we know what Parts we have to load, before we load them we do 
a quick pass to make sure any Parts that we would load have its dependents 
loaded from cache. This is loads a set of state that we have to have to make 
sure SCons can build everything correctly

o   So then we load each Parts and lets SCons do its thing. IF nothing is to be 
done, we force SCons to exist early and say everything is up-to-date.

This is main logic for the default “loader” as it is defined in Parts. Parts 
has four loaders at the moment that can be controlled via a --load-logic or 
--ll switch. These logics are as follows:


1)      All – Load everything. Used when we have not parts cache. Basically 
this is default SCons logic

2)      Targets – this load all files Parts files for a given target. Does not 
check if anything is out of date or not. Like All but loads a smaller set 
depending on the targets.

3)      Unsafe ( no depends) – this load the target Parts files and its direct 
dependency from cache. This is very fast, but very unsafe as it require that 
the user know that nothing changed.

4)      Min ( default logic) – given we have a parts cache does the logic as I 
describe above. Its goal is to be correct first, fast second.

So there are area’s of improvement to make still.
For example there some cases that are not checked in the cases of inputs to a 
parts call. Some logic could be added to reduce that pain of globs and Patterns 
calls to scan the disk which is a big time sucker for loading. ( it should be 
noted that the scanning the disk is a lot easier than defining a huge static 
array or string of nodes to be built). There is a case in which parts will not 
correct see that a file would be added to a scan on disk, which should have 
caused that Part file to be loaded. I should note that caching what is one disk 
in memory is a big time saver as well ( need to do) as for large build is 
common for a area on disk to be scanned many time for the different file ( or 
the same files in case of a cross build). This is a big deal for build system 
as the calling the system over and over again is “slow”.

So minus those opportunities for improvements, what could be done differently.

I found that I used the subst() system to pass data between components. In 
general this works well, but the subst system is inherently slow and has bugs. 
I did this to help make sure the that order in which a part is defined in a 
SConstruct does not matter. The main problem beside the extra time this can add 
to any build, is that functionally the system does not pass objects well, only 
strings ( which is expected I would think). This is a problem as I found there 
was an unexpected, but more common use case that happens in a logic of builds. 
This is that people want to define dynamic builders to be shared between 
components. As it turns out many project want to define a Part/component that 
defines a custom builder and they want to export it and have it imported as a 
dependency to certain components. Given this worked well, this would be great 
as a Parts allow for Symantec versioning which allows for controllable way to 
make sure the correct version is being used ( or more than one version if 
hackery has to be done to get something working quickly). While there is a work 
around to get to logic to work in some way, it is not very usable, unless I 
remove the subst() logic to pass dependency. This can only be done, if I can 
control the load order better. However this is complex as we have to know what 
to load, but we cannot know that before we load stuff to see what we need to 
know. This chicken and an egg problem can be solved two ways:


1)      A continuous loader ( in the works) which load a component to a depends 
statement and stop to load something else till we have what we need to continue 
load a given parts file. This is complex, but has backwards compatibility with 
existing code, which I have to have ( cannot tell people redo your build files…)

2)      A new format ( ie migrate to this). I had proto types this before, but 
could not implement it until I do 1). The main reason is that I had to 
internally at work provide some speed gains without a new format. This is the 
harder path, but is needed when you have a number of project depending on you. 
Given I get to the new format. What would it look like and who would it help. 
Given the time it takes SCons to start up, before it starts building anything ( 
which is the main issue with it on large builds). The new format addresses a 
few issues in this directions. I should note however that testing for me showed 
even if SCons took an extra minute or 5 to start building, most of the time a 
–j based build would match or still beat most other build system for a large 
build (mainly do that it could do a correct build, where a system like make, 
for example, it seems that people only trust a rebuild as something was not 
stated correctly and no one knew what). It was seen that python could easily 
read and parse 5000-8000+ files second. What was found was that executing the 
file took much longer. So the new format was to use decorators to allow a way 
to delay process as much as possible so we could get to a point of building 
something.  the simple mockup of this would look like:
/////
PartName(…)
PartVersion(…)

Depends(….)

@build
Def config(env):
   … stuff to set up environment

@build
Def emit(env):
     .. scan for files
     .. builder calls…
////

This overly simple example would allow declarative way to structure a build 
files. Python would be able to read and process this very fast as the 
“expensive” stuff can be delayed to till later. But anything I needed to know 
the about component relationship would be defined up front. This would allow 
Parts to take a simple “load all file” approach that SCons has without the 
delay we suffer today. Functionally this also allow the build system to define 
sections ( that could be custom). For example a simple case might be like:

/////
PartName(…)
PartVersion(…)

Depends(….)

@build
Def config(env):
   … stuff to set up environment

@build
Def emit(env):
     .. scan for files
     .. builder calls…

@utest
Def test1(env):

@utest
Def test2(env):
////

This case defines what I called a utest ( unit test) section. This would be 
processed if and only if the target was to build and or run a unit test. This 
allow a design in which a component can define what it needs to have built, and 
test, ( unit , gold, etc..) as different concepts. For large build it mean an 
item can build built without having to build system taking time to process 
everything under the sun which keeping the definition of what to build in one 
place, which make can increase maintainability in really large systems.

If I do this or not, is not known at this point. It might be something you can 
take advantage of.

At any rate, the main less for me is that a build system, given a smart cache 
can do a lot to speed up a build with a few checks when it know that what has 
changed. the trick is the balance of what to check. For parts at the moment it 
is about not loading stuff to be process by SCons that we know did not change. 
Anything that might have changed is loaded so we can have SCons do a correct 
job of building anything that might need to be.

Hopefully this is useful. Lots of little details missing to keep this “short”. 
Let me know if you have any questions.

Jason




From: Constantine [mailto:[email protected]]
Sent: Monday, January 26, 2015 5:06 PM
To: SCons developer list; Kenny, Jason L
Subject: Re: [Scons-dev] SCons-like build system



Parts check a number of things to see if a Part might be out of date, and if it 
could be, we load it, else we don’t read the file, and instead load cached 
information if and only if there is a component that depends on it.
I.e. Parts checks all sources, implicit dependencies, targets etc. by itself.
I mean - not using SCons standard logic. And it works faster than if SCons 
checked all these things.
Right?
Then what is the secret of Parts? How does it check all signatures much faster 
than SCons?

For me it sounds like if I split a big project to many totally independent 
small projects (SConstruct`s) and write a shell script:
    scons -C subprj1 && \
    scons -C subprj2 && \
    scons -C subprj3 && \
    ...
    scons -C subprj200

Then this shell script would work faster then one big project, but it would be 
still significantly slower than Parts.
Right?

Thank you.
Best regards,
Constantine.


In general Parts uses the notion of a component ( or a file that defines 
something) to make a “component” Dag. It checks to see if anything modified 
that state ( parts file changed, Sconstruct changed, configuration/toolchains 
was modified, source  or output files for component changed etc… which are 
mostly a Scons timestamp-MD5 check. If any component is out of date or might be 
out of sync we mark it as such and load any dependent component ( no need to 
check them as we know there is “some” modification). This loads the items into 
SCons to be processed. The resulting time to load and process is *much* smaller 
on average.

Currently Parts is looking at removing our “mapper” logic, which is an abuse of 
the subst() system in SCons to share data between components, and moving to 
what is called “continuous loader” which will load the Components in dependency 
order (making data sharing simpler). This should also make the current logic 
for checking state simpler and faster.

From there the idea to look at is to store the actions defined in the Component 
and replay them as part of the rebuild, as this can be done once we know we 
have a sub tree that has nothing new added to it. While those items build we 
continue to load more data ( as the build would be waiting for build actions to 
complete). Given the common case for a incremental build this should work out. 
As any relationships defined explicitly or implicitly will not change. The most 
common change will be in the source files, which will be seem as part of a 
change that effect loading a component build file, or by the component build 
file being changed. At any rate the dependent information gets loaded as needed 
as processed to see what is safe or not safe to say. This idea need more 
flushing out as there are details that could mess up a correct build, or it 
might show to not speed anything up enough.

Jason

From: Scons-dev [mailto:[email protected]] On Behalf Of Constantine
Sent: Sunday, January 25, 2015 3:24 AM
To: SCons developer list; Tom Tanner
Subject: Re: [Scons-dev] SCons-like build system

Do I understand correctly?
That the main idea is that using the Parts a big project is split into many 
small parts.
And then SCons builds these parts more-or-less independently.
I.e. SCons processes many small DAGs instead of one big DAG.

Thank you.
Best regards,
Constantine.
On 01/23/15 18:03, Kenny, Jason L wrote:
I understand this problem. This is one main thing Parts tries to address. It 
uses information about the different component to figure out what not to load. 
This requires the build to be laid out in some sort of component based like 
build, vs a recursive make, which may not be a big deal, depending on how your 
project is laid out. The result for example of a massive build I have here is a 
“do nothing” build takes ~7-20 second vs the normal ~15-20 minutes it would 
normally take. Incremental build also are reduced to minutes ( depending on 
what changed of course)

I honestly believe this can be better yet.. but we requires more work.  The 
main issue with spawn issue that we pushed, was found when a build for this 
large product moved from rhel4 to rhel5. The time increased from 2 hours to 4+. 
It was the spawning issue. Something changed that really made this worse. Once 
we had this fixed rhel5 build went to 2 hours and the old rhel4 based build 
went to ~1.5 hours.

Jason

From: Scons-dev [mailto:[email protected]] On Behalf Of Tom Tanner 
(BLOOMBERG/ LONDON)
Sent: Thursday, January 22, 2015 2:49 AM
To: [email protected]<mailto:[email protected]>
Subject: Re: [Scons-dev] SCons-like build system

Having been poking around in this, I see that 'posix_spawn' cleans to be 
availble on both aix and solaris (at least they have man pages). Which is a 
relief for me. However, my current grief is that a 'do nothing' build is still 
taking 20 minutes to traverse the tree. *part* of this is because I check the 
md5sum on each file to make sure someone hasn't gone and edit/patched/hacked a 
generated target (which happens more often than is desirable), but that isn't 
the bulk of the time taken.

I suspect I could leverage the fact that we use git to get the sha1 of certain 
repositories that are known not to be changed by us and if we find a file 
therein, to use the combined sha1 of the repos might improve that at the cost 
of potentially spurious rebuilds if one of the repos changed but the others 
didn't as i wouldn't be reading all the files.






_______________________________________________

Scons-dev mailing list

[email protected]<mailto:[email protected]>

https://pairlist2.pair.net/mailman/listinfo/scons-dev

_______________________________________________
Scons-dev mailing list
[email protected]
https://pairlist2.pair.net/mailman/listinfo/scons-dev

Reply via email to