diff options
Diffstat (limited to 'cli/cli_trim.cpp')
-rw-r--r-- | cli/cli_trim.cpp | 284 |
1 files changed, 16 insertions, 268 deletions
diff --git a/cli/cli_trim.cpp b/cli/cli_trim.cpp index ed950e5c..b1e6b485 100644 --- a/cli/cli_trim.cpp +++ b/cli/cli_trim.cpp @@ -29,13 +29,10 @@ #include <limits.h> // for CHAR_MAX #include <getopt.h> -#include <set> - #include "cli.hpp" #include "os_string.hpp" -#include "trace_analyzer.hpp" #include "trace_callset.hpp" #include "trace_parser.hpp" #include "trace_writer.hpp" @@ -52,98 +49,15 @@ usage(void) " -h, --help Show detailed help for trim options and exit\n" " --calls=CALLSET Include specified calls in the trimmed output.\n" " --frames=FRAMESET Include specified frames in the trimmed output.\n" - " --deps Include additional calls to satisfy dependencies\n" - " --no-deps Do not include any more calls than requestd\n" - " --prune Omit calls without side effects from the output\n" - " --no-prune Do not omit any requested calls\n" - " -a, --auto Trim automatically to calls specified in --calls/--frames\n" - " Equivalent to both --deps and --prune\n" - " --exact Trim to exactly the calls specified in --calls/--frames\n" - " Equivalent to both --no-deps and --no-prune\n" - " --print-callset Print the final set of calls included in output\n" - " --trim-spec=SPEC Only performing trimming as described in SPEC\n" - " --thread=THREAD_ID Only retain calls from specified thread\n" - " -o, --output=TRACE_FILE Output trace file\n" - ; -} - -static void -help() -{ - std::cout - << "usage: apitrace trim [OPTIONS] TRACE_FILE...\n" - << synopsis << "\n" - "\n" - " -h, --help Show this help message and exit\n" - "\n" - " --calls=CALLSET Include specified calls in the trimmed output.\n" - " --frames=FRAMESET Include specified frames in the trimmed output.\n" - "\n" - " --deps Perform dependency analysis and include dependent\n" - " calls as needed, (even if those calls were not\n" - " explicitly requested with --calls or --frames).\n" - " (On by default. See --no-deps or --exact)\n" - "\n" - " --no-deps Do not perform dependency analysis. Output will\n" - " not include any additional calls beyond those\n" - " explicitly requested with --calls or --frames).\n" - "\n" - " --prune Omit calls with no side effects, even if the call\n" - " is within the range specified by --calls/--frames.\n" - " (On by default. See --no-prune or --exact)\n" - "\n" - " --no-prune Never omit any calls from the range specified\n" - " --calls/--frames.\n" - "\n" - " -a, --auto Use dependency analysis and pruning\n" - " of uninteresting calls the resulting trace may\n" - " include more and less calls than specified.\n" - " This option is equivalent\n" - " to passing both --deps and --prune and is on by\n" - " default (see --no-deps, --no-prune and --exact)\n" - "\n" - " --exact Trim output to exact the calls or frames\n" - " specified with --calls or --frames.\n" - " This option is equivalent\n" - " to passing both --no-deps and --no-prune.\n" - "\n" - " --print-callset Print to stdout the final set of calls included\n" - " in the trim output. This can be useful for\n" - " tweaking the trimmed callset from --auto on the\n" - " command-line.\n" - " Use --calls=@FILE to read callset from a file.\n" - "\n" - " --trim-spec=SPEC Specifies which classes of calls will be trimmed.\n" - " This option only has an effect if dependency\n" - " analysis is enabled. The argument is a comma-\n" - " separated list of names from the following:\n" - "\n" - " no-side-effects Calls with no side effects\n" - " textures Calls to setup unused textures\n" - " shaders Calls to setup unused shaders\n" - " drawing Calls that draw\n" - "\n" - " The default trim specification includes all of\n" - " the above, (as much as possible will be trimmed).\n" - "\n" " --thread=THREAD_ID Only retain calls from specified thread\n" - "\n" " -o, --output=TRACE_FILE Output trace file\n" - "\n" ; } enum { CALLS_OPT = CHAR_MAX + 1, FRAMES_OPT, - DEPS_OPT, - NO_DEPS_OPT, - PRUNE_OPT, - NO_PRUNE_OPT, - THREAD_OPT, - PRINT_CALLSET_OPT, - TRIM_SPEC_OPT, - EXACT_OPT + THREAD_OPT }; const static char * @@ -154,16 +68,8 @@ longOptions[] = { {"help", no_argument, 0, 'h'}, {"calls", required_argument, 0, CALLS_OPT}, {"frames", required_argument, 0, FRAMES_OPT}, - {"deps", no_argument, 0, DEPS_OPT}, - {"no-deps", no_argument, 0, NO_DEPS_OPT}, - {"prune", no_argument, 0, PRUNE_OPT}, - {"no-prune", no_argument, 0, NO_PRUNE_OPT}, - {"auto", no_argument, 0, 'a'}, - {"exact", no_argument, 0, EXACT_OPT}, {"thread", required_argument, 0, THREAD_OPT}, {"output", required_argument, 0, 'o'}, - {"print-callset", no_argument, 0, PRINT_CALLSET_OPT}, - {"trim-spec", required_argument, 0, TRIM_SPEC_OPT}, {0, 0, 0, 0} }; @@ -180,91 +86,24 @@ struct trim_options { /* Frames to be included in trace. */ trace::CallSet frames; - /* Whether dependency analysis should be performed. */ - bool dependency_analysis; - - /* Whether uninteresting calls should be pruned.. */ - bool prune_uninteresting; - /* Output filename */ std::string output; /* Emit only calls from this thread (-1 == all threads) */ int thread; - - /* Print resulting callset */ - int print_callset; - - /* What kind of trimming to perform. */ - TrimFlags trim_flags; }; static int trim_trace(const char *filename, struct trim_options *options) { - trace::ParseBookmark beginning; trace::Parser p; - TraceAnalyzer analyzer(options->trim_flags); - trace::FastCallSet *required; unsigned frame; - int call_range_first, call_range_last; if (!p.open(filename)) { std::cerr << "error: failed to open " << filename << "\n"; return 1; } - /* Mark the beginning so we can return here for pass 2. */ - p.getBookmark(beginning); - - /* In pass 1, analyze which calls are needed. */ - frame = 0; - trace::Call *call; - while ((call = p.parse_call())) { - - /* There's no use doing any work past the last call and frame - * requested by the user. */ - if ((options->calls.empty() || call->no > options->calls.getLast()) && - (options->frames.empty() || frame > options->frames.getLast())) { - - delete call; - break; - } - - /* If requested, ignore all calls not belonging to the specified thread. */ - if (options->thread != -1 && call->thread_id != options->thread) { - goto NEXT; - } - - /* Also, prune if no side effects (unless the user asked for no pruning. */ - if (options->prune_uninteresting && call->flags & trace::CALL_FLAG_NO_SIDE_EFFECTS) { - goto NEXT; - } - - /* If this call is included in the user-specified call set, - * then require it (and all dependencies) in the trimmed - * output. */ - if (options->calls.contains(*call) || - options->frames.contains(frame, call->flags)) { - - analyzer.require(call); - } - - /* Regardless of whether we include this call or not, we do - * some dependency tracking (unless disabled by the user). We - * do this even for calls we have included in the output so - * that any state updates get performed. */ - if (options->dependency_analysis) { - analyzer.analyze(call); - } - - NEXT: - if (call->flags & trace::CALL_FLAG_END_FRAME) - frame++; - - delete call; - } - /* Prepare output file and writer for output. */ if (options->output.empty()) { os::String base(filename); @@ -279,15 +118,9 @@ trim_trace(const char *filename, struct trim_options *options) return 1; } - /* Reset bookmark for pass 2. */ - p.setBookmark(beginning); - - /* In pass 2, emit the calls that are required. */ - required = analyzer.get_required(); frame = 0; - call_range_first = -1; - call_range_last = -1; + trace::Call *call; while ((call = p.parse_call())) { /* There's no use doing any work past the last call and frame @@ -299,23 +132,21 @@ trim_trace(const char *filename, struct trim_options *options) break; } - if (required->contains(call->no)) { - writer.writeCall(call); + /* If requested, ignore all calls not belonging to the specified thread. */ + if (options->thread != -1 && call->thread_id != options->thread) { + goto NEXT; + } + + /* If this call is included in the user-specified call set, + * then require it (and all dependencies) in the trimmed + * output. */ + if (options->calls.contains(*call) || + options->frames.contains(frame, call->flags)) { - if (options->print_callset) { - if (call_range_first < 0) { - call_range_first = call->no; - printf ("%d", call_range_first); - } else if (call->no != call_range_last + 1) { - if (call_range_last != call_range_first) - printf ("-%d", call_range_last); - call_range_first = call->no; - printf (",%d", call_range_first); - } - call_range_last = call->no; - } + writer.writeCall(call); } + NEXT: if (call->flags & trace::CALL_FLAG_END_FRAME) { frame++; } @@ -323,71 +154,26 @@ trim_trace(const char *filename, struct trim_options *options) delete call; } - if (options->print_callset) { - if (call_range_last != call_range_first) - printf ("-%d\n", call_range_last); - } - std::cerr << "Trimmed trace is available as " << options->output << "\n"; return 0; } static int -parse_trim_spec(const char *trim_spec, TrimFlags *flags) -{ - std::string spec(trim_spec), word; - size_t start = 0, comma = 0; - *flags = 0; - - while (start < spec.size()) { - comma = spec.find(',', start); - - if (comma == std::string::npos) - word = std::string(spec, start); - else - word = std::string(spec, start, comma - start); - - if (strcmp(word.c_str(), "no-side-effects") == 0) - *flags |= TRIM_FLAG_NO_SIDE_EFFECTS; - else if (strcmp(word.c_str(), "textures") == 0) - *flags |= TRIM_FLAG_TEXTURES; - else if (strcmp(word.c_str(), "shaders") == 0) - *flags |= TRIM_FLAG_SHADERS; - else if (strcmp(word.c_str(), "drawing") == 0) - *flags |= TRIM_FLAG_DRAWING; - else { - return 1; - } - - if (comma == std::string::npos) - break; - - start = comma + 1; - } - - return 0; -} - -static int command(int argc, char *argv[]) { struct trim_options options; options.calls = trace::CallSet(trace::FREQUENCY_NONE); options.frames = trace::CallSet(trace::FREQUENCY_NONE); - options.dependency_analysis = true; - options.prune_uninteresting = true; options.output = ""; options.thread = -1; - options.print_callset = 0; - options.trim_flags = -1; int opt; while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) { switch (opt) { case 'h': - help(); + usage(); return 0; case CALLS_OPT: options.calls.merge(optarg); @@ -395,42 +181,12 @@ command(int argc, char *argv[]) case FRAMES_OPT: options.frames.merge(optarg); break; - case DEPS_OPT: - options.dependency_analysis = true; - break; - case NO_DEPS_OPT: - options.dependency_analysis = false; - break; - case PRUNE_OPT: - options.prune_uninteresting = true; - break; - case NO_PRUNE_OPT: - options.prune_uninteresting = false; - break; - case 'a': - options.dependency_analysis = true; - options.prune_uninteresting = true; - break; - case EXACT_OPT: - options.dependency_analysis = false; - options.prune_uninteresting = false; - break; case THREAD_OPT: options.thread = atoi(optarg); break; case 'o': options.output = optarg; break; - case PRINT_CALLSET_OPT: - options.print_callset = 1; - break; - case TRIM_SPEC_OPT: - if (parse_trim_spec(optarg, &options.trim_flags)) { - std::cerr << "error: illegal value for trim-spec: " << optarg << "\n"; - std::cerr << "See \"apitrace help trim\" for help.\n"; - return 1; - } - break; default: std::cerr << "error: unexpected option `" << (char)opt << "`\n"; usage(); @@ -460,20 +216,12 @@ command(int argc, char *argv[]) return 1; } - if (options.dependency_analysis) { - std::cerr << - "Note: The dependency analysis in \"apitrace trim\" is still experimental.\n" - " We hope that it will be useful, but it may lead to incorrect results.\n" - " If you find a trace that misbehaves while trimming, please share that\n" - " by sending email to apitrace@lists.freedesktop.org, cworth@cworth.org\n"; - } - return trim_trace(argv[optind], &options); } const Command trim_command = { "trim", synopsis, - help, + usage, command }; |