1/*
2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <errno.h>
7#include <fcntl.h>
8#include <getopt.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15#include <OS.h>
16
17#include "time_stats.h"
18
19
20#define SCHEDULING_ANALYSIS_BUFFER_SIZE	10 * 1024 * 1024
21
22
23extern const char* __progname;
24
25static const char* kUsage =
26	"Usage: %s [ <options> ] <command line>\n"
27	"Executes the given command line <command line> and print an analysis of\n"
28	"the user and kernel times of all threads that ran during that time.\n"
29	"\n"
30	"Options:\n"
31	"  -b <size>    - When doing scheduling analysis: the size of the buffer\n"
32	"                 used (in MB)\n"
33	"  -h, --help   - Print this usage info.\n"
34	"  -o <output>  - Print the results to file <output>.\n"
35	"  -s           - Also perform a scheduling analysis over the time the\n"
36	"                 child process ran. This requires that scheduler kernel\n"
37	"                 tracing had been enabled at compile time.\n"
38;
39
40
41static void
42print_usage_and_exit(bool error)
43{
44    fprintf(error ? stderr : stdout, kUsage, __progname);
45    exit(error ? 1 : 0);
46}
47
48
49int
50main(int argc, const char* const* argv)
51{
52	const char* outputFile = NULL;
53	bool schedulingAnalysis = false;
54	size_t bufferSize = SCHEDULING_ANALYSIS_BUFFER_SIZE;
55
56	while (true) {
57		static struct option sLongOptions[] = {
58			{ "help", no_argument, 0, 'h' },
59			{ "output", required_argument, 0, 'o' },
60			{ 0, 0, 0, 0 }
61		};
62
63		opterr = 0; // don't print errors
64		int c = getopt_long(argc, (char**)argv, "+b:ho:s", sLongOptions, NULL);
65		if (c == -1)
66			break;
67
68		switch (c) {
69			case 'b':
70				bufferSize = atol(optarg);
71				if (bufferSize < 1 || bufferSize > 1024) {
72					fprintf(stderr, "Error: Invalid buffer size. Should be "
73						"between 1 and 1024 MB\n");
74					exit(1);
75				}
76				bufferSize *= 1024 * 1024;
77				break;
78			case 'h':
79				print_usage_and_exit(false);
80				break;
81			case 'o':
82				outputFile = optarg;
83				break;
84			case 's':
85				schedulingAnalysis = true;
86				break;
87
88			default:
89				print_usage_and_exit(true);
90				break;
91		}
92	}
93
94	if (optind >= argc)
95		print_usage_and_exit(true);
96
97	// open output file, if specified
98	int outFD = -1;
99	if (outputFile != NULL) {
100		outFD = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC,
101			S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP| S_IROTH | S_IWOTH);
102		if (outFD < 0) {
103			fprintf(stderr, "Error: Failed to open \"%s\": %s\n", outputFile,
104				strerror(errno));
105			exit(1);
106		}
107	}
108
109	do_timing_analysis(argc - optind, argv + optind, schedulingAnalysis, outFD,
110		bufferSize);
111
112	return 0;
113}
114