@@ -278,6 +278,13 @@ scheduler_impl_tmpl_t<memref_t, reader_t>::record_type_is_instr_boundary(
278
278
return record_type_is_instr (record);
279
279
}
280
280
281
+ template <>
282
+ bool
283
+ scheduler_impl_tmpl_t <memref_t , reader_t >::record_type_is_thread_exit(memref_t record)
284
+ {
285
+ return record.exit .type == TRACE_TYPE_THREAD_EXIT;
286
+ }
287
+
281
288
template <>
282
289
bool
283
290
scheduler_impl_tmpl_t <memref_t , reader_t >::record_type_is_marker(
@@ -556,6 +563,14 @@ scheduler_impl_tmpl_t<trace_entry_t, record_reader_t>::record_type_is_instr_boun
556
563
!record_reader_t::record_is_pre_instr (&prev_record);
557
564
}
558
565
566
+ template <>
567
+ bool
568
+ scheduler_impl_tmpl_t <trace_entry_t , record_reader_t >::record_type_is_thread_exit(
569
+ trace_entry_t record)
570
+ {
571
+ return record.type == TRACE_TYPE_THREAD_EXIT;
572
+ }
573
+
559
574
template <>
560
575
bool
561
576
scheduler_impl_tmpl_t <trace_entry_t , record_reader_t >::record_type_set_marker_value(
@@ -1623,6 +1638,10 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::read_kernel_sequences(
1623
1638
error_string_ += sequence_type + " marker values mismatched" ;
1624
1639
return sched_type_t ::STATUS_ERROR_INVALID_PARAMETER;
1625
1640
}
1641
+ if (sequence[sequence_key].empty ()) {
1642
+ error_string_ += sequence_type + " sequence empty" ;
1643
+ return sched_type_t ::STATUS_ERROR_INVALID_PARAMETER;
1644
+ }
1626
1645
VPRINT (this , 1 , " Read %zu kernel %s records for key %d\n " ,
1627
1646
sequence[sequence_key].size (), sequence_type.c_str (), sequence_key);
1628
1647
sequence_key = INVALID_SEQ_KEY;
@@ -1791,6 +1810,83 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::get_initial_input_content(
1791
1810
return sched_type_t ::STATUS_SUCCESS;
1792
1811
}
1793
1812
1813
+ template <typename RecordType, typename ReaderType>
1814
+ typename scheduler_tmpl_t <RecordType, ReaderType>::stream_status_t
1815
+ scheduler_impl_tmpl_t <RecordType, ReaderType>::inject_pending_syscall_sequence(
1816
+ output_ordinal_t output, input_info_t *input, RecordType &record)
1817
+ {
1818
+ assert (!input->in_syscall_injection );
1819
+ assert (input->to_inject_syscall != input_info_t ::INJECT_NONE);
1820
+ if (!record_type_is_invalid (record)) {
1821
+ // May be invalid if we're at input eof, in which case we do not need to
1822
+ // save it.
1823
+ input->queue .push_front (record);
1824
+ }
1825
+ int syscall_num = input->to_inject_syscall ;
1826
+ input->to_inject_syscall = input_info_t ::INJECT_NONE;
1827
+ assert (syscall_sequence_.find (syscall_num) != syscall_sequence_.end ());
1828
+ stream_status_t res = inject_kernel_sequence (syscall_sequence_[syscall_num], input);
1829
+ if (res != stream_status_t ::STATUS_OK)
1830
+ return res;
1831
+ ++outputs_[output]
1832
+ .stats [memtrace_stream_t ::SCHED_STAT_KERNEL_SYSCALL_SEQUENCE_INJECTIONS];
1833
+ VPRINT (this , 3 , " Inserted %zu syscall records for syscall %d to %d.%d\n " ,
1834
+ syscall_sequence_[syscall_num].size (), syscall_num, input->workload ,
1835
+ input->index );
1836
+
1837
+ // Return the first injected record.
1838
+ assert (!input->queue .empty ());
1839
+ record = input->queue .front ();
1840
+ input->queue .pop_front ();
1841
+ input->cur_from_queue = true ;
1842
+ input->in_syscall_injection = true ;
1843
+ return stream_status_t ::STATUS_OK;
1844
+ }
1845
+
1846
+ template <typename RecordType, typename ReaderType>
1847
+ typename scheduler_tmpl_t <RecordType, ReaderType>::stream_status_t
1848
+ scheduler_impl_tmpl_t <RecordType, ReaderType>::maybe_inject_pending_syscall_sequence(
1849
+ output_ordinal_t output, input_info_t *input, RecordType &record)
1850
+ {
1851
+ if (input->to_inject_syscall == input_info_t ::INJECT_NONE)
1852
+ return stream_status_t ::STATUS_OK;
1853
+
1854
+ trace_marker_type_t marker_type;
1855
+ uintptr_t marker_value_unused;
1856
+ uintptr_t timestamp_unused;
1857
+ bool is_marker = record_type_is_marker (record, marker_type, marker_value_unused);
1858
+ bool is_injection_point = false ;
1859
+ if (
1860
+ // For syscalls not specified in -record_syscall, which do not have
1861
+ // the func_id-func_retval markers.
1862
+ record_type_is_timestamp (record, timestamp_unused) ||
1863
+ // For syscalls that did not have a post-event because the trace ended.
1864
+ record_type_is_thread_exit (record) ||
1865
+ // For syscalls interrupted by a signal and did not have a post-syscall
1866
+ // event.
1867
+ (is_marker && marker_type == TRACE_MARKER_TYPE_KERNEL_EVENT)) {
1868
+ is_injection_point = true ;
1869
+ } else if (is_marker && marker_type == TRACE_MARKER_TYPE_FUNC_ID) {
1870
+ if (!input->saw_first_func_id_marker_after_syscall ) {
1871
+ // XXX i#7482: If we allow recording zero args for syscalls in
1872
+ // -record_syscall, we would need to update this logic.
1873
+ input->saw_first_func_id_marker_after_syscall = true ;
1874
+ } else {
1875
+ // For syscalls specified in -record_syscall, for which we inject
1876
+ // after the func_id-func_arg markers (if any) but before the
1877
+ // func_id-func_retval markers.
1878
+ is_injection_point = true ;
1879
+ }
1880
+ }
1881
+ if (is_injection_point) {
1882
+ stream_status_t res = inject_pending_syscall_sequence (output, input, record);
1883
+ if (res != stream_status_t ::STATUS_OK)
1884
+ return res;
1885
+ input->saw_first_func_id_marker_after_syscall = false ;
1886
+ }
1887
+ return stream_status_t ::STATUS_OK;
1888
+ }
1889
+
1794
1890
template <typename RecordType, typename ReaderType>
1795
1891
typename scheduler_tmpl_t <RecordType, ReaderType>::stream_status_t
1796
1892
scheduler_impl_tmpl_t <RecordType, ReaderType>::inject_kernel_sequence(
@@ -1804,8 +1900,7 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::inject_kernel_sequence(
1804
1900
// not affect input stream ordinals.
1805
1901
// XXX: These will appear before the top headers of a new thread which is slightly
1806
1902
// odd to have regular records with the new tid before the top headers.
1807
- if (sequence.empty ())
1808
- return stream_status_t ::STATUS_EOF;
1903
+ assert (!sequence.empty ());
1809
1904
bool saw_any_instr = false ;
1810
1905
bool set_branch_target_marker = false ;
1811
1906
trace_marker_type_t marker_type;
@@ -2072,6 +2167,10 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::get_input_record_ordinal(
2072
2167
// own counts for every input and just ignore the input stream's tracking.
2073
2168
ord -= inputs_[index ].queue .size () + (inputs_[index ].cur_from_queue ? 1 : 0 );
2074
2169
}
2170
+ if (inputs_[index ].in_syscall_injection ) {
2171
+ // We readahead by one record when injecting syscalls.
2172
+ --ord;
2173
+ }
2075
2174
return ord;
2076
2175
}
2077
2176
@@ -2732,6 +2831,7 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::next_record(output_ordinal_t outp
2732
2831
input_info_t *&input,
2733
2832
uint64_t cur_time)
2734
2833
{
2834
+ record = create_invalid_record ();
2735
2835
// We do not enforce a globally increasing time to avoid the synchronization cost; we
2736
2836
// do return an error on a time smaller than an input's current start time when we
2737
2837
// check for quantum end.
@@ -2830,7 +2930,14 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::next_record(output_ordinal_t outp
2830
2930
} else {
2831
2931
input->needs_advance = true ;
2832
2932
}
2833
- if (input->at_eof || *input->reader == *input->reader_end ) {
2933
+ bool input_at_eof = input->at_eof || *input->reader == *input->reader_end ;
2934
+ if (input_at_eof && input->to_inject_syscall != input_info_t ::INJECT_NONE) {
2935
+ // The input's at eof but we have a syscall trace yet to be injected.
2936
+ stream_status_t res =
2937
+ inject_pending_syscall_sequence (output, input, record);
2938
+ if (res != stream_status_t ::STATUS_OK)
2939
+ return res;
2940
+ } else if (input_at_eof) {
2834
2941
if (!input->at_eof ) {
2835
2942
stream_status_t status = mark_input_eof (*input);
2836
2943
if (status != sched_type_t ::STATUS_OK)
@@ -2853,6 +2960,22 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::next_record(output_ordinal_t outp
2853
2960
record = **input->reader ;
2854
2961
}
2855
2962
}
2963
+
2964
+ stream_status_t res =
2965
+ maybe_inject_pending_syscall_sequence (output, input, record);
2966
+ if (res != stream_status_t ::STATUS_OK)
2967
+ return res;
2968
+
2969
+ // Check whether all syscall injected records have been passed along
2970
+ // to the caller.
2971
+ trace_marker_type_t marker_type;
2972
+ uintptr_t marker_value_unused;
2973
+ if (input->in_syscall_injection &&
2974
+ record_type_is_marker (outputs_[output].last_record , marker_type,
2975
+ marker_value_unused) &&
2976
+ marker_type == TRACE_MARKER_TYPE_SYSCALL_TRACE_END) {
2977
+ input->in_syscall_injection = false ;
2978
+ }
2856
2979
VPRINT (this , 5 ,
2857
2980
" next_record[%d]: candidate record from %d (@%" PRId64 " ): " , output,
2858
2981
input->index , get_instr_ordinal (*input));
@@ -2868,8 +2991,8 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::next_record(output_ordinal_t outp
2868
2991
bool preempt = false ;
2869
2992
uint64_t blocked_time = 0 ;
2870
2993
uint64_t prev_time_in_quantum = input->prev_time_in_quantum ;
2871
- stream_status_t res = check_for_input_switch (
2872
- output, record, input, cur_time, need_new_input, preempt, blocked_time);
2994
+ res = check_for_input_switch (output, record, input, cur_time, need_new_input,
2995
+ preempt, blocked_time);
2873
2996
if (res != sched_type_t ::STATUS_OK && res != sched_type_t ::STATUS_SKIPPED)
2874
2997
return res;
2875
2998
if (need_new_input) {
@@ -2988,18 +3111,11 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::finalize_next_record(
2988
3111
marker_type == TRACE_MARKER_TYPE_SYSCALL &&
2989
3112
syscall_sequence_.find (static_cast <int >(marker_value)) !=
2990
3113
syscall_sequence_.end ()) {
2991
- int syscall_num = static_cast <int >(marker_value);
2992
- stream_status_t res =
2993
- inject_kernel_sequence (syscall_sequence_[syscall_num], input);
2994
- if (res == stream_status_t ::STATUS_OK) {
2995
- ++outputs_[output].stats
2996
- [memtrace_stream_t ::SCHED_STAT_KERNEL_SYSCALL_SEQUENCE_INJECTIONS];
2997
- VPRINT (this , 3 , " Inserted %zu syscall records for syscall %d to %d.%d\n " ,
2998
- syscall_sequence_[syscall_num].size (), syscall_num, input->workload ,
2999
- input->index );
3000
- } else if (res != stream_status_t ::STATUS_EOF) {
3001
- return res;
3002
- }
3114
+ assert (!input->in_syscall_injection );
3115
+ // The actual injection of the syscall trace happens later at the intended
3116
+ // point between the syscall function tracing markers.
3117
+ input->to_inject_syscall = static_cast <int >(marker_value);
3118
+ input->saw_first_func_id_marker_after_syscall = false ;
3003
3119
} else if (record_type_is_instr (record, &instr_pc, &instr_size)) {
3004
3120
input->last_pc_fallthrough = instr_pc + instr_size;
3005
3121
}
0 commit comments