diff --git a/contrib/watch-sched-debug b/contrib/watch-sched-debug deleted file mode 100755 index edf2b2e..0000000 --- a/contrib/watch-sched-debug +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/perl -# -*- mode: perl; indent-tabs-mode: nil; perl-indent-level: 4 -*- -# vim: autoindent tabstop=4 shiftwidth=4 expandtab softtabstop=4 filetype=perl - -use strict; -use warnings; - -use Time::HiRes qw(time sleep); -use Getopt::Long; -use Text::Diff; -use threads qw(yield); -use Thread::Semaphore; -use Thread::Queue; - -use Data::Dumper; -$Data::Dumper::Sortkeys = 1; -$Data::Dumper::Pair = ' : '; -$Data::Dumper::Useqq = 1; -$Data::Dumper::Indent = 1; - -my %args; -$args{'interval'} = 10; -$args{'cpus'} = { '0' => 1 }; -$args{'count'} = -1; - -sub arg_handler { - my ($opt_name, $opt_value) = @_; - - if ($opt_name eq 'count') { - $args{'count'} = $opt_value; - } elsif ($opt_name eq 'interval') { - $args{'interval'} = $opt_value; - } elsif ($opt_name eq 'cpus') { - $args{'cpus'} = {}; - - foreach my $element (split(/,/, $opt_value)) { - if ($element =~ /^[0-9]+$/) { - $args{'cpus'}{$element} = 1; - } elsif ($element =~ /-/) { - my @array = split(/-/, $element); - - for (my $i=$array[0]; $i<=$array[1]; $i++) { - $args{'cpus'}{$i} = 1; - } - } - } - } -} - -sub read_file { - my ($file_name) = @_; - - my $timestamp = time(); - my $file_content = do { - local(@ARGV, $/) = $file_name; - <> - }; - - return ($timestamp . '|' . $file_content); -} - -GetOptions("interval=s" => \&arg_handler, - "count=s" => \&arg_handler, - "cpus=s" => \&arg_handler) - or die("Error in command line arguments"); - -my $quit : shared = 0; -my $data_queue = new Thread::Queue(); -my $signal_quit = 0; -use vars qw ($signal_quit); - -$SIG{'INT'} = sub { $signal_quit = 1; }; - -my $collector_thread = threads->create('collector', $data_queue, \$quit); -my $reporter_thread = threads->create('reporter', $data_queue, \$quit); - -while(($signal_quit == 0) && $collector_thread->is_running() && $reporter_thread->is_running()) { - sleep($args{'interval'} / 2); -} -$quit = 1; - -$collector_thread->join(); -$reporter_thread->join(); - -exit(0); - -sub reporter { - my ($queue, $quit) = @_; - - my $cur_sample; - my $prev_sample; - - while(!$$quit || $queue->pending()) { - undef($cur_sample); - - my $cur_sample = $queue->dequeue_timed($args{'interval'} / 2); - - if (defined($cur_sample)) { - $cur_sample = parse_sample($cur_sample); - - if (defined($prev_sample)) { - diff_samples($prev_sample, $cur_sample); - } - - $prev_sample = $cur_sample; - } - } - - return(0); -} - -sub collector { - my ($queue, $quit) = @_; - - my $counter = 0; - - while(!$$quit) { - my $sample = read_file('/proc/sched_debug'); - $queue->enqueue($sample); - - if ($args{'count'} != -1) { - $counter += 1; - if ($counter == ($args{'count'} + 1)) { - $$quit = 1; - } - } - - if (!$$quit) { - sleep($args{'interval'}); - } - } - - return(0); -} - -sub parse_sample { - my ($sample) = @_; - - my %sample_data; - - my @data = split(/\|/, $sample, 2); - $sample_data{'timestamp'} = $data[0]; - - my @cpus = split(/cpu#/, $data[1]); - - for (my $i=1; $i{'timestamp'}), $start->{'timestamp'}; - printf "End: %s (%s)\n", format_timestamp($stop->{'timestamp'}), $stop->{'timestamp'}; - - foreach my $cpu (sort(keys %{$args{'cpus'}})) { - print "\nCPU: $cpu\n\n"; - - my @start_array = split(/\n/, $start->{$cpu}, 4); - my @stop_array = split(/\n/, $stop->{$cpu}, 4); - - print $start_array[1] . "\n"; - print $start_array[2] . "\n"; - - my $cpu_diff = diff(\$start_array[3], \$stop_array[3], { STYLE => "Unified", CONTEXT => 0 }); - - my @diff_lines = split(/\n/, $cpu_diff); - - for (my $i=0; $i 1: + sample[cpu_num] = parts[1] + + return sample + + +def format_timestamp(ts): + dt = datetime.fromtimestamp(ts) + return dt.strftime("%Y-%m-%d %H:%M:%S") + ".%03d" % (dt.microsecond / 1000) + + +def diff_samples(prev, cur, watched_cpus): + print() + print("Start: %s (%s)" % (format_timestamp(prev["timestamp"]), prev["timestamp"])) + print("End: %s (%s)" % (format_timestamp(cur["timestamp"]), cur["timestamp"])) + + for cpu in sorted(watched_cpus): + if cpu not in prev or cpu not in cur: + continue + + print("\nCPU: %d\n" % cpu) + + start_lines = prev[cpu].split("\n", 3) + stop_lines = cur[cpu].split("\n", 3) + + if len(start_lines) > 1: + print(start_lines[1]) + if len(start_lines) > 2: + print(start_lines[2]) + + if len(start_lines) > 3 and len(stop_lines) > 3: + diff = difflib.unified_diff( + start_lines[3].splitlines(keepends=True), + stop_lines[3].splitlines(keepends=True), + n=0, + ) + for line in diff: + if line.startswith("@@") or line.startswith("---") or line.startswith("+++"): + continue + print(line, end="" if line.endswith("\n") else "\n") + + +def collector(data_queue, quit_event, args): + counter = 0 + + while not quit_event.is_set(): + timestamp, content = read_file(args.file) + data_queue.put((timestamp, content)) + + if args.count != -1: + counter += 1 + if counter == args.count + 1: + quit_event.set() + return + + quit_event.wait(args.interval) + + +def reporter(data_queue, quit_event, args): + prev_sample = None + + while not quit_event.is_set() or not data_queue.empty(): + try: + timestamp, content = data_queue.get(timeout=args.interval / 2) + except queue.Empty: + continue + + cur_sample = parse_sample(timestamp, content, args.cpus) + + if prev_sample is not None: + diff_samples(prev_sample, cur_sample, args.cpus) + + prev_sample = cur_sample + + +def main(): + args = parse_args() + + quit_event = threading.Event() + + signal.signal(signal.SIGINT, lambda *_: quit_event.set()) + + data_queue = queue.Queue() + + collector_thread = threading.Thread(target=collector, args=(data_queue, quit_event, args), daemon=True) + reporter_thread = threading.Thread(target=reporter, args=(data_queue, quit_event, args), daemon=True) + + collector_thread.start() + reporter_thread.start() + + while not quit_event.is_set() and collector_thread.is_alive() and reporter_thread.is_alive(): + time.sleep(args.interval / 2) + + quit_event.set() + + collector_thread.join() + reporter_thread.join() + + +if __name__ == "__main__": + main()