summaryrefslogtreecommitdiff
path: root/cli/cli_trim.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cli/cli_trim.cpp')
-rw-r--r--cli/cli_trim.cpp284
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
};