Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.73/26: Рейтинг темы: голосов - 26, средняя оценка - 4.73
0 / 0 / 0
Регистрация: 19.02.2019
Сообщений: 5

Распараллеливание с помщью потоков. Время работы

19.02.2019, 14:32. Показов 5541. Ответов 23
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!

Написал программу, которая должна распараллеливать умножение матриц

https://www.cyberforum.ru/cgi-bin/latex.cgi?<br />
A=\{a_{ik}\} \in M(m\times n), B= \{b_{kj}\} \in M(n \times l)<br />

(код программы ниже).

Распараллеливал по i формулу:

https://www.cyberforum.ru/cgi-bin/latex.cgi?<br />
c_{ij} = \sum_{k=1}^n a_{ik}b_{kj}, \quad i = 1,2, \ldots m, \quad j = 1,2,\ldots,l.<br />

Тестировал на матрицах размера 2000 x 2000, 2000 x 2000 на машине с 4-мя процессорами.
Запускал с 2, 3, 4 потоками.

Вопрос: Почему программа работает медленнее, чем последовательный вариант?
Причем чем больше потоков, тем медленнее.


Использовать одну память для чтения несколькими потоками нельзя?


C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<time.h>
 
 
 
typedef struct Thread_Data {
    pthread_t id; 
    double ** a;
    double ** b;
    double ** c;
    int from; 
    int to;
    int col2; 
    int row2;
} Thread_Data;
void * Thread_Function(void * arg) {
    int i, j, k;
    Thread_Data * data = (Thread_Data *) arg;
    for(i = data -> from; i < data -> to; i++) {
        for(j = 0; j < data -> col2; j++) {
            data -> c[i][j] = 0.0;
            for(k = 0; k < data -> row2; k++)
                data -> c[i][j] += data -> a[i][k] * data -> b[k][j];
        }
    }
    return NULL;
}
void mult_mat (int thread_count, double ** mat1, double ** mat2, double ** res, int r1, int r2, int c2) {
    int s  = r1 / thread_count;
    int i;
    Thread_Data * data;
    data = (Thread_Data *) malloc(thread_count * sizeof(Thread_Data));
    for(i = 0; i < thread_count - 1; i++) {
        data[i].a = mat1;
        data[i].b = mat2;
        data[i].c = res;
        data[i].from = i * s;
        data[i].to = (i + 1) * s;
        data[i].col2 = c2;
        data[i].row2 = r2;
        pthread_create(&(data[i].id), NULL, Thread_Function, &(data[i]));
    }
    data[thread_count - 1].a = mat1;
    data[thread_count - 1].b = mat2;
    data[thread_count - 1].c = res;
    data[thread_count - 1].from = (thread_count - 1) * s;
    data[thread_count - 1].to = r1;
    data[thread_count - 1].col2 =c2;
    data[thread_count - 1].row2 = r2;
 
    pthread_create(&(data[thread_count - 1].id), NULL, Thread_Function, &(data[thread_count - 1]));
 
    for( i = 0; i < thread_count; i++)
        pthread_join(data[i].id, NULL);
}
int main(int argc, char* argv[]) {
    double **a, **b, **c;
    int m, n, k, i, j, nproc;
    unsigned start_time, end_time, time;
    FILE *fin, *fout;
    fin = fopen("input.txt", "r");
    fscanf(fin, "%d %d%d", &m, &n, &k);
    a  = (double **)malloc(m * sizeof(double *));
    for(i = 0; i < m; i++)
        a[i] = (double *) malloc(n * sizeof(double));
    b  = (double **)malloc(n * sizeof(double *));
    for(i = 0; i < n; i++)
        b[i] = (double *) malloc(k * sizeof(double));
    c  = (double **)malloc(m * sizeof(double *));
    for(i = 0; i < m; i++)
        c[i] = (double *) malloc(k * sizeof(double));
    printf("Ok \n");
    for(i= 0; i< m; i++) {
        for(j = 0; j < n; j++)
            fscanf(fin, "%lf", &a[i][j]);
    }
    for(i= 0; i< n; i++) {
        for(j = 0; j < k; j++)
            fscanf(fin, "%lf", &b[i][j]);
    }
    start_time = clock();
    nproc = atoi(argv[1]);
    mult_mat(nproc, a, b, c, m, n, k);
    fout = fopen("output.txt", "w");
    for(i = 0; i < m; i++) {
        for(j = 0; j < k; j++)
            fprintf(fout, "%lf ", c[i][j]);
        fprintf(fout, "\n");
    }
    end_time = clock();
    printf("time = %lf \n", (end_time - start_time) * 1.0 / CLOCKS_PER_SEC);
    return 0;
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
19.02.2019, 14:32
Ответы с готовыми решениями:

Сложить матрицы с помощью потоков и узнать время работы
Добрый вечер дорогие форумчане. Такая задача: сложить матрицы с помощью потоков и узнать время работы. Я могу это сделать через Thread в...

Распараллеливание потоков для нахождения суммы матрицы <omp.h>
Доброго дня. Сегодня слушал занимательную лекцию об распараллеливание потоков и получил задание: есть матрица 10,10 инициализированная...

Используя распараллеливание потоков найти количество цифр, входящих в заданную строку
Используя распараллеливания потоков найти количество цифр, входящих в заданную строку. Я говорил с преподавателем он сказал разбить строку...

23
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
20.02.2019, 08:32
Цитата Сообщение от prime2019 Посмотреть сообщение
Вопрос: Почему программа работает медленнее, чем последовательный вариант?
Причем чем больше потоков, тем медленнее.
Вы выбрали не ту ф-цию для подсчета времени. clock() = процессорное время программы. Пусть в один поток задача работает 100 условных единиц времени. Разбив ее на N частей, мы получим те же 100 единиц процессорного времени N * ( 100 / N) + не нулевые накладные расходы на поддержку нитей.
Возьмите например clock_gettime(CLOCK_MONOTONIC, )
2
0 / 0 / 0
Регистрация: 19.02.2019
Сообщений: 5
20.02.2019, 12:50  [ТС]
Цитата Сообщение от prik Посмотреть сообщение
Вы выбрали не ту ф-цию для подсчета времени. clock() = процессорное время программы. Пусть в один поток задача работает 100 условных единиц времени. Разбив ее на N частей, мы получим те же 100 единиц процессорного времени N * ( 100 / N) + не нулевые накладные расходы на поддержку нитей.
Возьмите например clock_gettime(CLOCK_MONOTONIC, )
Спасибо за ответ! Обязательно рассмотрю указанную функцию.

Возникает несколько вопросов. Прошу прощения, если скажу глупость.

Суть распараллеливания - это ведь ускорение
времени выполнения программы.
В моем понимании функция clock() отражает время выполнения основной части программы.
Разве это не так?

В моем примере даже визуально выполнение параллельной программы
проходит дольше чем последовательной (если смотреть за терминалом после запуска программы).

Неужели на таком примере (умножение матриц) нельзя
увидеть эффект распараллеливания? (ускорение времени)

Или нужны входные данные побольше (матрицы) и побольше количество процессоров?
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
20.02.2019, 13:54
Цитата Сообщение от prime2019 Посмотреть сообщение
Суть распараллеливания - это ведь ускорение
времени выполнения программы.
В данном случае, да.
Цитата Сообщение от prime2019 Посмотреть сообщение
моем понимании функция clock() отражает время выполнения основной части программы.
Нет. Я наверное плохо написал... Это число тиков ОС в течении которых ваша программа, включая _все_ ее нити кушала процессор. Если в один поток задача была решена за 100 тиков, то разбив ее на 4 подзадачи путем ограничения объема обрабатываемых каждой частью данных мы получим 25*4 = те же 100 тиков. Т.е. замеряется совсем не та величина.
Цитата Сообщение от prime2019 Посмотреть сообщение
В моем примере даже визуально выполнение параллельной программы
проходит дольше чем последовательной (если смотреть за терминалом после запуска программы).
Если ядра настоящие, то странно. Предлагаю все-таки промерять время Ответы у одно/много поточных решений совпадают?
Цитата Сообщение от prime2019 Посмотреть сообщение
Или нужны входные данные побольше (матрицы) и побольше количество процессоров?
Нет.
1
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
20.02.2019, 23:34
Цитата Сообщение от prime2019 Посмотреть сообщение
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void mult_mat (int thread_count, ...) {
/*****/
  Thread_Data * data;
  data = (Thread_Data *) malloc(thread_count * sizeof(Thread_Data));
  for(i = 0; i < thread_count - 1; i++) {
     /********/
     pthread_create(&(data[i].id), NULL, Thread_Function, &(data[i]));
  }
  /*******/
 
  pthread_create(&(data[thread_count - 1].id), NULL, Thread_Function, &(data[thread_count - 1]));
 
  for( i = 0; i < thread_count; i++)
      pthread_join(data[i].id, NULL);
}
В цикле насоздавали потоков. Затем ещё один без цикла. И после этого в следующем цикле начинаем ждать завершения потока[i], но man pthread_join() нам говорит: "Функция pthread_join() блокирует вызывающий поток, пока указанный поток не завершится."
Может в этом причина?
Попробуй pthread_tryjoin_np() или синхронизироваться через семафоры...

З.Ы. но мне кажется - дело в "лёгкости" задачи для потока. Сколько там получается - 4 млн умножений и при этом данные, наполовину в кеше 3лвл? Кроме того как компиируешь? попробуй указать gcc -O0 (отрубить все оптимизации)

З.З.Ы Как получить доступ к input.txt? - могу поэкспериментировать...
1
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
21.02.2019, 08:08
Цитата Сообщение от drfaust Посмотреть сообщение
Может в этом причина?
Попробуй pthread_tryjoin_np() или синхронизироваться через семафоры...
Ересь какая-то
Цитата Сообщение от drfaust Посмотреть сообщение
Сколько там получается - 4 млн умножений
Чуть больше 8000 млн.
Цитата Сообщение от drfaust Посмотреть сообщение
могу поэкспериментировать...
Можете просто выкинуть чтение из файла, пусть мусор перемножает. m=n=k=2000
0
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
21.02.2019, 08:33
Цитата Сообщение от prik Посмотреть сообщение
Можете просто выкинуть чтение из файла, пусть мусор перемножает.
Чтение из файла не считается clock`ом. Хотя первый запуск, пока файло ещё не в кеше будет "визуально тормозить".
Цитата Сообщение от prik Посмотреть сообщение
Ересь какая-то
Цитата Сообщение от drfaust Посмотреть сообщение
Может в этом причина?
В качестве эксперимента...

Вообще хотелось бы проверить у себя утверждение
Цитата Сообщение от prime2019 Посмотреть сообщение
Почему программа работает медленнее, чем последовательный вариант?
но лень ваять входной файлик/заполнять "рандомом". Лучше конечно проверять именно на его файлике и исходной_проге, не вмешиваясь.
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
21.02.2019, 08:56
Цитата Сообщение от drfaust Посмотреть сообщение
Чтение из файла не считается clock`ом. Хотя первый запуск, пока файло ещё не в кеше будет "визуально тормозить".
На фоне времени вычислений эта задержка стремиться к нулю.
Цитата Сообщение от drfaust Посмотреть сообщение
В качестве эксперимента...
Просто, не понимаю чем спячка в pthread_join() может быть хуже ожидания на любом другом объекте синхронизации...
Цитата Сообщение от drfaust Посмотреть сообщение
но лень ваять входной файлик/заполнять "рандомом
Я потому и предложил вам, как готовому ставить эксперименты, выкинуть чтение полностью, заменив его на
C
1
m = n = k = 2000;
0
0 / 0 / 0
Регистрация: 19.02.2019
Сообщений: 5
21.02.2019, 10:04  [ТС]
Цитата Сообщение от prik Посмотреть сообщение
Если ядра настоящие, то странно. Предлагаю все-таки промерять время Ответы у одно/много поточных решений совпадают?Нет.
Вчера не было возможности написать.

Ответы у одно/много поточных решений совпадают.

По поводу ядер.
Я тестировал на двух машинах.

Одна может быть не в счет.
Там тестировал на гостевой Ubuntu в VirtualBox.
Для гостевой Ubuntu выделено 2 ядра из 4.
Хостовая Win10.


На второй машине стоят две системы (параллельно): Ubuntu и Win7.

Процессор там Intel(R) Core(TM) i3-2120 CPU @ 3.30 GHz
c 4-мя ядрами.

В терминале в Ubuntu ответ на команду nproc выдет 4.

Вот на второй машине запускал с 2,3,4 потоками.
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
21.02.2019, 10:33
Лучший ответ Сообщение было отмечено prime2019 как решение

Решение

Цитата Сообщение от prime2019 Посмотреть сообщение
Процессор там Intel(R) Core(TM) i3-2120 CPU @ 3.30 GHz
c 4-мя ядрами.
Тут 2 ядра, HT можно не считать. Но все равно, разница во времени должна быть.
таки поменяйте ваш xxx_time = clock(); на
C
1
2
3
4
5
6
7
8
9
10
11
12
struct timespec start_time, end_time, time;
 
clock_gettime(CLOCK_MONOTONIC, &start_time);
...
clock_gettime(CLOCK_MONOTONIC, &end_time);
time.tv_sec = end_time.tv_sec - start_time.tv_sec;
time.tv_nsec = end_time.tv_nsec - start_time.tv_nsec;
if (time.tv_nsec < 0) {
  time.tv_sec--;
  time.tv_nsec += 1000000000L;
}
printf("time = %lld.%ld \n", time.tv_sec, time.tv_nsec);
и приходите с результатами.
1
0 / 0 / 0
Регистрация: 19.02.2019
Сообщений: 5
21.02.2019, 12:17  [ТС]
Цитата Сообщение от drfaust Посмотреть сообщение
В цикле насоздавали потоков. Затем ещё один без цикла. И после этого в следующем цикле начинаем ждать завершения потока[i], но man pthread_join() нам говорит: "Функция pthread_join() блокирует вызывающий поток, пока указанный поток не завершится."
Может в этом причина?
Попробуй pthread_tryjoin_np() или синхронизироваться через семафоры...
Функция pthread_join() ведь нужна для того чтобы главный поток
дождался созданные им остальные потоки.

Во многих примерах (в частности, в примерах книги Богачева К.Ю. "Основы параллельного программирования")
есть вызов функции pthread_join().

Цитата Сообщение от drfaust Посмотреть сообщение
З.Ы. но мне кажется - дело в "лёгкости" задачи для потока. Сколько там получается - 4 млн умножений и при этом данные, наполовину в кеше 3лвл? Кроме того как компиируешь? попробуй указать gcc -O0 (отрубить все оптимизации)
Я компилирую gcc -o main -pthread mult_matrix.c.
Попробовал с ключом -o0, компилятор ругается, причем я таких слов не знаю.

Цитата Сообщение от drfaust Посмотреть сообщение
З.З.Ы Как получить доступ к input.txt? - могу поэкспериментировать...
Файл весит 72 Mb. Не загружается.
Заполнял рандомно.
Вот код программы, которая заполняла файл.

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
 
int main() {
    
    FILE * fp;
    int m, n, k;
    int i, j;
    double tmp;
    srand(time(NULL));
    fp = fopen("input.txt", "w");
    if(!fp)
        printf("Couldn't open the file \n");
    scanf("%d %d %d", &m, &n, &k);
    fprintf(fp, "%d %d %d \n", m, n, k);
    for(i = 0; i < m; i++) {
        for(j = 0; j < n; j++) {
            tmp = (rand() % 20) / 10000.0 ;
            fprintf(fp, "%lf ", tmp);
        }
        fprintf(fp, "\n");
    }
    for(i = 0; i < n; i++) {
        for(j = 0; j < k; j++) {
            tmp = (rand() % 20) / 10000.0 ;
            fprintf(fp, "%lf ", tmp);
        }
        fprintf(fp, "\n");
    }
    fclose(fp);
    return 0;
}
Добавлено через 1 час 19 минут
Цитата Сообщение от prik Посмотреть сообщение
Тут 2 ядра, HT можно не считать. Но все равно, разница во времени должна быть.
таки поменяйте ваш xxx_time = clock(); на
C
1
2
3
4
5
6
7
8
9
10
11
12
struct timespec start_time, end_time, time;
 
clock_gettime(CLOCK_MONOTONIC, &start_time);
...
clock_gettime(CLOCK_MONOTONIC, &end_time);
time.tv_sec = end_time.tv_sec - start_time.tv_sec;
time.tv_nsec = end_time.tv_nsec - start_time.tv_nsec;
if (time.tv_nsec < 0) {
  time.tv_sec--;
  time.tv_nsec += 1000000000L;
}
printf("time = %lld.%ld \n", time.tv_sec, time.tv_nsec);
и приходите с результатами.
Спасибо большое! Работает!

Запускал три раза оба варианта программы с Вашим кодом.

Время работы последовательной программы:

1) 94.127962015

2) 94.233204728

3) 94.10741871


Время работы параллельной программы:

1) 49.317953911

2) 49.14839388

3) 49.404053058

Параллельную программу запускал на двух потоках.

Буду разбираться с функциями clock() и clock_gettime() и распараллеливанием в целом.

Да, кстати что такое НТ из вашего сообщения?
Цитата Сообщение от prik Посмотреть сообщение
Тут 2 ядра, HT можно не считать.
Напоследок пара вопросов по обучению распараллеливанию потоками:

1) Что читать? Что слушать, смотреть?

2) Какие задачи полезны для освоения распараллеливания?
0
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
21.02.2019, 12:46
Цитата Сообщение от prime2019 Посмотреть сообщение
-o0
-O0 это O английское большое, затем ноль. По дефолту gcc компилит с -O2.

Цитата Сообщение от prime2019 Посмотреть сообщение
Заполнял рандомно.
Вот код программы, которая заполняла файл.
Будет время поэкспериментирую...

Цитата Сообщение от prime2019 Посмотреть сообщение
Да, кстати что такое НТ из вашего сообщения?
Технология HyperThreading от Intel`а. Позволяет на одном ядре выполнять "параллельно" два потока, т.к. есть несколько конвейеров(u и v, если не изменяет склероз) внутри ядра. Даёт прирост до 30%
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
21.02.2019, 13:04
Лучший ответ Сообщение было отмечено prime2019 как решение

Решение

Цитата Сообщение от drfaust Посмотреть сообщение
По дефолту gcc компилит с -O2.
Я бы наоборот с -O3 собрал, думаю %40-%50 для этого кода даст.
Цитата Сообщение от prime2019 Посмотреть сообщение
Да, кстати что такое НТ из вашего сообщения?
Выше уже ответили. Можно добавить, что на некоторых задачах вместо роста можно получить и тормоза.
Цитата Сообщение от prime2019 Посмотреть сообщение
Напоследок пара вопросов по обучению распараллеливанию потоками:
Книжек не знаю. По моему достаточно посмотреть на pthread.h и никогда, не при каких обстоятельствах не строить предположений о порядке выполнения параллельного кода.
0
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
21.02.2019, 19:16
Лучший ответ Сообщение было отмечено prime2019 как решение

Решение

Цитата Сообщение от prik Посмотреть сообщение
и никогда, не при каких обстоятельствах не строить предположений о порядке выполнения параллельного кода.
А так же всегда думать о том, что несколько потоков могут лезть к одним и тем же данным, если чтение - ладно, а если кто-то ещё и писать будет, то всё... без синхронизации получится бред.

Добавлено через 5 часов 48 минут
Цитата Сообщение от prik Посмотреть сообщение
Вы выбрали не ту ф-цию для подсчета времени. clock() = процессорное время программы. Пусть в один поток задача работает 100 условных единиц времени. Разбив ее на N частей, мы получим те же 100 единиц процессорного времени
Да, прогнав прогу через time я сразу обратил внимание на некоторые цифры. А когда залез в "man 3 clock" и на opennet, то увидел подтверждение своим подозрениям:

man 3 орёт "Функция clock() возвращает приблизительное процессорное время, использованное программой." (archlinux почти ежедневнообновляемый) - совсем не очевидно, что считается суммарное процессорное время.

opennet намного короче, но сразу даёт понять о чём идёт речь: "Функция clock() возвращает суммарное процессорное время, использованное программой. " тут уже всё понятно...
Мои результат с использованием clock():
Bash
1
2
3
4
5
6
7
8
9
10
11
12
faust@archlinux par]$ time -p ./a.out 4
Ok 
time = 181.489280 
real 49,05
user 183,29
sys 0,15
[faust@archlinux par]$ time -p ./a.out 1
Ok 
time = 181.134845 
real 183,93
user 183,01
sys 0,12
Добавлено через 8 минут
Выше я компилил с -O0 , сейчас решил посмотреть что будет с 03:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
[faust@archlinux par]$ gcc -O3 par.c -lpthread
[faust@archlinux par]$ time -p ./a.out 4                                                                                
Ok                                                                                                                                     
time = 106.692476 
real 30,38
user 108,50
sys 0,18
[faust@archlinux par]$ time -p ./a.out 1
Ok 
time = 106.369144 
real 109,38
user 108,07
sys 0,23
Впечатляет, от 60% до 80% скорости

Добавлено через 10 минут
Интересно, оказывается и -Og работает, я думал это аналог -O0 - ан-нет:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
faust@archlinux par]$ gcc -Og par.c -lpthread
[faust@archlinux par]$ time -p ./a.out 1
Ok 
time = 144.695144 
real 147,47
user 146,53
sys 0,17
[faust@archlinux par]$ time -p ./a.out 4
Ok 
time = 142.832517 
real 40,87
user 144,55
sys 0,25
[faust@archlinux par]$
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
21.02.2019, 19:30
Цитата Сообщение от drfaust Посмотреть сообщение
Впечатляет, от 60% до 80% скорости
На -O2 циклы не раскрываются. А тут все нагрузка в
C
1
2
3
4
5
6
7
    for(i = data -> from; i < data -> to; i++) {
        for(j = 0; j < data -> col2; j++) {
            data -> c[i][j] = 0.0;
            for(k = 0; k < data -> row2; k++)
                data -> c[i][j] += data -> a[i][k] * data -> b[k][j];
        }
    }
1
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
21.02.2019, 19:37
Мне больше непонятно с -Og "включает все оптимизации, которые не мешают отладке".
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
21.02.2019, 19:45
drfaust, -Og это O[1] без
Цитата Сообщение от drfaust Посмотреть сообщение
которые не мешают отладке".
0
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
21.02.2019, 20:00
Цитата Сообщение от prik Посмотреть сообщение
Og это O[1] без
Теперь понятно - просто альяс...

Вот сделал по рекомендации prik, через clock_gettime() - теперь можно отказаться от time и видеть действительное время работы:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[faust@archlinux par]$ gcc -O3 par.c -lpthread
[faust@archlinux par]$ time -p ./a.out 1
Ok 
time = 105.250617792 
real 109,28
user 108,25
sys 0,18
[faust@archlinux par]$ time -p ./a.out 4
Ok 
time = 26.697527828 
real 30,50
user 109,54
sys 0,18
[faust@archlinux par]$ gcc -O0 par.c -lpthread
[faust@archlinux par]$ time -p ./a.out 1
Ok 
time = 181.4380876 
real 184,96
user 183,93
sys 0,13
time учитывает ещё и файловый ввод/вывод. Заметил, что у ТС отсчёт времени (через clock) после выполнения происходит после выхлопа в файл, что нарушает точность измерений - исправил.

Сейчас погоняю на разном кол-ве потоков и посмотрю что будет. Оптимизации только -O3, исходный текст с clock_gettime в качестве образца, переделывать не буду(хотя там, если полопатить....)
0
725 / 224 / 73
Регистрация: 01.03.2011
Сообщений: 643
21.02.2019, 20:38
Цитата Сообщение от drfaust Посмотреть сообщение
Сейчас погоняю на разном кол-ве потоков и посмотрю что будет
Если не лень:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int main(int argc, char* argv[]) {
    double **a, **b, **c;
    int m, n, k, i, j, nproc, x;
    struct timespec start_time, end_time, time;
    FILE *fin;
 
    if (argc != 2)
        return 1;
    fin = fopen("input.txt", "r");
    fscanf(fin, "%d %d%d", &m, &n, &k);
    a  = (double **)malloc(m * sizeof(double *));
    for(i = 0; i < m; i++)
        a[i] = (double *) malloc(n * sizeof(double));
    b  = (double **)malloc(n * sizeof(double *));
    for(i = 0; i < n; i++)
        b[i] = (double *) malloc(k * sizeof(double));
    c  = (double **)malloc(m * sizeof(double *));
    for(i = 0; i < m; i++)
        c[i] = (double *) malloc(k * sizeof(double));
    //printf("Ok \n");
    for(i= 0; i< m; i++) {
        for(j = 0; j < n; j++)
            fscanf(fin, "%lf", &a[i][j]);
    }
    for(i= 0; i< n; i++) {
        for(j = 0; j < k; j++)
            fscanf(fin, "%lf", &b[i][j]);
    }
    nproc = atoi(argv[1]);
    for (x = nproc; x > 0; x--) {
        clock_gettime(CLOCK_MONOTONIC_RAW, &start_time);
        mult_mat(x, a, b, c, m, n, k);
        clock_gettime(CLOCK_MONOTONIC_RAW, &end_time);
        timespecsub(&end_time, &start_time, &time);
        printf("%dx%d * %dx%d, %d threads: %lld.%ld \n", m, n, n, k, x, time.tv_sec, time.tv_nsec);
    }
    return 0;
}
Прогоняет тест в цикле с числом потоков от argv[1] до 1, не создает output.txt, если запущен ntpd - не влияет на время (линуксизм)
0
599 / 421 / 137
Регистрация: 02.10.2008
Сообщений: 1,798
Записей в блоге: 1
21.02.2019, 21:08
Ну вот, то чего и ожидал ТС. У меня 4 ядерный феном (никаких HT), на 5 потоках - я полазил в гуглохроме, и потому сбил показания... Оверхед от операционки(еа переключение процессов) в данном случае минимален:
Кликните здесь для просмотра всего текста
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
[faust@archlinux par]$ ./a.out 1 && ./a.out 1 && ./a.out 1
Ok 
time = 179.884671625 
Ok 
time = 180.211107125 
Ok 
time = 180.478086379 
[faust@archlinux par]$ ./a.out 2 && ./a.out 2 && ./a.out 2
Ok 
time = 90.122336334 
Ok 
time = 90.107070148 
Ok 
time = 90.37819941 
[faust@archlinux par]$ ./a.out 3 && ./a.out 3 && ./a.out 3
Ok 
time = 60.282967531 
Ok 
time = 60.283562032 
Ok 
time = 60.307121332 
[faust@archlinux par]$ ./a.out 4 && ./a.out 4 && ./a.out 4
Ok 
time = 45.513118739 
Ok 
time = 45.337107981 
Ok 
time = 45.127946900 
[faust@archlinux par]$ ./a.out 5 && ./a.out 5 && ./a.out 5
Ok 
time = 46.966589466 
Ok 
time = 45.937451430 
Ok 
time = 46.721443653 
[faust@archlinux par]$ ./a.out 6 && ./a.out 6 && ./a.out 6
Ok 
time = 48.661131606 
Ok 
time = 49.571588977 
Ok 
time = 48.592256834 
[faust@archlinux par]$ ./a.out 7 && ./a.out 8 && ./a.out 9
Ok 
time = 44.885776785 
Ok 
time = 39.259477979 
Ok 
time = 44.622543398 
[faust@archlinux par]$ ./a.out 10 && ./a.out 10 && ./a.out 10
Ok 
time = 45.644115020 
Ok 
time = 45.962891134 
Ok 
time = 45.543576141 
[faust@archlinux par]$


Добавлено через 27 минут
Предупреждение: неявная декларация функции «timespecsub»;
В каком стандарте/версии gcc собираешь? Откуда этот макрос взялся?
#include <sys/time.h>
(See libbsd(7) for include usage.)
Откуда он взялся?

Добавлено через 55 секунд
Bash
1
2
3
[faust@archlinux par]$ gcc -O3 par1.c -lpthread -lbsd -o 1
par1.c: В функции «main»:
par1.c:93:9: предупреждение: неявная декларация функции «timespecsub»;
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
21.02.2019, 21:08
Помогаю со студенческими работами здесь

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

Распараллеливание работы между ядрами.
Кто знает подскажите пожалуйсто. Есть программа на java, с использованием потоков. И есть компьютер 2-х, 4-х ядерный. Меня интересует...

Разделить время выполнения потоков
Я только начал изучать потоки, так что возможно это нубский вопрос, но как организовать чтобы если работает только один поток, то весь...

Посчитать время события - время работы кассиров (система массового обслуживания)
Есть программа, моделирующая следующую задачу (система массового обслуживания): В бухгалтерии предприятия имеются два кассира, каждый...

Выводить текущее время в определенные позиции консоли во время работы
Портирую консольное приложение. Есть код, который работал после компиляции в BC++ 3.1, после компиляции под MinGW GCC программа не...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru