|
1 | 1 | /* ********************************************************** |
2 | | - * Copyright (c) 2023-2024 Google, Inc. All rights reserved. |
| 2 | + * Copyright (c) 2023-2025 Google, Inc. All rights reserved. |
3 | 3 | * **********************************************************/ |
4 | 4 |
|
5 | 5 | /* |
@@ -2288,41 +2288,6 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::set_cur_input( |
2288 | 2288 | stream->page_size_ = inputs_[input].reader->get_page_size(); |
2289 | 2289 | } |
2290 | 2290 |
|
2291 | | - if (inputs_[input].pid != INVALID_PID) { |
2292 | | - insert_switch_tid_pid(inputs_[input]); |
2293 | | - } |
2294 | | - |
2295 | | - if (!switch_sequence_.empty() && |
2296 | | - outputs_[output].stream->get_instruction_ordinal() > 0) { |
2297 | | - switch_type_t switch_type = sched_type_t::SWITCH_INVALID; |
2298 | | - if (prev_workload != inputs_[input].workload) |
2299 | | - switch_type = sched_type_t::SWITCH_PROCESS; |
2300 | | - else |
2301 | | - switch_type = sched_type_t::SWITCH_THREAD; |
2302 | | - // Inject kernel context switch code. Since the injected records belong to this |
2303 | | - // input (the kernel is acting on behalf of this input) we insert them into the |
2304 | | - // input's queue, but ahead of any prior queued items. This is why we walk in |
2305 | | - // reverse, for the push_front calls to the deque. We update the tid of the |
2306 | | - // records here to match. They are considered as is_record_synthetic() and do |
2307 | | - // not affect input stream ordinals. |
2308 | | - // XXX: These will appear before the top headers of a new thread which is slightly |
2309 | | - // odd to have regular records with the new tid before the top headers. |
2310 | | - if (!switch_sequence_[switch_type].empty()) { |
2311 | | - ++outputs_[output] |
2312 | | - .stats[memtrace_stream_t::SCHED_STAT_KERNEL_SWITCH_SEQUENCE_INJECTIONS]; |
2313 | | - for (int i = static_cast<int>(switch_sequence_[switch_type].size()) - 1; |
2314 | | - i >= 0; --i) { |
2315 | | - RecordType record = switch_sequence_[switch_type][i]; |
2316 | | - record_type_set_tid(record, inputs_[input].tid); |
2317 | | - inputs_[input].queue.push_front(record); |
2318 | | - } |
2319 | | - VPRINT(this, 3, |
2320 | | - "Inserted %zu switch records for type %d from %d.%d to %d.%d\n", |
2321 | | - switch_sequence_[switch_type].size(), switch_type, prev_workload, |
2322 | | - outputs_[output].prev_input, inputs_[input].workload, input); |
2323 | | - } |
2324 | | - } |
2325 | | - |
2326 | 2291 | inputs_[input].prev_time_in_quantum = |
2327 | 2292 | outputs_[output].cur_time->load(std::memory_order_acquire); |
2328 | 2293 |
|
@@ -2415,28 +2380,80 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::pick_next_input(output_ordinal_t |
2415 | 2380 | } |
2416 | 2381 | // We can't easily place these stats inside set_cur_input() as we call that to |
2417 | 2382 | // temporarily give up our input. |
2418 | | - update_switch_stats(output, prev_index, index); |
| 2383 | + on_context_switch(output, prev_index, index); |
2419 | 2384 | set_cur_input(output, index); |
2420 | 2385 | return res; |
2421 | 2386 | } |
2422 | 2387 |
|
2423 | 2388 | template <typename RecordType, typename ReaderType> |
2424 | 2389 | void |
2425 | | -scheduler_impl_tmpl_t<RecordType, ReaderType>::update_switch_stats( |
| 2390 | +scheduler_impl_tmpl_t<RecordType, ReaderType>::on_context_switch( |
2426 | 2391 | output_ordinal_t output, input_ordinal_t prev_input, input_ordinal_t new_input) |
2427 | 2392 | { |
| 2393 | + bool do_inject_switch_seq = false; |
2428 | 2394 | if (prev_input == new_input) |
2429 | 2395 | ++outputs_[output].stats[memtrace_stream_t::SCHED_STAT_SWITCH_NOP]; |
2430 | 2396 | else if (prev_input != sched_type_t::INVALID_INPUT_ORDINAL && |
2431 | | - new_input != sched_type_t::INVALID_INPUT_ORDINAL) |
| 2397 | + new_input != sched_type_t::INVALID_INPUT_ORDINAL) { |
2432 | 2398 | ++outputs_[output].stats[memtrace_stream_t::SCHED_STAT_SWITCH_INPUT_TO_INPUT]; |
2433 | | - else if (new_input == sched_type_t::INVALID_INPUT_ORDINAL) |
| 2399 | + do_inject_switch_seq = true; |
| 2400 | + } else if (new_input == sched_type_t::INVALID_INPUT_ORDINAL) { |
| 2401 | + // XXX: For now, we do not inject a kernel context switch sequence on |
| 2402 | + // input-to-idle transitions (note that we do so on idle-to-input though). |
| 2403 | + // However, we may want to inject some other suitable sequence, but we're not |
| 2404 | + // sure yet. |
2434 | 2405 | ++outputs_[output].stats[memtrace_stream_t::SCHED_STAT_SWITCH_INPUT_TO_IDLE]; |
2435 | | - else { |
| 2406 | + } else { |
2436 | 2407 | ++outputs_[output].stats[memtrace_stream_t::SCHED_STAT_SWITCH_IDLE_TO_INPUT]; |
2437 | 2408 | // Reset the flag so we'll try to steal if we go idle again. |
2438 | 2409 | outputs_[output].tried_to_steal_on_idle = false; |
| 2410 | + do_inject_switch_seq = true; |
2439 | 2411 | } |
| 2412 | + |
| 2413 | + // We want to insert the context switch sequence on input-to-input and |
| 2414 | + // idle-to-input cases. This is a better control point to do that than |
| 2415 | + // set_cur_input. Here we get the stolen input events too, and we don't have |
| 2416 | + // to filter out the init-time set_cur_input cases. |
| 2417 | + if (!do_inject_switch_seq) |
| 2418 | + return; |
| 2419 | + if (inputs_[new_input].pid != INVALID_PID) { |
| 2420 | + insert_switch_tid_pid(inputs_[new_input]); |
| 2421 | + } |
| 2422 | + if (switch_sequence_.empty()) |
| 2423 | + return; |
| 2424 | + switch_type_t switch_type = sched_type_t::SWITCH_INVALID; |
| 2425 | + if ( // XXX: idle-to-input transitions are assumed to be process switches |
| 2426 | + // for now. But we may want to improve this heuristic. |
| 2427 | + prev_input == sched_type_t::INVALID_INPUT_ORDINAL || |
| 2428 | + inputs_[prev_input].workload != inputs_[new_input].workload) |
| 2429 | + switch_type = sched_type_t::SWITCH_PROCESS; |
| 2430 | + else |
| 2431 | + switch_type = sched_type_t::SWITCH_THREAD; |
| 2432 | + if (switch_sequence_[switch_type].empty()) |
| 2433 | + return; |
| 2434 | + // Inject kernel context switch code. Since the injected records belong to |
| 2435 | + // this input (the kernel is acting on behalf of this input) we insert them |
| 2436 | + // into the input's queue, but ahead of any prior queued items. This is why |
| 2437 | + // we walk in reverse, for the push_front calls to the deque. We update the |
| 2438 | + // tid of the records here to match. They are considered as |
| 2439 | + // is_record_synthetic() and do not affect input stream ordinals. |
| 2440 | + // XXX: These will appear before the top headers of a new thread which is |
| 2441 | + // slightly odd to have regular records with the new tid before the top |
| 2442 | + // headers. |
| 2443 | + ++outputs_[output] |
| 2444 | + .stats[memtrace_stream_t::SCHED_STAT_KERNEL_SWITCH_SEQUENCE_INJECTIONS]; |
| 2445 | + for (int i = static_cast<int>(switch_sequence_[switch_type].size()) - 1; i >= 0; |
| 2446 | + --i) { |
| 2447 | + RecordType record = switch_sequence_[switch_type][i]; |
| 2448 | + record_type_set_tid(record, inputs_[new_input].tid); |
| 2449 | + inputs_[new_input].queue.emplace_front(record); |
| 2450 | + } |
| 2451 | + VPRINT(this, 3, "Inserted %zu switch for type %d from %d.%d to %d.%d\n", |
| 2452 | + switch_sequence_[switch_type].size(), switch_type, |
| 2453 | + prev_input != sched_type_t::INVALID_INPUT_ORDINAL |
| 2454 | + ? inputs_[prev_input].workload |
| 2455 | + : -1, |
| 2456 | + prev_input, inputs_[new_input].workload, new_input); |
2440 | 2457 | } |
2441 | 2458 |
|
2442 | 2459 | template <typename RecordType, typename ReaderType> |
@@ -2655,7 +2672,7 @@ scheduler_impl_tmpl_t<RecordType, ReaderType>::next_record(output_ordinal_t outp |
2655 | 2672 | } else if (res == sched_type_t::STATUS_STOLE) { |
2656 | 2673 | // We need to loop to get the new record. |
2657 | 2674 | input = &inputs_[outputs_[output].cur_input]; |
2658 | | - update_switch_stats(output, prev_input, input->index); |
| 2675 | + on_context_switch(output, prev_input, input->index); |
2659 | 2676 | lock.unlock(); |
2660 | 2677 | lock = std::unique_lock<mutex_dbg_owned>(*input->lock); |
2661 | 2678 | lock.lock(); |
|
0 commit comments