Запишите программу C для измерения времени, проведенного в контекстном переключении в Linux ОС

Мы можем записать c программу для обнаружения времени, проведенного в контекстном переключении в Linux? Вы могли совместно использовать код, если у Вас есть тот? Спасибо

27
задан Gautham 3 March 2010 в 02:34
поделиться

3 ответа

Профилировать время переключения очень сложно, но инструменты профилирования задержки в ядре, а также 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 мс. Только.

Легенда в распечатке, похоже, содержит ошибку округления или что-то в этом роде (и вставленный исходный код не совпадает с версией). Я никогда особо не доводил это приложение до релиза ...

24
ответ дан 28 November 2019 в 05:24
поделиться

Если у вас есть привилегии суперпользователя, вы можете запустить программу SystemTap с точками зондирования для контекстных переключений и вывести текущее время в каждой из них:

probe scheduler.ctxswitch {
    printf("Switch from %d to %d at %d\n", prev_pid, next_pid, gettimeofday_us())
}

Я не уверен, насколько надежны выходные данные, но это быстрый и простой способ получить некоторые цифры.

8
ответ дан 28 November 2019 в 05:24
поделиться

Короткий ответ - нет. Длинный ответ ниже.

Переключение контекста происходит в следующих случаях:

  1. Пользовательский процесс входит в ядро через системный вызов или ловушку (например, ошибка страницы) и запрашиваемые данные (например, содержимое файла) еще не доступны, поэтому ядро переводит пользовательский процесс в состояние сна и переключается на другой выполняемый процесс.
  2. Ядро обнаруживает, что данный пользовательский процесс израсходовал все свои кванты времени (это происходит в коде, вызываемом из прерывания по таймеру).
  3. Данные становятся доступными для процесса с более высоким текущим приоритетом, который в данный момент спит (это происходит в коде, вызываемом из/в обход прерываний IO).

Сам переключатель является односторонним, поэтому лучшее, что мы можем сделать в пользовательской среде (я предполагаю, что это то, о чем вы спрашиваете), это измерить что-то вроде RTT, от нашего процесса к другому и обратно. Другому процессу также требуется время для выполнения своей работы. Конечно, мы можем заставить два или более процессов сотрудничать в этом, но дело в том, что ядро не гарантирует, что один из наших процессов будет выбран следующим. Вероятно, можно предсказуемо переключаться на заданный процесс с помощью RT планировщика, но здесь у меня нет совета, предложения приветствуются.

4
ответ дан 28 November 2019 в 05:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: