Norm Jacobs
2010-05-17 f1b72958ef719648e4346492aceddb7f5b0fc1cd
dependency gathering tool(s)
2 files added
225 ■■■■■ changed files
tools/build-watch.d 74 ●●●●● patch | view | raw | blame | history
tools/build-watch.pl 151 ●●●●● patch | view | raw | blame | history
tools/build-watch.d
New file
@@ -0,0 +1,74 @@
#!/usr/sbin/dtrace -s -q
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright (c) 2010, Oracle and/or it's affiliates.  All rights reserved.
 *
 *
 * build-watch.d - a simple dtrace script to keep track of some key
 *           information to help determine build dependencies.
 */
/*
 * record paths successfully opened
 */
syscall::open:entry, syscall::open64:entry
/(pid == $target) || progenyof($target)/
{
    self->file = cleanpath(copyinstr(arg0));
}
syscall::openat:entry
/(pid == $target) || progenyof($target)/
{
    self->file = cleanpath(copyinstr(arg1));
}
syscall::open*:return
/((pid == $target) || progenyof($target)) && (arg0 != -1) && (self->file != "")/
{
    @opened[self->file] = count();
    self->file = 0;
}
/*
 * record the programs successfully execed (full path names)
 */
proc:::exec
/(pid == $target) || progenyof($target)/
{
    self->execpath = stringof(arg0);
}
proc:::exec-success
/(pid == $target) || progenyof($target)/
{
    @tools[execname, self->execpath] = count();
    self->execpath = 0;
}
/*
 * Summarize the results of watching the [sub]process tree
 */
END
{
    printf("\n");
    printa("TOOL: %s = %s\n", @tools);
    printa("FILE: %s\n", @opened);
}
tools/build-watch.pl
New file
@@ -0,0 +1,151 @@
#!/usr/perl5/bin/perl
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright (c) 2010, Oracle and/or it's affiliates.  All rights reserved.
#
#
# build-watch.pl - a simple utility to watch a process and it's children under
#            dtrace and process the results for dependency information.
#
# Ex:
#    $ export WS_TOP=/top/of/your/workspace
#    $ cd $(WS_TOP)/components/{component}
#    $ $(WS_TOP)/tools/build-watch.pl -c "gmake install"
#
use File::Temp qw/tempfile/;
use Getopt::Long;
my $verbose = 0;
my @ignore = (
    '^[^/\.].*',        # ignore paths that don't begin with / or .
    '^/dev/',        # ignore devices
    '^/etc/',        # ignore config files
    '^/proc/',        # ignore /proc
    '^/tmp/',        # ignore temp files
    '^/var/',        # ignore more temp/volatile files
    '^/usr/lib/locale/',    # ignore locale support
    '^/usr/share/lib/make/',    # ignore make bits
    '^/usr/share/lib/zoneinfo/',    # ignore timezone info
    '/SUNWspro/',        # ignore compiler bits
    '/sunstudio12.1/',    # ignore more compiler bits
    '^/ws/',        # nothing in /ws can be interesting
    '^\.[/\.]{0,1}$'    # ignore ., .., and ./
);
sub match
{
    local($string, @expressions) = @_;
    foreach (@expressions) {
        ($string =~ m{$_}) && return (1);
    }
    return (0);
}
sub process_dtrace_results
{
    local ($filename) = @_;
    my (%tools, %files, $fh) = ();
    open($fh, "<$filename") || die "open($filename): $!\n";
    while (<$fh>) {
        if (/^TOOL:\s+(\S+) = (\S+)$/) {
            $tools{$2} = $1;
        } elsif ((/^FILE:\s+(\S+)\s*$/) && (match($1, @ignore) == 0) &&
             (-e $1)) {
            $files{$1} = $1;
        }
    }
    close($fh);
    return (\%tools, \%files);
}
sub generate_package_requirements
{
    local (*tools, *files) = @_;
    my ($count, %pkgs, @search_strings, $search_string) = (0);
    # create a set of search strings to query the package DB
    foreach (sort (keys %tools, keys %files)) {
        if ($count++ % 100 == 0) {
            defined($search_string) && \
                push(@search_strings, $search_string);
            $search_string = $_;
        } else {
            $search_string .= " OR $_";
        }
    }
    push(@search_strings, $search_string);
    # walk through the search strings and query the package DB
    foreach (@search_strings) {
        my $IFH;
        open($IFH, "pkg search -l -H -o path,pkg.name '$_'|");
        while (<$IFH>) {
                   (/^(\S+)\s+(\S+)$/) && ($pkgs{$1} = $2);
        }
        close($IFH);
    }
    return (\%pkgs);
}
#
# Main execution begins here
#
GetOptions("c|command=s" => \$cmd, "i|input-file=s" => \@file,
       "v|verbose" => \$verbose);
if (defined($cmd)) {
    $file = (tempfile(UNLINK => 1))[1];
    if (!defined($ENV{'WS_TOP'})) {
        print("WS_TOP must be set in the calling environment\n");
        exit(1);
    }
    ($verbose == 1) && print("*** Executing '$cmd' under dtrace...\n");
    system($ENV{'WS_TOP'}."/tools/build-watch.d", "-o", $file, "-c", $cmd);
}
($verbose == 1) && printf("*** Processing results...\n");
my ($tools, $files) = process_dtrace_results($file);
($verbose == 1) && printf("*** Generating package requirements...\n");
my ($pkgs) = generate_package_requirements($tools, $files);
if (defined($tools)) {
    print "TOOL: $_\n" for (sort keys %$tools);
}
if (defined($files)) {
    print "FILE: $_\n" for (sort keys %$files);
}
if (defined($pkgs)) {
    @unique{values %$pkgs} = ();
    print "PKG: $_\n" for (sort keys %unique);
}
exit(0);