Как вы можете измерить время, проведенное в переключении контекста под платформой Java - PullRequest
20 голосов
/ 08 августа 2011

Давайте предположим, что каждый поток выполняет некоторые вычисления FP, меня интересует

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

Мой вопрос: как разработать тестовую программу для получения этих данных?

Ответы [ 3 ]

10 голосов
/ 09 августа 2011

Вы не можете легко дифференцировать потери из-за переключения потоков и из-за нехватки памяти.Вы МОЖЕТЕ измерить конфликт между потоками. А именно, в linux вы можете выполнить cat / proc / PID / XXX и получить тонны подробной статистики по потокам.ОДНАКО, так как упреждающий планировщик не собирается стрелять сам в ногу, вы не получите больше, чем, скажем, 30 ctx-переключателей в секунду, независимо от того, сколько потоков вы используете. И это время будет относительномаленький по сравнению с объемом работы, которую вы делаете. Реальная стоимость переключения контекста - загрязнение кеша.Например, существует высокая вероятность того, что вы будете в большинстве случаев пропадать в кеше после переключения контекста. Таким образом, время ОС и количество переключений контекста имеют минимальное значение.

ДЕЙСТВИТЕЛЬНО ценным является соотношениегрязи между потокамиВ зависимости от процессора, грязная строка кэша, за которой следует одноранговое чтение, является МЕНЬШЕ, чем промах кэша - потому что вы должны заставить одноранговый ЦПУ записать его значение в main-mem, прежде чем вы даже сможете начать чтение. НекоторыеПроцессоры позволяют вам извлекать из одноранговых строк кэша, не нажимая main-mem.

Таким образом, ключ к абсолютному минимизации ЛЮБЫХ общих модифицированных структур памяти. Делайте все максимально доступным только для чтения. Это ВКЛЮЧАЕТ общий буфер FIFO(включая пулы исполнителей). А именно, если вы использовали синхронизированную очередь - тогда каждая синхронизация является общей грязной областью памяти.И более того, если скорость достаточно высока, она, скорее всего, вызовет прерывание ОС, ожидая мьютекса однорангового потока.

Идеально - сегментировать оперативную память, распределять ее среди фиксированного числа рабочих.одну большую единицу работы, затем используйте защелку обратного отсчета или какой-либо другой барьер памяти (чтобы каждый поток касался его только один раз).В идеале любые временные буферы предварительно выделяются вместо того, чтобы входить и выходить из общего пула памяти (что затем приводит к конфликту в кэше).«Синхронизированные» блоки Java используют (за кулисами) разделяемое пространство памяти хэш-таблицы и, таким образом, вызывают нежелательные «грязные» чтения. Я не определил, избегают ли объекты блокировки Java 5 этого, но вы все еще используете операционные системы, которые выигралине поможет в вашей пропускной способности.Очевидно, что большинство операций OutputStream инициируют такие синхронизированные вызовы (и, конечно, обычно заполняют общий буфер потока).

Вообще мой опыт показывает, что однопоточность быстрее, чем многопоточность, для обычного байтового массива / массива объектов и т. Д. По крайней мере с простыми алгоритмами сортировки / фильтрации, с которыми я экспериментировал.Это верно как для Java, так и для C, по моему опыту.Я не пробовал использовать операции FPU (например, divides, sqrt), где строки кэша могут иметь меньшее значение.

В основном, если вы используете один процессор, у вас нет проблем со строками кэша (если операционная система не всегда очищает кэш даже в общих потоках), но многопоточность покупает вас меньше, чем ничего.В гиперпоточности это то же самое.В конфигурациях кэш-памяти L2 / L3 с одним процессором (например, AMD) вы можете найти некоторое преимущество.В многопроцессорных процессорах Intel BUS забудьте об этом - общая память записи хуже, чем однопоточная.

2 голосов
/ 18 июля 2013

Чтобы измерить, сколько времени занимает переключение контекста, я бы запустил что-то вроде следующего:

public static void main(String[] args) {     
    Object theLock = new Object(); 
    long startTime;
    long endtime;
    synchronized( theLock ){
        Thread task = new TheTask( theLock ); 
        task.start();
        try {
             theLock.wait(); 
             endTime = System.currentTimeMillis();
        }
        catch( InterruptedException e ){
             // do something if interrupted
        }
    }
    System.out.println("Context Switch Time elapsed: " + endTime - startTime);
}

class TheTask extends Thread {
    private Object theLock;
    public TheTask( Object theLock ){
        this.theLock = theLock; 
    }
    public void run(){ 
        synchronized( theLock ){
            startTime = System.currentTimeMillis();
            theLock.notify(); 
        }
    }
}

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

1 голос
/ 09 августа 2011

сколько времени процессор использует для переключения потоков вместо их запуска

  • Допустим, у вас есть 100 миллионов FPU для выполнения.
  • Загрузите их всинхронизированная очередь (т. е. потоки должны заблокировать очередь при опросе)
  • Пусть n будет числом процессоров, доступных на вашем устройстве (duo = 2 и т. д.) *

Затем создайте n потоков, всасывающих очередь, чтобы выполнить все FPU.Вы можете вычислить общее время с помощью System.currentTimeMillis() до и после.Затем попробуйте использовать n + 1 потоков, затем n + 2, n + 3 и т. Д.

Теоретически, чем больше у вас потоков, тем больше будет переключений, тем больше времени потребуется дляобработать все FPU.Это даст вам весьма приблизительное представление о накладных расходах на переключение, но это трудно измерить.

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

Я бы создал 10 потоков, отправляющих каждые 10 000 сообщений в другой поток случайным образом, используя синхронизированную очередь блокировки из 100 сообщений.Каждый поток просматривал очередь блокировки, чтобы проверить, предназначено ли сообщение для них или нет, и вытащить его, если это правда.Затем они будут пытаться вставить сообщение без блокировки, затем повторить операцию просмотра и т. Д., Пока очередь не опустеет и все потоки не вернутся.

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

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

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