Мы можем записать c программу для обнаружения времени, проведенного в контекстном переключении в Linux? Вы могли совместно использовать код, если у Вас есть тот? Спасибо
Профилировать время переключения очень сложно, но инструменты профилирования задержки в ядре, а также oprofile (который может профилировать само ядро) помогут вам там.
Для тестирования производительности интерактивных приложений я написал небольшой инструмент под названием latencybench, который измеряет неожиданные всплески задержки:
// Compile with g++ latencybench.cc -o latencybench -lboost_thread-mt
// Should also work on MSVC and other platforms supported by Boost.
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/date_time.hpp>
#include <algorithm>
#include <cstdlib>
#include <csignal>
volatile bool m_quit = false;
extern "C" void sighandler(int) {
m_quit = true;
}
std::string num(unsigned val) {
if (val == 1) return "one occurrence";
return boost::lexical_cast<std::string>(val) + " occurrences";
}
int main(int argc, char** argv) {
using namespace boost::posix_time;
std::signal(SIGINT, sighandler);
std::signal(SIGTERM, sighandler);
time_duration duration = milliseconds(10);
if (argc > 1) {
try {
if (argc != 2) throw 1;
unsigned ms = boost::lexical_cast<unsigned>(argv[1]);
if (ms > 1000) throw 2;
duration = milliseconds(ms);
} catch (...) {
std::cerr << "Usage: " << argv[0] << " milliseconds" << std::endl;
return EXIT_FAILURE;
}
}
typedef std::map<long, unsigned> Durations;
Durations durations;
unsigned samples = 0, wrongsamples = 0;
unsigned max = 0;
long last = -1;
std::cout << "Measuring actual sleep delays when requesting " << duration.total_milliseconds() << " ms: (Ctrl+C when done)" << std::endl;
ptime begin = boost::get_system_time();
while (!m_quit) {
ptime start = boost::get_system_time();
boost::this_thread::sleep(start + duration);
long actual = (boost::get_system_time() - start).total_milliseconds();
++samples;
unsigned num = ++durations[actual];
if (actual != last) {
std::cout << "\r " << actual << " ms " << std::flush;
last = actual;
}
if (actual != duration.total_milliseconds()) {
++wrongsamples;
if (num > max) max = num;
std::cout << "spike at " << start - begin << std::endl;
last = -1;
}
}
if (samples == 0) return 0;
std::cout << "\rTotal measurement duration: " << boost::get_system_time() - begin << "\n";
std::cout << "Number of samples collected: " << samples << "\n";
std::cout << "Incorrect delay count: " << wrongsamples << boost::format(" (%.2f %%)") % (100.0 * wrongsamples / samples) << "\n\n";
std::cout << "Histogram of actual delays:\n\n";
unsigned correctsamples = samples - wrongsamples;
const unsigned line = 60;
double scale = 1.0;
char ch = '+';
if (max > line) {
scale = double(line) / max;
ch = '*';
}
double correctscale = 1.0;
if (correctsamples > line) correctscale = double(line) / correctsamples;
for (Durations::const_iterator it = durations.begin(); it != durations.end(); ++it) {
std::string bar;
if (it->first == duration.total_milliseconds()) bar = std::string(correctscale * it->second, '>');
else bar = std::string(scale * it->second, ch);
std::cout << boost::format("%5d ms | %s %d") % it->first % bar % it->second << std::endl;
}
std::cout << "\n";
std::string indent(30, ' ');
std::cout << indent << "+-- Legend ----------------------------------\n";
std::cout << indent << "| > " << num(1.0 / correctscale) << " (of " << duration.total_milliseconds() << " ms delay)\n";
if (wrongsamples > 0) std::cout << indent << "| " << ch << " " << num(1.0 / scale) << " (of any other delay)\n";
}
Результаты для общего ядра Ubuntu 2.6.32-14. Во время измерения я компилировал код C ++ с четырьмя ядрами и одновременно играл в игру с графикой OpenGL (чтобы было интереснее):
Total measurement duration: 00:01:45.191465
Number of samples collected: 10383
Incorrect delay count: 196 (1.89 %)
Histogram of actual delays:
10 ms | >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 10187
11 ms | *************************************************** 70
12 ms | ************************************************************ 82
13 ms | ********* 13
14 ms | ********* 13
15 ms | ** 4
17 ms | *** 5
18 ms | * 2
19 ms | **** 6
20 ms | 1
+-- Legend ----------------------------------
| > 169 occurrences (of 10 ms delay)
| * one occurrence (of any other delay)
С ядрами с исправлениями rt я получаю гораздо лучшие результаты, примерно 10-12 мс. Только.
Легенда в распечатке, похоже, содержит ошибку округления или что-то в этом роде (и вставленный исходный код не совпадает с версией). Я никогда особо не доводил это приложение до релиза ...
Если у вас есть привилегии суперпользователя, вы можете запустить программу SystemTap с точками зондирования для контекстных переключений и вывести текущее время в каждой из них:
probe scheduler.ctxswitch {
printf("Switch from %d to %d at %d\n", prev_pid, next_pid, gettimeofday_us())
}
Я не уверен, насколько надежны выходные данные, но это быстрый и простой способ получить некоторые цифры.
Короткий ответ - нет. Длинный ответ ниже.
Переключение контекста происходит в следующих случаях:
Сам переключатель является односторонним, поэтому лучшее, что мы можем сделать в пользовательской среде (я предполагаю, что это то, о чем вы спрашиваете), это измерить что-то вроде RTT, от нашего процесса к другому и обратно. Другому процессу также требуется время для выполнения своей работы. Конечно, мы можем заставить два или более процессов сотрудничать в этом, но дело в том, что ядро не гарантирует, что один из наших процессов будет выбран следующим. Вероятно, можно предсказуемо переключаться на заданный процесс с помощью RT планировщика, но здесь у меня нет совета, предложения приветствуются.