[pthreads] у кого какие числа получаются и почему?

margadon

в аттаче - простая программа под linux/g++ которая заполняет большой глобальный массив, потом в несколько потоков без блокировок по нему бегает и считает какую-то арифметическую ерунду.
компилил её вот так:
g++ -O3 -lpthread -oth
у меня на двухпроцессорном сервере (2 ксеона, 4 ядра, три стабильно свободны) выдаёт
./th 1
threads: 1
[1082132800] result = -1963181146, time= 22.1900
./th 2
threads: 2
[1082132800] result = -1963181146, time= 51.6700
[1090525504] result = -1963181146, time= 52.6300
./th 4
threads: 4
[1082132800] result = -1963181146, time= 88.2000
[1098918208] result = -1963181146, time= 117.3100
[1107310912] result = -1963181146, time= 130.3400
[1090525504] result = -1963181146, time= 131.8100
будто не параллельно выполняются потоки, а последовательно...
кто-нибудь может это объяснить?! :o
а у вас какие числа получаются?
прога вот:

procenkotanya

Пропускная способность памяти одна на всех.

sergeikozyr

Получаются примерно такие же цифры:
 
lol:~/papko$ ./th 1
threads: 1
[1109244240] result = -1963181146, time= 13.0400
lol:~/papko$ ./th 2
threads: 2
[1113573712] result = -1963181146, time= 29.9200
[1105181008] result = -1963181146, time= 29.9200
lol:~/papko$ ./th 4
threads: 4
[1123293520] result = -1963181146, time= 74.4600
[1104308560] result = -1963181146, time= 74.4000
[1131686224] result = -1963181146, time= 79.9700
[1114900816] result = -1963181146, time= 79.9900

правильно объяснил почему

dgaf

нет, не похоже
проверил на 4 dualcore opterons - у каждого камня свой контроллер памяти и свои банки.
---
блин, они же все один кусок памяти используют
---
msc060 ~ $ ./th 1
threads: 1
[1096280432] result = -1963181146, time= 30.8300
msc060 ~ $ ./th 2
threads: 2
[1103305072] result = -1963181146, time= 59.5300
[1094912368] result = -1963181146, time= 61.5700
msc060 ~ $ ./th 4
threads: 4
[1135204720] result = -1963181146, time= 130.9600
[1118419312] result = -1963181146, time= 154.7300
[1110026608] result = -1963181146, time= 157.2200
[1126812016] result = -1963181146, time= 160.1500
msc060 ~ $ ./th 8
threads: 8
[1146141040] result = -1963181146, time= 459.2400
[1112570224] result = -1963181146, time= 468.4400
[1095784816] result = -1963181146, time= 496.7900
[1129355632] result = -1963181146, time= 498.6500
[1104177520] result = -1963181146, time= 517.0300
[1087392112] result = -1963181146, time= 524.2600
[1137748336] result = -1963181146, time= 524.7600
[1120962928] result = -1963181146, time= 514.3800
интересный переход от 4 к 8
кстати, а планировщик действительно рюхает (2.6.26):

CPU states: cpu user nice system irq softirq iowait idle
total 48.5% 0.0% 0.4% 0.0% 0.1% 0.0% 50.9%
cpu00 0.0% 0.0% 0.0% 0.0% 0.8% 0.0% 99.1%
cpu01 100.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0%
cpu02 100.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0%
cpu03 0.9% 0.0% 2.7% 0.0% 0.0% 0.0% 96.3%
cpu04 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 100.0%
cpu05 100.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0%
cpu06 0.0% 0.0% 0.9% 0.0% 0.0% 0.0% 99.0%
cpu07 100.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0%

по одному процессу на один контроллер памяти.

margadon

охх, спасибо всем, мне это конечно совсем не нравится, но придётся смириться...

sergeikozyr

Похоже, очень похоже. Смотри не абсолютные цифры (у меня быстрая десктопная память а коэффициент снижения скорости работы. Как и следовало ожидать, хорошо оптимизированный встроенный контроллер памяти оптеронов зарулил и вплоть до 4 тредов показатели ухудшения у оптеронов существенно ниже.

dgaf

я как раз исправился - раз все треды используют один кусок памяти (который принадлежит одному процессору то всё равно всё упирается в одну шину.

onairika

Вообщето тут неплохо бы было приводить ещё и ассемблер ф-ции th_func, так как достаточно разумный компилятор мог бы все три цикла по i объединить в один, и в цикле по k осталось бы всего одно обращение на каждое i, а не три.

pitrik2

прога вот:
у мя не запускается :(
edit: тьфу, там параемтр запуска нада, гадство что она не сообщает об этом :(
мой результ:

threads: 1
[2] result = -1963181146, time= 31.1600

threads: 2
[3] result = -1963181146, time= 62.7800
[2] result = -1963181146, time= 65.8700

threads: 4
[5] result = -1963181146, time= 158.1000
[3] result = -1963181146, time= 171.2900
[4] result = -1963181146, time= 173.8000
[2] result = -1963181146, time= 176.3300

threads: 8
[5] result = -1963181146, time= 620.4200
[9] result = -1963181146, time= 625.8600
[8] result = -1963181146, time= 646.7900
[3] result = -1963181146, time= 647.8800
[2] result = -1963181146, time= 678.8100
[6] result = -1963181146, time= 679.8500
[7] result = -1963181146, time= 683.5900
[4] result = -1963181146, time= 684.0400

slonishka

патч :grin:
--- th.cpp      2008-11-26 19:35:37.000000000 +0300
+++ th.cpp 2008-11-27 10:37:33.921256509 +0300
@@ -52,6 +52,12 @@

int main(int argc, char * argv[])
{
+ if (2 > argc)
+ {
+ printf("Usage: %s threads_num\n", argv[0]);
+ return -1;
+ }
+
int threads_num = atoi(argv[1]);
printf("threads: %d\n", threads_num);

pitrik2

работает :)

> patch -i th.patch th.cpp
Looks like a unified context diff.
done

> g++ -O3 -lpthread th.cpp

> ./a.out
Usage: ./a.out threads_num

margadon

lol
если вместо ::clock использовать ::gettimeofday числа совсеееем другие получаются...

Werdna

если вместо ::clock использовать ::gettimeofday числа совсеееем другие получаются...
Да, смешно получилось. Ситуация, когда секундомер в руках будет показывать другие цифры.
 
NAME
clock - Determine processor time

SYNOPSIS
#include <time.h>

clock_t clock(void);

DESCRIPTION
The clock function returns an approximation of [b]processor time[/b] used by the program.

Готова задачка на собеседование. ;)

slonishka

имхо это ебанатство такие вещи на собеседовании спрашивать. =)
(ну т.е. если комп с юникс-окружением дать на решение, то нормально).
просто прежде чем использовать вызов, нужно ман-страницу по нему прочитать.
я вот вчера поленился, так бы может даже в форум не написали, если бы двумя головами его распарсили.
и есть шанс, что мы (ты? ? я?) еще чего-то очень важного не понимаем.

slonishka

еще мне кажется не совсем логичным то, что с одной стороны pthread_attr_getscope в линуксах
возвращает PTHREAD_SCOPE_SYSTEM, а с другой стороны clock-и считаются per-process.
хотя да, из этого можно сделать вывод о совместимости clock и мультитредности, наверное.

Werdna

я вот вчера поленился, так бы может даже в форум не написали, если бы двумя головами его распарсили.
Так дело-то в лени как раз на самом очевидном месте. :)
Назовись эта функция «clock_t dfghjkluytr», полезли бы в ман, а в очевидном варианте каждый считает себя знатоком АПИ. ;)

sergeikozyr

Ты время меряешь clock-ом? Он же некорректно работает в многотредовом окружении. Исправляй на times (man times).

margadon

угу, теперь знаю :)
хотя в списке откровенно немультитредных функций (вроде strerror) её не встречал, потому и думал что всё окей
не лазить же в man за каждым вызовом printf?
нынче меряю разницей в вызовах gettimeofday до и после

pitrik2

если вместо ::clock использовать ::gettimeofday числа совсеееем другие получаются...
вот что получается

threads: 1
[2] result = -1963181146, time= 30387

threads: 2
[2] result = -1963181146, time= 35663
[3] result = -1963181146, time= 38828

threads: 4
[2] result = -1963181146, time= 45166
[5] result = -1963181146, time= 45411
[3] result = -1963181146, time= 46488
[4] result = -1963181146, time= 49524

threads: 8
[6] result = -1963181146, time= 64003
[8] result = -1963181146, time= 81388
[3] result = -1963181146, time= 82175
[9] result = -1963181146, time= 85411
[4] result = -1963181146, time= 85963
[5] result = -1963181146, time= 92912
[7] result = -1963181146, time= 93286
[2] result = -1963181146, time= 96867

вставил там вместо клока

< clock_t beg = clock;
---
> struct timeval tv;
> gettimeofday(&tv, NULL);
> long beg = (tv.tv_sec*1000) + (tv.tv_usec / 1000);

< beg = clock - beg;
---
> long end = (tv.tv_sec*1000) + (tv.tv_usec / 1000);
> beg = end - beg;
> // beg = clock - beg;

< printf("[%d] result = %d, time= %.4f\n", (int)pthread_self result, beg/(double)1000000);
---
> printf("[%d] result = %d, time= %ld\n", (int)pthread_self result, beg);

т.е. вывод стал в миллисекундах
P.S.
для 8 запускал попозже, там тачка занята была, поэтому так медленно и неоднозначно вышло

> psrinfo -v
Status of virtual processor 0 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:13.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Status of virtual processor 1 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:16.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Status of virtual processor 2 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:18.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Status of virtual processor 3 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:20.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Status of virtual processor 4 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:22.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Status of virtual processor 5 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:24.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Status of virtual processor 6 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:26.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Status of virtual processor 7 as of: 11/27/2008 14:06:09
on-line since 11/24/2007 11:31:28.
The i386 processor operates at 2600 MHz,
and has an i387 compatible floating point processor.
Оставить комментарий
Имя или ник:
Комментарий: