Подтвердить что ты не робот

Как вы можете измерить время, проведенное в контекстном переключателе под платформой java

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

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

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

4b9b3361

Ответ 1

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

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

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

Идеал заключается в сегментировании ОЗУ, распределении на фиксированное число рабочих одной большой единицы работы, затем использовании счетчика-защелки или какого-либо другого барьера памяти (чтобы каждый поток касался только один раз). В идеале любые временные буферы предварительно выделяются вместо того, чтобы входить в пул разделяемой памяти и выходить из него (что приводит к конфликту с кешем). Java "синхронизировал" блокирует использование (за кулисами) общего пространства памяти хэш-таблицы и, таким образом, вызывает нежелательные грязные чтения, я не определил, избегают ли этого объекта блокировки java 5 Lock, но вы все еще используете стойки OS, которые выиграли Не помогайте в вашей пропускной способности. Очевидно, что большинство операций OutputStream запускают такие синхронные вызовы (и, конечно, обычно заполняют общий буфер потока).

Как правило, мой опыт заключается в том, что однопоточность выполняется быстрее, чем mulithreading для общего массива byte-array/object-array и т.д. По крайней мере, с упрощенными алгоритмами сортировки/фильтрации, с которыми я экспериментировал. Это верно как в Java, так и в C в моем опыте. Я не пробовал FPU intesive ops (например, dives, sqrt), где кеш-строки могут быть менее значимыми.

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

Ответ 2

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

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(); 
        }
    }
}

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

Ответ 3

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

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

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

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

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

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

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

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