Re[8]: GetCurrentProcessorNumber() под WinXP
От: Sergey Storozhevykh Россия  
Дата: 23.01.08 06:56
Оценка:
Здравствуйте, remark, Вы писали:

R>О LB я упомянул только, что бы сказать, что нельзя вот так просто сделать SetThreadAffinityMask(), это компромисное решение. Помимо возможности определять номер процессора ты получишь ещё ряд артефактов, которые скорее всего ты не хочешь иметь. Больше никоим образом меня сейчас LB не интересует.


Можно более мягко попросить планировщик выбирать предпочитаемый процессор для исполнения кода потока — SetThreadIdealProcessor. Для ваших целей оптимизации чего-то там вполне может подойти

When a thread becomes ready to run, Windows 2000 first tries to schedule the thread to run on an idle processor. If there is a choice of idle processors, preference is given first to the thread's ideal processor, then to the thread's last processor, and then to the currently executing processor (that is, the CPU on which the scheduling code is running). If none of these CPUs are idle, Windows 2000 picks the first available idle processor by scanning the idle processor mask from highest to lowest CPU number.

If all processors are currently busy and a thread becomes ready, Windows 2000 looks to see whether it can preempt a thread in the running or standby state on one of the CPUs. Which CPU is examined? The first choice is the thread's ideal processor, and the second choice is the thread's last processor. If neither of those CPUs are in the thread's affinity mask, Windows 2000 selects the highest processor in the active processor mask that the thread can run on.

Re[9]: GetCurrentProcessorNumber() под WinXP
От: Геннадий Майко США  
Дата: 23.01.08 08:54
Оценка:
Здравствуйте, remark,

R>>>Здесь я написал более подробно, что я имею в виду:

R>>>http://gzip.rsdn.ru/forum/message/2806303.1.aspx
Автор: remark
Дата: 22.01.08

ГМ>>--
ГМ>>В примере Вы сравниваете апельсины с яблоками, потому что результаты работы 2х функций разные.

R>Естественно, 2 разные функции делают разное. Я сравниваю 2 разных метода решения одной и той же задачи. По-моему, тут всё корректно. А сравнивать 2 функции, которые дают одинаковый результат имхо бессмысленно...

--
1. Ваши два разных метода решения одной и той же задачи приводят к разным ответам, поэтому я по прежнему считаю Ваши результаты сравнения некорректными.
2. Почему же бессмысленно сравнивать 2 функции (устройства, методы и т.п.), которые дают один результат? Этот результат-то можно получить разными способами, за разное времы, с различными усилями и т.п.


ГМ>>Если я правильно понял, Вы хотите поместить некоторые данные в кеш процессора и работать только с ними "локально" в этом кэше, нет?


R>Ну, так скажем, примерно. Совсем локально — это уже другой случай, тогда можно просто размещать данные на стеке. Я же хочу "большую часть времени" работать с данными уже находящимися в кэше процессора, но при этом иметь возможность и агрегировать эти данные.

R>Т.е. с логической т.з. мне нужны глобальные данные, но с физической т.з. я хочу сделать их локальными.
--
1. Что такое "агрегировать эти данные"?

2. Как только Вы захотите корректно использовать глобальные данные, Вам нужно будет обеспечить механизм их консистентной и корректной видимости для всех CPU, которые захотят их использовать. Вам обязательно понадобится механизм обновления или переноса измененного глобального значения этой переменной от одного CPU к другому. Я бы попытался сравнивать время работу именно этих механизмов, хотя боюсь, это будет не просто. Более того, я бы стал это делать только тогда, когда выяснилось бы, что именно это является bottleneck в моей задаче.

С уважением,
Геннадий Майко.
Re[9]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 23.01.08 10:59
Оценка:
Здравствуйте, Sergey Storozhevykh, Вы писали:

SS>Здравствуйте, remark, Вы писали:


R>>О LB я упомянул только, что бы сказать, что нельзя вот так просто сделать SetThreadAffinityMask(), это компромисное решение. Помимо возможности определять номер процессора ты получишь ещё ряд артефактов, которые скорее всего ты не хочешь иметь. Больше никоим образом меня сейчас LB не интересует.


SS>Можно более мягко попросить планировщик выбирать предпочитаемый процессор для исполнения кода потока — SetThreadIdealProcessor. Для ваших целей оптимизации чего-то там вполне может подойти



Речь идёт о библиотечном коде, т.ч. никакие трюки типа SetThreadIdealProcessor() и SetThreadAffinityMask() не подходят.



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[10]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 23.01.08 11:11
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

ГМ>Здравствуйте, remark,


R>>>>Здесь я написал более подробно, что я имею в виду:

R>>>>http://gzip.rsdn.ru/forum/message/2806303.1.aspx
Автор: remark
Дата: 22.01.08

ГМ>>>--
ГМ>>>В примере Вы сравниваете апельсины с яблоками, потому что результаты работы 2х функций разные.

R>>Естественно, 2 разные функции делают разное. Я сравниваю 2 разных метода решения одной и той же задачи. По-моему, тут всё корректно. А сравнивать 2 функции, которые дают одинаковый результат имхо бессмысленно...

ГМ>--
ГМ>1. Ваши два разных метода решения одной и той же задачи приводят к разным ответам, поэтому я по прежнему считаю Ваши результаты сравнения некорректными.
ГМ>2. Почему же бессмысленно сравнивать 2 функции (устройства, методы и т.п.), которые дают один результат? Этот результат-то можно получить разными способами, за разное времы, с различными усилями и т.п.


Если под разным результатами ты имеешь в виду, что в одном случае сумма лежит в одной переменной, а в другом в нескольких, то это не есть разный результат, т.к. я в тест специально включил и агрегирование данных. В одном случае оно выглядит как:
            volatile int x = values[0].value;


В другом как:
            volatile int x = 0;
            for (int j = 0; j != arch::processor_count; ++j)
            {
                x += values[j].value;
            }


Т.ч. в этом смысле результата разного нет — я всегда получаю полную сумму.




ГМ>>>Если я правильно понял, Вы хотите поместить некоторые данные в кеш процессора и работать только с ними "локально" в этом кэше, нет?


R>>Ну, так скажем, примерно. Совсем локально — это уже другой случай, тогда можно просто размещать данные на стеке. Я же хочу "большую часть времени" работать с данными уже находящимися в кэше процессора, но при этом иметь возможность и агрегировать эти данные.

R>>Т.е. с логической т.з. мне нужны глобальные данные, но с физической т.з. я хочу сделать их локальными.
ГМ>--
ГМ>1. Что такое "агрегировать эти данные"?

Это то, что я привёл выше.


ГМ>2. Как только Вы захотите корректно использовать глобальные данные, Вам нужно будет обеспечить механизм их консистентной и корректной видимости для всех CPU, которые захотят их использовать.


В тесте это обеспечивается.


ГМ>Вам обязательно понадобится механизм обновления или переноса измененного глобального значения этой переменной от одного CPU к другому.


У меня все компьютеры с когерентрым кэшем. Компьютеры с некогерентным кэшем меня пока не интересует... потому что я их не видел.


ГМ>Я бы попытался сравнивать время работу именно этих механизмов, хотя боюсь, это будет не просто.


Всё, что нужно, учитывается в тесте. Это полноценный вариант счётчика.


ГМ>Более того, я бы стал это делать только тогда, когда выяснилось бы, что именно это является bottleneck в моей задаче.


Я отказываюсь это обсуждать — с этим в Философию.



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[11]: GetCurrentProcessorNumber() под WinXP
От: Геннадий Майко США  
Дата: 23.01.08 12:36
Оценка:
Здравствуйте, remark,

R>Если под разным результатами ты имеешь в виду, что в одном случае сумма лежит в одной переменной, а в другом в нескольких, то это не есть разный результат, т.к. я в тест специально включил и агрегирование данных. В одном случае оно выглядит как:

R>
R>            volatile int x = values[0].value;
R>


R>В другом как:

R>
R>            volatile int x = 0;
R>            for (int j = 0; j != arch::processor_count; ++j)
R>            {
R>                x += values[j].value;
R>            }
R>


R>Т.ч. в этом смысле результата разного нет — я всегда получаю полную сумму.

--
Замените arch::processor_count на случайную величину, и я сомневаюсь, что результаты такого теста будут сильно отличаться от Вашего оригинального.


ГМ>>Вам обязательно понадобится механизм обновления или переноса измененного глобального значения этой переменной от одного CPU к другому.


R>У меня все компьютеры с когерентрым кэшем. Компьютеры с некогерентным кэшем меня пока не интересует... потому что я их не видел.


ГМ>>Я бы попытался сравнивать время работу именно этих механизмов, хотя боюсь, это будет не просто.


R>Всё, что нужно, учитывается в тесте. Это полноценный вариант счётчика.

--
Да, я тоже имею в виду компьютеры с когерентым кешем. Я просто хочу Вам подсказать, что вариантов обеспечения такой когерентности может быть не один. Посмотрите, например, описания тех же x86 процессоров.



ГМ>>Более того, я бы стал это делать только тогда, когда выяснилось бы, что именно это является bottleneck в моей задаче.


R>Я отказываюсь это обсуждать — с этим в Философию.

--
Да, наверное, на этом стоит прекратить нашу дискуссию.

С уважением,
Геннадий Майко.
Re[12]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 23.01.08 12:41
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

R>>Т.ч. в этом смысле результата разного нет — я всегда получаю полную сумму.

ГМ>--
ГМ>Замените arch::processor_count на случайную величину, и я сомневаюсь, что результаты такого теста будут сильно отличаться от Вашего оригинального.

Какой в этом смысл?
Эта величина не должна быть случайной!



R>>Всё, что нужно, учитывается в тесте. Это полноценный вариант счётчика.

ГМ>--
ГМ>Да, я тоже имею в виду компьютеры с когерентым кешем. Я просто хочу Вам подсказать, что вариантов обеспечения такой когерентности может быть не один. Посмотрите, например, описания тех же x86 процессоров.

А какая разница какой механизм обеспечения когерентности используется? Главное, что он есть.
Я именно под x86 в основном и пишу...



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[13]: GetCurrentProcessorNumber() под WinXP
От: Геннадий Майко США  
Дата: 23.01.08 13:21
Оценка:
Здравствуйте, remark,

R>>>Т.ч. в этом смысле результата разного нет — я всегда получаю полную сумму.

ГМ>>--
ГМ>>Замените arch::processor_count на случайную величину, и я сомневаюсь, что результаты такого теста будут сильно отличаться от Вашего оригинального.

R>Какой в этом смысл?

R>Эта величина не должна быть случайной!
--
Смысл простой — предпочтительно работать с разными переменными в разных потоках.
А какая разница — случайная ли она из-за вызова функции GetCurrentProcessorNumber() или или из-за вызова функции rand()?


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

С уважением,
Геннадий Майко.
Re[14]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 23.01.08 15:03
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

Правила форума нарушены.
— оверквотинг
Правила можно найти в разделе FAQ данного форума и\или ресурса.
Нарушение правил может повлечь за собой санкции, описанные там же — модератор
ГМ>Если Ваша цель — как-то разделить обработку переменной, то это можно делать не только по номеру процессора, но и по любому другому закону; главное, чтобы обеспечивалось уникальность номера для каждого потока команд.


Здесь я описал почему не всегда можно использовать идентификатор потока:
http://www.rsdn.ru/Forum/message/2808741.aspx
Автор: Andrew.W Worobow
Дата: 23.01.08


Случайный номер имхо это заведомо хуже, чем номер процессора.



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: GetCurrentProcessorNumber() под WinXP
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 28.01.08 17:47
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

ГМ>Well, я, пока не знаю точно, что подразумевается под выделенным выше, но если это реализация, например, какого-то рекурсивного спинлока, то вполне можно обойтись и без номера процессора. Я вспоминаю, что эту же тему мы обсуждали как-то несколько лет назад с Евгением Музыченко в другом месте, и вроде пришли к этому же выводу.


Да, я тогда заменил KeGetCurrentProcessorNumber на KeGetCurrentThread, и не только получил всю нужную функциональность, но и избавился от лишних проверок, ибо номер процессора может меняться, а идентификатор потока — нет.

Только вот возникает ощущение, что рекурсивные спинлоки — штука удобная и универсальная, но провоцирует на избыточный код, и порой довольно заметно снижает быстродействие
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 28.01.08 18:06
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, Геннадий Майко, Вы писали:


ГМ>>Well, я, пока не знаю точно, что подразумевается под выделенным выше, но если это реализация, например, какого-то рекурсивного спинлока, то вполне можно обойтись и без номера процессора. Я вспоминаю, что эту же тему мы обсуждали как-то несколько лет назад с Евгением Музыченко в другом месте, и вроде пришли к этому же выводу.


ЕМ>Да, я тогда заменил KeGetCurrentProcessorNumber на KeGetCurrentThread, и не только получил всю нужную функциональность, но и избавился от лишних проверок, ибо номер процессора может меняться, а идентификатор потока — нет.



Это значит, что функциональность, которая тебе требовалась, прямолинейнее той, которая требуется мне. Про то, что можно использовать идентификатор потока, я, естественно, в курсе. Про то, что его не всегда достаточно я писал здесь:
http://gzip.rsdn.ru/forum/message/2806303.1.aspx
Автор: remark
Дата: 22.01.08



ЕМ>Только вот возникает ощущение, что рекурсивные спинлоки — штука удобная и универсальная, но провоцирует на избыточный код, и порой довольно заметно снижает быстродействие



Хммм, вообще считается, что рекурсивные локи — вещь вредная, т.к. провоцирует на небрежный/кривой код. В любом случае, они тривиально реализуются с помощью GetСurrentThreadId(), идентификатор процессора тут совершенно не нужен.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[8]: GetCurrentProcessorNumber() под WinXP
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.01.08 05:11
Оценка:
Здравствуйте, remark, Вы писали:

R>Это значит, что функциональность, которая тебе требовалась, прямолинейнее той, которая требуется мне. Про то, что можно использовать идентификатор потока, я, естественно, в курсе. Про то, что его не всегда достаточно я писал здесь:

R>http://gzip.rsdn.ru/forum/message/2806303.1.aspx
Автор: remark
Дата: 22.01.08


Я, честно говоря, так и не понял, чего ты хочешь достичь — практически, а не теоретически. Любопытства ради я прогнал твой пример на двухъядерном Athlon 64 X2, под виндами (линуха у меня нет). Создавал восемь потоков с привязкой к процессорам и без нее. Скомпилировано MS VS 2005 (VC 8), _InterlockedIncrement раскрывается в lock xadd. Ну и во втором случае _InterlockedIncrement будет избыточным, ибо конкуренции за переменную нет.

Получилось вот что (количество тактов на проход цикла):

1 с привязкой к процессорам — 56
1 без привязки — 57
2 с привязкой с _InterlockedIncrement — 12
2 без привязки с _InterlockedIncrement — 12
2 с привязкой с ++ — 5
2 без привязки с ++ — 6

То есть, наиболее эффективный вариант — привязывать потоки к процессорам. Если каждый поток занимается интенсивной вычислительной работой, то от привязки к разным процессорам они только выиграют. Если же загрузка неравномерная, то и вероятность конфликта за переменную падает многократно, а вероятность получения номера на одном процессоре и последующего переключения на другой, наоборот, возрастает. Так что обоснованность твоего стремления представляется весьма сомнительной.

Если есть практические примеры, показывающие эффективность именно выбранного тобой подхода — буду рад посмотреть.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[9]: GetCurrentProcessorNumber() под WinXP
От: MShura  
Дата: 29.01.08 07:48
Оценка:
ЕМ>Я, честно говоря, так и не понял, чего ты хочешь достичь — практически, а не теоретически.

По-моему товарищ remark хочет использовать/повторить идею, которая реализована в windows и linux при подсчете статистики обращений к диску/тому.
Так, если посмотреть на реализацию FAT, то можно увидеть, что драйвер создает столько экземпляров FILE_SYSTEM_STATISTICS, сколько процессоров и во время работы заполняет их так:

#define CollectCreateHitStatistics(VCB) {                                                \
    PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()];   \
    Stats->Fat.CreateHits += 1;                                                          \
}

#define CollectCreateStatistics(VCB,STATUS) {                                            \
    PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()];   \
    if ((STATUS) == STATUS_SUCCESS) {                                                    \
        Stats->Fat.SuccessfulCreates += 1;                                               \
    } else {                                                                             \
        Stats->Fat.FailedCreates += 1;                                                   \
    }                                                                                    \
}


При запросе FSCTL_FILESYSTEM_GET_STATISTICS драйвер не делает никаких сложений, а просто копирует все структуры в выходной буффер, оставляя сложение нужных полей на откуп вызывающему коду.

Похожий подход и в linux (include/linux/genhd.h):
struct gendisk {
....
#ifdef    CONFIG_SMP
    struct disk_stats *dkstats;
#else
    struct disk_stats dkstats;
#endif
};

#ifdef    CONFIG_SMP
// Обновление статистики
#define disk_stat_add(gendiskp, field, addnd)            \
    do {                            \
        preempt_disable();                \
        // Макрос __disk_stat_add раскрыт               \
        per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd;\
        preempt_enable();                \
    } while (0)

// Чтение итоговой статистики, например для вывода в файл /sys/block/<dev>/stat
#define disk_stat_read(gendiskp, field)                    \
({                                    \
    typeof(gendiskp->dkstats->field) res = 0;            \
    int i;                                \
    for_each_possible_cpu(i)                    \
        res += per_cpu_ptr(gendiskp->dkstats, i)->field;    \
    res;                                \
})
#endif
Re[10]: GetCurrentProcessorNumber() под WinXP
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.01.08 08:18
Оценка:
Здравствуйте, MShura, Вы писали:

MS>идею, которая реализована в windows и linux при подсчете статистики обращений к диску/тому.

MS>Так, если посмотреть на реализацию FAT, то можно увидеть, что драйвер создает столько экземпляров FILE_SYSTEM_STATISTICS

Э-э-э... А какой-нибудь объективный смысл в таком подходе есть, или это сугубо произвольная фантазия разработчиков? О чем может говорить статистика обращений того или иного процессора к дискам, и какую практическую пользу можно из нее извлечь?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: GetCurrentProcessorNumber() под WinXP
От: Геннадий Майко США  
Дата: 29.01.08 08:36
Оценка:
Здравствуйте, MShura,

MS>По-моему товарищ remark хочет использовать/повторить идею, которая реализована в windows и linux при подсчете статистики обращений к диску/тому.


MS>[/ccode]

MS>#ifdef CONFIG_SMP
MS>// Обновление статистики
MS>#define disk_stat_add(gendiskp, field, addnd) \
MS> do { \
MS> preempt_disable(); \
MS> // Макрос __disk_stat_add раскрыт \
MS> per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd;\
MS> preempt_enable(); \
MS> } while (0)
MS>[/ccode]
--
Кстати, я не знаю, как там в Windows, но в linux использование идентификатора процессора делается достаточно корректно, так как на момент изменения переменной запрещается смена процессора.

C уважением,
Геннадий Майко.
Re[11]: GetCurrentProcessorNumber() под WinXP
От: MShura  
Дата: 29.01.08 09:22
Оценка:
MS>>идею, которая реализована в windows и linux при подсчете статистики обращений к диску/тому.
MS>>Так, если посмотреть на реализацию FAT, то можно увидеть, что драйвер создает столько экземпляров FILE_SYSTEM_STATISTICS

ЕМ>Э-э-э... А какой-нибудь объективный смысл в таком подходе есть, или это сугубо произвольная фантазия разработчиков? О чем может говорить статистика обращений того или иного процессора к дискам, и какую практическую пользу можно из нее извлечь?


Даже не могу сказать про практическую пользу знаний статистики по отдельным процессорам, к тому-же в конкретной файловой системе, но в сумме смысл уже есть.
Так в windows task manager может показывать статистику обращений к диску (не к тому).

В linux можно из этих знаний даже извлечь практическую пользу:
Так в файле /sys/block/<dev>/stat выводится следующая статистика по диску на текущий момент:

Name            units         description
----            -----         -----------
read I/Os       requests      number of read I/Os processed
read merges     requests      number of read I/Os merged with in-queue I/O
read sectors    sectors       number of sectors read
read ticks      milliseconds  total wait time for read requests
write I/Os      requests      number of write I/Os processed
write merges    requests      number of write I/Os merged with in-queue I/O
write sectors   sectors       number of sectors written
write ticks     milliseconds  total wait time for write requests
in_flight       requests      number of I/Os currently in flight
io_ticks        milliseconds  total time this block device has been active
time_in_queue   milliseconds  total wait time for all requests


Поскольку планировщик ввода-вывода (elevator) в linux можно менять на лету, а также менять его параметры, то можно быстро (без перегрузок) оценивать эффективность того или иного элеватора на конкретных файловых операциях или на том или ином сценарии действий или на том или ином носителе.
Справедливости ради стоит сказать, что я не увидел особой разницы в элеваторах deadline/noop/as в обычных условиях на embedded устройствах.
А проводить сложные эксперименты/измерения ради интереса было лень.
Re[11]: GetCurrentProcessorNumber() под WinXP
От: MShura  
Дата: 29.01.08 09:33
Оценка:
ГМ>Кстати, я не знаю, как там в Windows, но в linux использование идентификатора процессора делается достаточно корректно, так как на момент изменения переменной запрещается смена процессора.

Макросы CollectCreateHitStatistics/CollectCreateStatistics
вызываются внутри блока FsRtlEnterFileSystem/FsRtlExitFileSystem
Re[9]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 29.01.08 11:24
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, remark, Вы писали:


R>>Это значит, что функциональность, которая тебе требовалась, прямолинейнее той, которая требуется мне. Про то, что можно использовать идентификатор потока, я, естественно, в курсе. Про то, что его не всегда достаточно я писал здесь:

R>>http://gzip.rsdn.ru/forum/message/2806303.1.aspx
Автор: remark
Дата: 22.01.08


ЕМ>Я, честно говоря, так и не понял, чего ты хочешь достичь — практически, а не теоретически. Любопытства ради я прогнал твой пример на двухъядерном Athlon 64 X2, под виндами (линуха у меня нет). Создавал восемь потоков с привязкой к процессорам и без нее. Скомпилировано MS VS 2005 (VC 8), _InterlockedIncrement раскрывается в lock xadd. Ну и во втором случае _InterlockedIncrement будет избыточным, ибо конкуренции за переменную нет.


Во-втором случае _InterlockedIncrement *не* избыточный, т.к. номер процессора может измениться, это не более, чем хинт. По крайней мере в user-space. _InterlockedIncrement избыточный только в случае жёсткой привязки потоков к процессорам.


ЕМ>Получилось вот что (количество тактов на проход цикла):


ЕМ>1 с привязкой к процессорам — 56

ЕМ>1 без привязки — 57
ЕМ>2 с привязкой с _InterlockedIncrement — 12
ЕМ>2 без привязки с _InterlockedIncrement — 12
ЕМ>2 с привязкой с ++ — 5
ЕМ>2 без привязки с ++ — 6


ЕМ>То есть, наиболее эффективный вариант — привязывать потоки к процессорам. Если каждый поток занимается интенсивной вычислительной работой, то от привязки к разным процессорам они только выиграют. Если же загрузка неравномерная, то и вероятность конфликта за переменную падает многократно, а вероятность получения номера на одном процессоре и последующего переключения на другой, наоборот, возрастает. Так что обоснованность твоего стремления представляется весьма сомнительной.


Про то, что привязка не всегда возможно я уже писал и писал причины. Допустим ты делаешь библиотечный код. НУ НЕ МОЖЕШЬ ТЫ ПРИВЯЗЫВАТЬ ПОЛЬЗОВАТЕЛЬСКИЕ ПОТОКИ К ПРОЦЕССОРАМ. НЕ МОЖЕШЬ!!!

Учитывая 2, указанные мной причины, получаем:

ЕМ>1 без привязки — 57

ЕМ>2 без привязки с _InterlockedIncrement — 12

Я вижу, что эти 2 цифры различаются в 4,75 раза. Что отсюда не очевидно? И дело не только голой производительности, более серьёзно дело обстоит с масштабируемостью. Если провести более исчерпывающее тестирование, то ты можешь получить следующие цифры масштабируемости.

Умная, аккуратная синхронизация, уважающая кэш:
1 ядро — 1
2 ядра — 2
2 процессора — 2
2 процессора по 2 ядра — 4

Тупая синхронизация в лоб:
1 ядро — 1
2 ядра — 0.6
2 процессора — 0.4
2 процессора по 2 ядра — 0.2

Такие цифры я лицезрел неоднократно.
Попробуй потестировать, привязывая несколько потоков только к одному ядру, либо к обоим.


ЕМ>Если есть практические примеры, показывающие эффективность именно выбранного тобой подхода — буду рад посмотреть.


Конкретные алгоритмы я не могу сейчас раскрывать. Но множество примеров можно поглядеть в ядрах ОС, где "копия на процессора" используется достаточно часто. Это могут быть различные мьютексы, сбор статистики, техники типа RCU. Пару примеров привёл MShura.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[10]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 29.01.08 11:25
Оценка:
Здравствуйте, MShura, Вы писали:

ЕМ>>Я, честно говоря, так и не понял, чего ты хочешь достичь — практически, а не теоретически.


MS>По-моему товарищ remark хочет использовать/повторить идею, которая реализована в windows и linux при подсчете статистики обращений к диску/тому.



В частности и это можно повторить. Только в user-space всё равно надо использовать Interlocked операции.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[11]: GetCurrentProcessorNumber() под WinXP
От: remark Россия http://www.1024cores.net/
Дата: 29.01.08 11:28
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, MShura, Вы писали:


MS>>идею, которая реализована в windows и linux при подсчете статистики обращений к диску/тому.

MS>>Так, если посмотреть на реализацию FAT, то можно увидеть, что драйвер создает столько экземпляров FILE_SYSTEM_STATISTICS

ЕМ>Э-э-э... А какой-нибудь объективный смысл в таком подходе есть, или это сугубо произвольная фантазия разработчиков? О чем может говорить статистика обращений того или иного процессора к дискам, и какую практическую пользу можно из нее извлечь?



Я думаю, что используется статистика только после сложения. Раздельный подсчёт — это не более чем деталь реализации.
Практическая польза следующая — получить линейно масштабируемую систему, в отличие от линейно деградирующей системы. Для меня это достаточное условие.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[10]: GetCurrentProcessorNumber() под WinXP
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 29.01.08 11:48
Оценка:
Здравствуйте, remark, Вы писали:

R>Допустим ты делаешь библиотечный код. НУ НЕ МОЖЕШЬ ТЫ ПРИВЯЗЫВАТЬ ПОЛЬЗОВАТЕЛЬСКИЕ ПОТОКИ К ПРОЦЕССОРАМ. НЕ МОЖЕШЬ!!!


А если спокойно подумать? Что за библиотечный код, который, не зная о процессорах и потоках, тем не менее претендует на предельно высокое быстродействие? Это извращение, а не код. Либо библиотека сама создает потоки по определенной схеме, либо требует этого от кода, ее использующего. Либо, соответственно, ничего этого не делает, и на эффективность не претендует.

R>Я вижу, что эти 2 цифры различаются в 4,75 раза. Что отсюда не очевидно?


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

ЕМ>>Если есть практические примеры, показывающие эффективность именно выбранного тобой подхода — буду рад посмотреть.


R>Конкретные алгоритмы я не могу сейчас раскрывать.


Начинается... Каким бы новаторским и секретным ни был алгоритм — нет проблем его переиначить или с ходу придумать аналогию, годную для примера.

R> Но множество примеров можно поглядеть в ядрах ОС, где "копия на процессора" используется достаточно часто. Это могут быть различные мьютексы, сбор статистики, техники типа RCU. Пару примеров привёл MShura.


В ядрах ОС понятие "номер процессора" имеет вполне конкретное значение, в отличие от user-mode. Оттого и не возникало реальной необходимости в функции GetCurrentProcessorNumber.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.