-
-
Save iaveryanov/9949603 to your computer and use it in GitHub Desktop.
| package ru.inlinetelecom.vn2.util; | |
| import java.util.concurrent.CountDownLatch; | |
| import java.util.concurrent.ExecutorService; | |
| import java.util.concurrent.Executors; | |
| import java.util.concurrent.atomic.AtomicInteger; | |
| import java.util.concurrent.atomic.AtomicLong; | |
| /** | |
| * вариант с uncontended lock (getAvailableProcessors >= worker_count | |
| */ | |
| public class AtomicDecUntilZeroMain { | |
| // счетчик холостого хода | |
| private static AtomicLong idlingCounter = new AtomicLong(0); | |
| /** | |
| * 1) вызывается из многих потоков | |
| * 2) не должно быть меньше 0 | |
| * 3) если уже 0 и вызывают этот метод, то должно оставаться 0 | |
| * | |
| * @param counter | |
| * @return 0 or value after decrement | |
| */ | |
| private static int decUntilZero(AtomicInteger counter) { | |
| while (true) { | |
| int current = counter.get(); | |
| if (current == 0) { | |
| return current; | |
| } | |
| int next = current - 1; | |
| if (counter.compareAndSet(current, next)) { | |
| return next; | |
| } | |
| idlingCounter.incrementAndGet(); | |
| } | |
| } | |
| public static void main(String[] args) throws InterruptedException { | |
| final int initialValue = 400000000; | |
| final int countOfThreads = 4; // всего потоков | |
| final int countOfDecPerThread = initialValue/countOfThreads; // количество декрементов на один поток | |
| final AtomicInteger counter = new AtomicInteger(initialValue); | |
| ExecutorService executor = Executors.newFixedThreadPool(countOfThreads); | |
| long startedAt = System.currentTimeMillis(); | |
| final CountDownLatch latch = new CountDownLatch(countOfThreads); | |
| for (int i = 0; i < countOfThreads; i++) { | |
| executor.execute(new Runnable() { | |
| @Override | |
| public void run() { | |
| for (int i = 0; i < countOfDecPerThread; i++) { | |
| decUntilZero(counter); | |
| } | |
| latch.countDown(); | |
| // System.out.println("task in progress..." + (latch.getCount())); | |
| } | |
| }); | |
| } | |
| System.out.println("всех ждёмс, однако..."); | |
| latch.await(); | |
| long elapsed = System.currentTimeMillis() - startedAt; | |
| executor.shutdown(); // за ненадобностью более! | |
| System.out.println("Ну наконец-ТА дождалИСА!!! Урра товариСЧи, уРРа!"); | |
| System.out.println("================================================"); | |
| int now = counter.get(); | |
| System.out.println("== INPUT DATA"); | |
| System.out.println(String.format("%s: %d", "initial ", initialValue)); | |
| System.out.println(String.format("%s: %d", "threads ", countOfThreads)); | |
| System.out.println(String.format("%s: %d", "dec per threads ", countOfDecPerThread)); | |
| System.out.println("== RESULTS"); | |
| System.out.println(String.format("%s: %d", "еще осталось ", now)); | |
| System.out.println(String.format("%s: %d", "раз выполнилось ", (initialValue - now))); | |
| System.out.println(String.format("%s: %d", "холостых ходов ", idlingCounter.get())); | |
| System.out.println(String.format("%s: %s", "elapsed, millis ", elapsed)); | |
| } | |
| } |
atop - это средство сбора данных о работе системы (типа top, но с возможность просмотра исторической статистики)
посмотри man atop
установи его sudo apt-get install atop
затем запусти сбор данных atop -w atop.log -S 1 (раз в секунду)
собирай данные в момент запуска своих экспериментов
после проведения эксперимента останови сбор статистики atop
и теперь ты можешь читать данные по использованию системных ресурсов из файла atop.log
это бинарный файл - его читать нужно через atop -r atop.log
листать посекундные отчеты можно с помощью интерактивной навигации - клавишы t и T
можешь например отрисовать график средней загрузки системы с помощью gnuplot
скрипт тут https://gist.github.com/LexaChebara/9951340
например cpl.sh atop.log
вообще неплохо бы исследования оформить графиком
кол-во холостых ходов лучше не в абсолютных величинах, а в относительных. например, в процентах от величины initialValue
да я о процентах уже подумал, улучу
какая версия jdk?
Profile
java version "1.7.0_40"
Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)
Linux 2.6.38-13-server #57 SMP Sun Feb 19 22:11:49 UTC 2012 x86_64 GNU/Linux
2 x Intel(R) Xeon(R) CPU E5645 @ 2.40GHz, т.е. 12 hardware cpu core или 24 потока
Results
Initial value - 400 000 000
| Pool size | Ops per thread | Final value | Op count | Misses count | Time elapsed, ms |
|---|---|---|---|---|---|
| 4 | 100 000 000 | 0 | 400 000 000 | 105 621 882 | 23 303 |
| 24 | 16 666 666 | 16 | 399 999 984 | 367 097 933 | 40 331 |
| 100 | 4 000 000 | 0 | 400 000 000 | 383 702 094 | 41 787 |
Интрересно, почему время увеличилось в 2 раза?
Время увеличилось в 2 раза вот почему.
Кол-во промахов стало в 3 раза больше.
Кол-во одновременно работающих потоков (так как 12 ядер) стало в 3 раза больше, а, следовательно, конфликтов стало больше. Вероятность конфликта растет с количеством одновременно работающих потоков. Операция cmpxchg блокирует шину данных при чтении из памяти.
могу запустить на 24 ядрах