Точность clock_gettime () в сценарии переключения контекста - PullRequest
0 голосов
/ 30 января 2019

Я пытаюсь «грубо» рассчитать время переключения контекста потока в системе Linux.Я написал программу, которая использует каналы и многопоточность для достижения этой цели.При запуске программы рассчитанное время явно неверно (см. Вывод ниже).Я не уверен, что это из-за того, что я использовал неправильный clock_id для этой процедуры или, возможно, мою реализацию

Я реализовал sched_setaffinity (), чтобы программа работала только на ядре 0. Я пытался выйтитак много пуха из кода, чтобы измерить только время переключения контекста, поэтому процесс протектора записывает в канал только один символ, а родитель читает 0 байт.

У меня есть родительский шаг, которыйсоздает один дочерний поток с односторонним каналом между ними для передачи данных, дочерний поток выполняет простую функцию для записи в канал.

    void* thread_1_function()
    {
         write(fd2[1],"",sizeof("");
    }

, в то время как родительский поток создает дочерний поток, запускает времяcounter, а затем вызывает чтение по каналу, в который записывается дочерний поток.

int main(int argc, char argv[])
{
//time struct declaration
struct timespec start,end;

//sets program to only use core 0
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(0,&cpu_set);


if((sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) < 1))
{

int nproc = sysconf(_SC_NPROCESSORS_ONLN);
int k;

printf("Processor used: ");
for(k = 0; k < nproc; ++k)
{
    printf("%d ", CPU_ISSET(k, &cpu_set));
}

printf("\n");


if(pipe(fd1) == -1)
{
    printf("fd1 pipe error");
    return 1;
}
//fail on file descriptor 2 fail
if(pipe(fd2) == -1)
{
    printf("fd2 pipe error");
    return 1;
}


pthread_t thread_1;


pthread_create(&thread_1, NULL, &thread_1_function, NULL);


pthread_join(thread_1,NULL);


int i;
uint64_t sum = 0;

for(i = 0; i < iterations; ++i)
{

    //initalize clock start
    clock_gettime(CLOCK_MONOTONIC, &start);
    //wait for child thread to write to pipe
    read(fd2[0],input,0);
    //record clock end
    clock_gettime(CLOCK_MONOTONIC, &end);   

    write(fd1[1],"",sizeof(""));



    uint64_t diff;
    diff = billion * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
    diff = diff;
    sum += diff;
}

Результаты, которые я получаю при выполнении этого, обычно таковы:

     3000
     3000
     4000
     2000
     12000
     3000
     5000

и т. д., когда я проверяю время, возвращаемое в начальную и конечную структуры timepec, я вижу, что tv_nsec также представляется «округленным» числом:

     start.tv_nsec: 714885000, end.tv_nsec: 714888000

WoulМожет ли это быть вызвано тем, что clock_monotonic недостаточно точен для того, что я пытаюсь измерить, или какой-то другой проблемой, которую я пропускаю?

1 Ответ

0 голосов
/ 30 января 2019

я вижу, что tv_nsec также представляется «округленным» числом:

 2626, 714885000, 2626, 714888000

Это может быть вызвано тем, что clock_monotonic недостаточно точен для того, что я пытаюсь измерить, или каким-то другимДругая проблема, которую я пропускаю?

Да, это возможно.Каждые часы, поддерживаемые системой, имеют фиксированное разрешение.struct timespec способен поддерживать часы с наносекундным разрешением, но это не означает, что вы можете ожидать, что каждые часы на самом деле будут иметь такое разрешение.Похоже, ваше CLOCK_MONOTONIC может иметь разрешение 1 микросекунда (1000 наносекунд), но вы можете проверить это с помощью функции clock_getres().

Если оно доступно вам, то вы можете попробовать CLOCK_PROCESS_CPUTIME_ID.Вполне возможно, что это будет иметь более высокое разрешение, чем CLOCK_MONOTONIC, но обратите внимание, что разрешение в одну микросекунду довольно точное - это порядка одного тика на 3000 циклов ЦП на современной машине.


Несмотря на это, я вижу несколько возможных проблем с вашим подходом:

  • Несмотря на то, что вы настроили свой процесс на привязку к одному ЦП, это не мешает системе планировать другиепроцессы на этом процессоре тоже.Таким образом, если вы не предприняли дополнительных мер, вы не можете быть уверены - даже маловероятно - что каждый контекст, переключающийся с одного из потоков вашей программы, равен на другого потока.

  • Вы запускаете вторую тему, а затем сразу присоединяетесь к ней.После этого больше не будет переключаться контекст между вашими потоками, потому что ваш второй поток больше не существует после успешного присоединения.

  • read() со счетчиком 0 может или не может проверять наличиеошибки, и это, конечно, не передает никаких данных.Мне совершенно непонятно, почему вы идентифицируете время для этого вызова со временем для переключения контекста.

  • Если переключение контекста действительно происходит в пространстве, которое вы синхронизируете, то втам должно произойти как минимум два - от вашей программы и обратно к ней.Кроме того, вы измеряете время, затрачиваемое на то, что еще работает в другом контексте, а не только на время переключения.Таким образом, шаги в 1000 наносекунд могут отражать временные интервалы, а не время переключения.

  • Ваш основной поток записывает нулевые символы в конец записи канала, но, похоже,что-нибудь, читая их.Если действительно нет, то это в конечном итоге заполнит буфер и блок канала.Цель потеряна для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...