@@ -601,41 +601,110 @@ sub sortStart {
return $val;
}
-my @sorted_keys = sort sortStart keys %db;
-my $re_sort = 0;
+my $re_sort = 1;
+my @sorted_keys;
-die "Database changed size?!" unless scalar(@sorted_keys) == $key_count;
+sub maybe_sort_keys
+{
+ if ($re_sort) {
+ @sorted_keys = sort sortStart keys %db;
+ $re_sort = 0;
+ die "Database changed size?!" unless scalar(@sorted_keys) ==
+ $key_count;
+ }
+}
-foreach my $key (@sorted_keys) {
- my $ring = $db{$key}->{'ring'};
- my $end = $db{$key}->{'end'};
+maybe_sort_keys();
+
+my %ctx_timelines;
+
+sub sortContext {
+ my $as = $db{$a}->{'seqno'};
+ my $bs = $db{$b}->{'seqno'};
+ my $val;
+
+ $val = $as <=> $bs;
+
+ die if $val == 0;
+
+ return $val;
+}
+
+sub get_ctx_timeline {
+ my ($ctx, $ring, $key) = @_;
+ my @timeline;
- # correct duration of merged batches
- if ($correct_durations and exists $db{$key}->{'no-end'}) {
+ return $ctx_timelines{$key} if exists $ctx_timelines{$key};
+
+ @timeline = grep { $db{$_}->{'ring'} == $ring and
+ $db{$_}->{'ctx'} == $ctx } @sorted_keys;
+ # FIXME seqno restart
+ @timeline = sort sortContext @timeline;
+
+ $ctx_timelines{$key} = \@timeline;
+
+ return \@timeline;
+}
+
+# Split out merged batches if requested.
+if ($correct_durations) {
+ my @port1;
+ my @no_end;
+
+ # Shift !port0 requests start time to after the previous context on the
+ # same timeline has finished.
+ @port1 = grep { $db{$_}->{'port'} != 0 } @sorted_keys;
+ foreach my $key (@port1) {
+ my $timeline = get_engine_timeline($db{$key}->{'ring'});
+ my $i = List::Util::first { ${$timeline}[$_] eq $key } 0..$#{$timeline};
+ my $prev_key;
+ my $start;
+
+ while ($i > 0) {
+ my $prev;
+
+ $i = $i - 1;
+ $prev = ${$timeline}[$i];
+
+ next if exists $db{$prev}->{'no-end'};
+
+ $prev_key = $prev;
+ last;
+ }
+
+ $start = $db{$prev_key}->{'end'};
+ $db{$key}->{'start'} = $start;
+ die if $start > $db{$key}->{'end'};
+
+ $re_sort = 1;
+ }
+
+ maybe_sort_keys();
+
+ # Batch with no-end (no request_out) means it was submitted as part of
+ # colaesced context. This means it's start time should be set to the end
+ # time of a precedeing request on this timeline.
+ @no_end = grep { exists $db{$_}->{'no-end'} } @sorted_keys;
+ foreach my $key (@no_end) {
my $ctx = $db{$key}->{'ctx'};
- my $seqno = $db{$key}->{'seqno'};
- my $start = $db{$key}->{'start'};
- my $next_key;
- my $i = 1;
-
- do {
- $next_key = db_key($ring, $ctx, $seqno + $i);
- $i++;
- } until (exists $db{$next_key} or $i > $key_count); # ugly stop hack
-
- # 20us tolerance
- if (exists $db{$next_key} and $db{$next_key}->{'start'} < $start + 20) {
- my $notify = $db{$key}->{'notify'};
+ my $ring = $db{$key}->{'ring'};
+ my $tkey = $ctx . '/' . $ring;
+ my $timeline = get_ctx_timeline($ctx, $ring, $tkey);
+ my $i;
+
+ $i = List::Util::first { ${$timeline}[$_] eq $key } 0..$#{$timeline};
+
+ # Shift following request to start after the current one.
+ if ($i < $#{$timeline}) {
+ my $next_key = ${$timeline}[$i + 1];
+
+ $db{$next_key}->{'start'} = $db{$key}->{'notify'};
$re_sort = 1;
- $db{$next_key}->{'start'} = $notify;
- $db{$next_key}->{'start'} = $db{$next_key}->{'end'} if $db{$next_key}->{'start'} > $db{$next_key}->{'end'};
- die if $db{$next_key}->{'start'} > $db{$next_key}->{'end'};
}
- die if $start > $end;
}
}
-@sorted_keys = sort sortStart keys %db if $re_sort;
+maybe_sort_keys();
# GPU time accounting
my (%running, %runnable, %queued, %batch_avg, %batch_total_avg, %batch_count);