Как оценить контекстное переключение потока наверху?

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

57
задан Ignas Limanauskas 21 November 2008 в 01:08
поделиться

7 ответов

В то время как Вы сказали, что не хотите писать тестовое приложение, я сделал это для предыдущего теста на платформе ARM9 Linux для обнаружения, каковы издержки. Это были всего два потока, которые повысят:: поток:: урожай () (или, Вы знаете), и увеличьте некоторую переменную, и приблизительно после одной минуты (без других рабочих процессов, по крайней мере, ни один, что делает что-то), приложение, распечатанное, сколько контекстных переключений это могло сделать в секунду. Конечно, это не действительно точно, но дело в том, что оба потока привели к ЦП друг другу, и это было настолько быстро, что просто не имело смысла больше думать об издержках. Так, просто идите вперед и просто запишите простой тест вместо того, чтобы думать слишком много о проблеме, которая может не существовать.

, Кроме которого, Вы могли бы попробовать как 1800, предложенный со счетчиками производительности.

, О, и я помню приложение, работающее на Windows CE 4. X, где мы также имеем четыре потока с интенсивным переключением время от времени, и никогда не сталкивались с проблемами производительности. Мы также пытались реализовать базовую вещь поточной обработки без потоков вообще и не видели повышения производительности (GUI просто ответил намного медленнее, но все остальное было тем же). Возможно, можно попробовать то же, или сокращением количества контекстных переключений или путем удаления потоков полностью (только для тестирования).

13
ответ дан OregonGhost 7 November 2019 в 16:11
поделиться

Вы не можете оценить его. Необходимо измерить его. И это собирается варьироваться в зависимости от процессора по устройству.

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

Первый, код путем (псевдокод):

DWORD tick;

main()
{
  HANDLE hThread = CreateThread(..., ThreadProc, CREATE_SUSPENDED, ...);
  tick = QueryPerformanceCounter();
  CeSetThreadPriority(hThread, 10); // real high
  ResumeThread(hThread);
  Sleep(10);
}

ThreadProc()
{
  tick = QueryPerformanceCounter() - tick;
  RETAILMSG(TRUE, (_T("ET: %i\r\n"), tick));
}

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

можно получить более точное измерение с CeLog путем сцепления в события планировщика, но совсем не просто сделать и не очень хорошо зарегистрированное. Если Вы действительно хотите пойти тем путем, у Sue Loh есть несколько блогов на нем, которые может найти поисковая система.

маршрут некода должен был бы использовать Удаленное Средство отслеживания Ядра. eVC 4.0 установки или версия оценки Platform Builder для получения его. Это даст графический дисплей всего, что ядро делает, и можно непосредственно измерить контекстное переключение потока с обеспеченными возможностями курсора. Снова, я уверен, что у Sue есть запись в блоге при использовании Средства отслеживания Ядра также.

Однако Вы собираетесь найти, что контекстные переключения потока внутрипроцесса CE действительно, действительно быстро. Это - переключатели процесса, которые являются дорогими, поскольку это требует свопинга активного процесса в RAM и затем выполнения миграции.

14
ответ дан ctacke 7 November 2019 в 16:11
поделиться

Я не знаю, но у Вас есть обычные счетчики производительности в Windows Mobile? Вы могли посмотреть на вещи как переключатели/секунда контекста. Я не знаю, существует ли тот, который конкретно измеряет время контекстного переключения все же.

1
ответ дан 1800 INFORMATION 7 November 2019 в 16:11
поделиться

Я только когда-либо пытался оценить это однажды, и это было на 486! Результат был то, что контекстное переключение процессора брало приблизительно 70 инструкций завершиться (обратите внимание, что это происходило для многих вызовов API ОС, а также переключения потока). Мы вычислили, что это брало приблизительно 30us на переключатель потока (включая ОС наверху) на DX3. Несколько тысяч контекстных переключений, которые мы делали в секунду, были абсорбирующими между 5-10% процессорного времени.

, Как это перевело бы в многоядерное, multi-ghz современный процессор, который я не знаю, но я предположил бы, что, если Вы полностью не перебарщивали с переключением потока, это - незначительные издержки.

Примечание, которые распараллеливают создание/удаление, является более дорогим ЦП/ОС hogger, чем активация/деактивация потоков. Хорошая политика для в большой степени потоковых приложений состоит в том, чтобы использовать пулы потоков и активировать/деактивировать как требуется.

5
ответ дан Tim Ring 7 November 2019 в 16:11
поделиться

Я сомневаюсь, что можно найти эти издержки где-нибудь в сети для любой существующей платформы. Там существует просто слишком много различных платформ. Издержки зависят от двух факторов:

  • ЦП, поскольку необходимые операции могут быть легче или более трудными на различных типах ЦП
  • системное ядро как различные ядра, должен будет выполнить различные операции на каждом переключателе

, Другие факторы включают, как переключатель происходит. Переключатель может произойти, когда

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

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

  3. потоку больше не требуется процессорное время, потому что это блокируется на некоторой операции или просто названное сном () (или подобное), чтобы прекратить работать.

Эти 3 сценария могли бы иметь различное время переключения потока в теории. Например, я ожидал бы, что последний будет самым медленным, так как вызов для сна () означает, что ЦП отдан к ядру, и ядро должно установить призыв к действию, который удостоверится, что поток разбужен, после приблизительно количество времени это запросило спать, это тогда должно вынуть поток из процесса планирования, и как только поток разбужен, это должно добавить поток снова к процессу планирования. Все, что они погружают, займут некоторое количество времени. Таким образом, фактический вызов сна мог бы быть более длинным, чем время, которое требуется для переключения на другой поток.

я думаю, хотите ли Вы знать наверняка, необходимо сравнить. Проблема состоит в том, что обычно необходимо будет или поместить потоки для сна, или необходимо синхронизировать их использующий взаимные исключения. Сон или Блокировка/Разблокирование взаимных исключений имеют самостоятельно издержки. Это означает, что Ваш сравнительный тест будет включать эти издержки также. Не имея мощного профилировщика, трудно позже сказать, сколько процессорного времени использовалось для фактического переключателя и сколько для sleep/mutex-call. С другой стороны, в реальном сценарии, Ваши потоки будут или спать или синхронизироваться через блокировки также. Сравнительный тест, который просто измеряет время контекстного переключения, искусственно сравнительный тест, поскольку это не моделирует реального сценария. Сравнительные тесты намного более "реалистичны", если они базируются на реальных сценариях. Из какого использование является сравнительным тестом GPU, который говорит мне, что мой GPU может в теории обрабатывать 2 миллиарда полигонов в секунду, если этот результат никогда не может достигаться в реальном 3D приложении? Не было бы намного более интересно знать, сколько полигонов реальное 3D приложение может иметь дескриптор GPU секунда?

, К сожалению, я не знаю ничего из программирования Windows. Я мог записать приложение для Windows в Java или возможно в C#, но C/C++ в Windows заставляет меня кричать. Я могу только предложить Вам некоторый исходный код для POSIX.

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>

uint32_t COUNTER;
pthread_mutex_t LOCK;
pthread_mutex_t START;
pthread_cond_t CONDITION;

void * threads (
    void * unused
) {
    // Wait till we may fire away
    pthread_mutex_lock(&START);
    pthread_mutex_unlock(&START);

    pthread_mutex_lock(&LOCK);
    // If I'm not the first thread, the other thread is already waiting on
    // the condition, thus Ihave to wake it up first, otherwise we'll deadlock
    if (COUNTER > 0) {
        pthread_cond_signal(&CONDITION);
    }
    for (;;) {
        COUNTER++;
        pthread_cond_wait(&CONDITION, &LOCK);
        // Always wake up the other thread before processing. The other
        // thread will not be able to do anything as long as I don't go
        // back to sleep first.
        pthread_cond_signal(&CONDITION);
    }
    pthread_mutex_unlock(&LOCK); //To unlock
}

int64_t timeInMS ()
{
    struct timeval t;

    gettimeofday(&t, NULL);
    return (
        (int64_t)t.tv_sec * 1000 +
        (int64_t)t.tv_usec / 1000
    );
}


int main (
    int argc,
    char ** argv
) {
    int64_t start;
    pthread_t t1;
    pthread_t t2;
    int64_t myTime;

    pthread_mutex_init(&LOCK, NULL);
    pthread_mutex_init(&START, NULL);   
    pthread_cond_init(&CONDITION, NULL);

    pthread_mutex_lock(&START);
    COUNTER = 0;
    pthread_create(&t1, NULL, threads, NULL);
    pthread_create(&t2, NULL, threads, NULL);
    pthread_detach(t1);
    pthread_detach(t2);
    // Get start time and fire away
    myTime = timeInMS();
    pthread_mutex_unlock(&START);
    // Wait for about a second
    sleep(1);
    // Stop both threads
    pthread_mutex_lock(&LOCK);
    // Find out how much time has really passed. sleep won't guarantee me that
    // I sleep exactly one second, I might sleep longer since even after being
    // woken up, it can take some time before I gain back CPU time. Further
    // some more time might have passed before I obtained the lock!
    myTime = timeInMS() - myTime;
    // Correct the number of thread switches accordingly
    COUNTER = (uint32_t)(((uint64_t)COUNTER * 1000) / myTime);
    printf("Number of thread switches in about one second was %u\n", COUNTER);
    return 0;
}

Вывод

Number of thread switches in about one second was 108406

более чем 100'000 не слишком плохи и что даже при том, что у нас есть блокировка и условное выражение, ожидает. Я предположил бы без всего этого материала, по крайней мере, вдвое больше переключателей потока было возможно секунда.

26
ответ дан SH' 7 November 2019 в 16:11
поделиться

Проблема с переключениями контекста в том, что они имеют фиксированное время. Графический процессор реализовал переключение контекста между потоками за 1 цикл. Следующее, например, не может быть распределено на CPU:

double * a; 
...
for (i = 0; i < 1000; i ++)
{
    a[i] = a[i] + a[i]
}

, потому что время его выполнения намного меньше, чем стоимость переключения контекста. На Core i7 этот код занимает около 1 микросекунды (зависит от компилятора). Таким образом, время переключения контекста имеет значение, потому что оно определяет, как можно распределять небольшие задания. Я предполагаю, что это также обеспечивает метод эффективного измерения переключения контекста. Проверьте, какой длины должен быть массив (в верхнем примере), чтобы два потока из пула потоков начали показывать реальное преимущество по сравнению с однопоточным. Это может легко превратиться в 100 000 элементов, и поэтому эффективное время переключения контекста будет где-то в диапазоне 20 мкс в одном приложении.

Все инкапсуляции, используемые пулом потоков, должны учитываться до времени переключения потоков, потому что именно к этому все сводится (в конце).

Атмапури

3
ответ дан 24 November 2019 в 19:43
поделиться

Мои 50 строк C++ показывают для Linux (QuadCore Q6600) время переключения контекста ~ 0.9us (0.75us для 2 потоков, 0.95 для 50 потоков). В этом бенчмарке потоки вызывают yield немедленно, когда получают квант времени.

7
ответ дан 24 November 2019 в 19:43
поделиться