Форум программистов, компьютерный форум CyberForum.ru

Производительность CPU, КЕШ, многопоточность - C++

Восстановить пароль Регистрация
 
Alex__Ch
0 / 0 / 0
Регистрация: 11.04.2012
Сообщений: 3
05.09.2012, 16:26     Производительность CPU, КЕШ, многопоточность #1
Доброго времени суток!
Суть проблемы - есть курсовой по системному программированию но я не знаю с чего и начать (

Тема: Исследование производительности ЦПУ при изменении размеров рабочих структур данных приложения и объема КЕШ памяти при чтении и записи.

Все написанное выше нужно рассматривать в контексте многоядерности и многопоточности. Как понял я, есть несколько потоков они чего-то пишут, что-то читают при этом критерий оценки производительности ЦПУ - время.

Мне неясно как должно выглядеть приложение и как показать наглядно взаимодействие процессов. Если говорить о многопоточности то должна быть ОС (Windows, Linux, etc.) ? И есть ли доступ в КЕШ в этих ОС или же писать свой драйвер?

Буду рад любым идеям и предложениям.
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.09.2012, 16:26     Производительность CPU, КЕШ, многопоточность
Посмотрите здесь:

C++ Производительность
Кеш процессора C++
Вопрос про многопоточность и производительность C++
C++ Многопоточность
C++ Многопоточность
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
05.09.2012, 18:21     Производительность CPU, КЕШ, многопоточность #2
Когда-то на работе занимался исследование префетча. Была написана такая программа - перемножение 3х мерных массивов, размером ~1000000 элементов. В коммандной строке можно задать кол-во потоков (потоки поровну делят между собой перемножаемые массивы), размер блока (размер, после перемножения которого, нужно производить следующий префетч) и вроде что-то еще, не помню.
Программа замеряет время, потраченное на перемножение всех элементов. Таким образом в программе присутствует:
- работа с потоками
- работа с кэшем
- замер производительности (времени)

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


Цитата Сообщение от Alex__Ch Посмотреть сообщение
при изменении размеров ... объема КЕШ памяти
так говорить не правильно, т.к. размер кэша зависит от процессора. Наверное имеется ввиду размер используемого кэша, на это как раз влияют потоки. Если они используют данные, которые находятся далеко друг от друга в памяти, то для каждого потока будет выполнена загрузка данных в кэш.

Цитата Сообщение от Alex__Ch Посмотреть сообщение
И есть ли доступ в КЕШ в этих ОС или же писать свой драйвер?
Есть, но это компиляторо-зависимые функции. Точно знаю, что есть в компиляторе gcc и Intel'овском компиляторе С++.
Alex__Ch
0 / 0 / 0
Регистрация: 11.04.2012
Сообщений: 3
05.09.2012, 20:09  [ТС]     Производительность CPU, КЕШ, многопоточность #3
Если нужно, завтра могу поискать на работе, вроде бы я ее не удалял.
Да, очень нужно. Шлите сюда: lodopip@gmail.com

Что посоветуете почитать по многопоточности? Я в этой теме пока не ориентируюсь.
alexey31415
 Аватар для alexey31415
59 / 59 / 3
Регистрация: 16.05.2010
Сообщений: 632
05.09.2012, 20:15     Производительность CPU, КЕШ, многопоточность #4
по многопоточности в Windows могу посоветовать Petzold Программирование Windows 95 или джонсон Системное программирование в среде Windows
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
06.09.2012, 10:26     Производительность CPU, КЕШ, многопоточность #5
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Код много раз менялся, что-то добавлял, что-то удалял, поэтому выглядет как каша. Я даже уже не помню, рабочая ли это версия. Но при большом желании можно разобраться
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <algorithm>
#include <cerrno>
#include <cstring>
#include <getopt.h>
 
#define L1_CACHE_BYTES  (1 << 6)
#define PREFETCH_STRIDE (4*L1_CACHE_BYTES)
 
#define _3D_INDEX(_x,_y,_z)    (_z) * global_args::y * global_args::x + (_y) * global_args::x + (_x)
 
#define LEFT_VAL(_x,_y,_z)    ((_x) > 0 ? matrix[_3D_INDEX((_x - 1),(_y),(_z))].array[p] : 0)
#define RIGHT_VAL(_x,_y,_z)   ((_x) < global_args::x - 1 ? matrix[_3D_INDEX((_x + 1),(_y),(_z))].array[p] : 0)
#define FRONT_VAL(_x,_y,_z)   ((_y) < global_args::y - 1 ? matrix[_3D_INDEX((_x),(_y + 1),(_z))].array[p] : 0)
#define BACK_VAL(_x,_y,_z)    ((_y) > 0 ? matrix[_3D_INDEX((_x),(_y - 1),(_z))].array[p] : 0)
#define UP_VAL(_x,_y,_z)      ((_z) < global_args::z - 1 ? matrix[_3D_INDEX((_x),(_y),(_z + 1))].array[p] : 0)
#define DOWN_VAL(_x,_y,_z)    ((_z) > 0 ? matrix[_3D_INDEX((_x),(_y),(_z - 1))].array[p] : 0)
 
#define LEFT_ADDR(_x,_y,_z)   ((_x) > 0 ? &(matrix[_3D_INDEX((_x - 1),(_y),(_z))]) : NULL)
#define RIGHT_ADDR(_x,_y,_z)  ((_x) < global_args::x - 1 ? &(matrix[_3D_INDEX((_x + 1),(_y),(_z))]) : NULL)
#define FRONT_ADDR(_x,_y,_z)  ((_y) < global_args::y - 1 ? &(matrix[_3D_INDEX((_x),(_y + 1),(_z))]) : NULL)
#define BACK_ADDR(_x,_y,_z)   ((_y) > 0 ? &(matrix[_3D_INDEX((_x),(_y - 1),(_z))]) : NULL)
#define UP_ADDR(_x,_y,_z)     ((_z) < global_args::z - 1 ? &(matrix[_3D_INDEX((_x),(_y),(_z + 1))]) : NULL)
#define DOWN_ADDR(_x,_y,_z)   ((_z) > 0 ? &(matrix[_3D_INDEX((_x),(_y),(_z - 1))]) : NULL)
 
 
struct node {
    static const size_t size = 100;
    int array[size];
};//__attribute__((aligned(0x4)));
 
struct global_args {
    static size_t block_size;
    static size_t foffset;
    static size_t byte_to_pref;
    static size_t threads;
 
    static const size_t x = 225, y = 225, z = 20, arr_size = x * y * z; //1 012 500
};
 
size_t global_args::block_size = -1;
size_t global_args::foffset = -1;
size_t global_args::byte_to_pref = -1;
size_t global_args::threads = -1;
 
struct args_for_thread {
    size_t beg_x, beg_y, beg_z;
    size_t end_x, end_y, end_z;
    static node *ptr;
    size_t length;
};
 
node *args_for_thread::ptr = NULL;
 
void prefetch_district_point(node *matrix, size_t x, size_t y, size_t z)
{
    node *addrs[] = {LEFT_ADDR(x,y,z), RIGHT_ADDR(x,y,z),  UP_ADDR(x,y,z), DOWN_ADDR(x,y,z)};
 
    for(size_t i = 0; i < sizeof(addrs) / sizeof(*addrs); i++) {
        if (addrs[i]) {
            for(size_t bytes = 0; bytes < 400; bytes += global_args::byte_to_pref) {
               __builtin_prefetch(&(addrs[i] -> array[bytes / sizeof(int)]), 0, 2);
            }
        }
    }
}
 
void prefetch_block_points(node *matrix, size_t _x, size_t _y, size_t _z)
{
    int point_count = global_args::block_size;
 
    for(size_t z = _z; z < global_args::z; z++) {
        for(size_t y = _y; y < global_args::y; y++) {
            for(size_t x = _x; x < global_args::x; x++) {
                prefetch_district_point(matrix, x, y, z);
 
                --point_count;
                if (!point_count) {
                    return;
                }
            }
        }
    }
}
 
int calc_point(node *matrix, size_t x, size_t y, size_t z)
{
    int result = 0;
 
    for(size_t p = 0; p < node::size; p++) {
        matrix[_3D_INDEX(x,y,z)].array[p] = (LEFT_VAL(x,y,z) +
                                             RIGHT_VAL(x,y,z) +
                                             FRONT_VAL(x,y,z) +
                                             BACK_VAL(x,y,z) +
                                             UP_VAL(x,y,z) +
                                             DOWN_VAL(x,y,z)
                                             ) / 6;
 
        result += matrix[_3D_INDEX(x,y,z)].array[p] ;
    }
    return result;
}
 
unsigned int calculated(args_for_thread *arg)
{
    node *matrix = args_for_thread::ptr;
    unsigned int result = 0;
    int point_count = 0;
 
    for(int cnt = 0; cnt < 2; cnt++) {
        for(size_t z = arg -> beg_z; z < global_args::z; z++) {
            for(size_t y = arg -> beg_y; y < global_args::y; y++) {
                for(size_t x = arg -> beg_x; x < global_args::x; x++) {
                    if (point_count == 0) {
                        int diff = global_args::foffset;
                        int xy = global_args::x * global_args::y;
                        size_t zz = diff / xy;
                        size_t yy = (diff % xy) / global_args::x;
                        size_t xx =  (diff % xy) % global_args::x;
 
                        if (xx + x >= global_args::x) {
                            ++yy;
                            xx = xx + x - global_args::x;
                        } else {
                            xx += x;
                        }
                        if (yy + y >= global_args::y) {
                            ++zz;
                            yy = yy + y - global_args::y;
                        } else {
                            yy += y;
                        }
                        if (zz + z < global_args::z) {
                            zz += z;
                            prefetch_block_points(matrix, xx, yy, zz);
                        }
                    }
 
                    result += calc_point(matrix, x, y, z);
 
                    -- arg -> length;
                    if(! arg -> length) {
                        return result;
                    }
 
                    ++point_count;
                    if (point_count == global_args::block_size) {
                        point_count = 0;
                    }
                }
            }
        }
    }
 
    return result;
}
 
 
int main(int argc, char* argv[])
{
    const struct option opts[] = {
                                    {"bs", required_argument, NULL, 's'}, //size of block
                                    {"fof", required_argument, NULL, 'f'}, // offset to start prefetch
                                    {"btp", required_argument, NULL, 'b'}, // step to prefetch (in bytes)
                                    {"threads", required_argument, NULL, 't'}, //number of threads
                                    {NULL, 0, NULL, 0}
                                };
    const char *opt_string = "b:f:s:t:";
    int opt_index = 0;
 
    int opt;
    while((opt = getopt_long(argc, argv, opt_string, opts, &opt_index)) != -1) {
        switch(opt) {
 
        case 'f':
            global_args::foffset = atoi(optarg);
            break;
 
        case 'b':
            global_args::byte_to_pref = atoi(optarg);
            break;
 
        case 's':
            global_args::block_size = atoi(optarg);
            break;
 
        case 't':
            global_args::threads = atoi(optarg);
            break;
        }
    }
 
 
    /*global_args::block_size = 512;
    global_args::foffset = 256;
    global_args::byte_to_pref = 400;
    global_args::threads = 25;*/
 
    if (global_args::block_size == -1 || global_args::foffset == -1 ||
        global_args::byte_to_pref == -1 || global_args::threads == -1) {
        std::cout << "Arguments is required!" << std::endl;
        return 1;
    }
 
//***********************************************************************************
    node *matrix;
 
    try {
        matrix = new node[global_args::arr_size];
    } catch (std::exception &e) {
        std::cout << "Exception: " << e.what() << std::endl;
        return 1;
    }
 
    args_for_thread::ptr = matrix;
 
    for(size_t i = 0; i < global_args::z; i++) {
        for(size_t j = 0; j < global_args::y; j++) {
            for(size_t k = 0; k < global_args::x; k++) {
                for(size_t p = 0; p < node::size; p++) {
                    matrix[_3D_INDEX(k,j,i)].array[p] = i * j * k;
                }
            }
        }
    }
 
    pthread_t *threads = new pthread_t[global_args::threads];
    args_for_thread *th_args = new args_for_thread[global_args::threads];
    size_t length_for_each = global_args::arr_size / global_args::threads;
 
    for(size_t i = 0; i < global_args::threads; i++) {
        size_t beg_x, beg_y, beg_z, end_x, end_y, end_z;
        const size_t xy = global_args::x * global_args::y;
 
        beg_z = (i * length_for_each) / xy;
        beg_y = ((i * length_for_each) % xy) / global_args::x;
        beg_x = ((i * length_for_each) % xy) % global_args::x;
 
        if (i + 1 != global_args::threads) {
            end_z = ((i + 1) * length_for_each) / xy;
            end_y = (((i + 1) * length_for_each) % xy) / global_args::x;
            end_x = (((i + 1) * length_for_each) % xy) % global_args::x;
            th_args[i].length = length_for_each;
        } else {
            end_z = global_args::z;
            end_y = global_args::y;
            end_x = global_args::x;
            th_args[i].length = global_args::arr_size - i * length_for_each;
        }
 
        th_args[i].beg_x = beg_x;
        th_args[i].beg_y = beg_y;
        th_args[i].beg_z = beg_z;
        th_args[i].end_x = end_x;
        th_args[i].end_y = end_y;
        th_args[i].end_z = end_z;
    }
 
    timespec time_start, time_end;
    long long int result = 0;
 
    std::cout << "Start calculation..." << std::endl;
 
    clock_gettime(CLOCK_REALTIME, &time_start);
 
    for(size_t i = 0; i < global_args::threads; i++) {
        int res = pthread_create(&threads[i], NULL, reinterpret_cast<void*(*)(void*)>(calculated), &th_args[i]);
        if (res) {
            std::cout << "Error: " << strerror(res) << std::endl;
            return 1;
        }
    }
 
    for(size_t i = 0; i < global_args::threads; i++) {
        void* calc_result = 0;
        int res = pthread_join(threads[i], &calc_result);
        if (res) {
            std::cout << "Error join " << i << " thread: " << strerror(res) << std::endl;
        }
 
        result += reinterpret_cast<unsigned int>(calc_result);
    }
 
    clock_gettime(CLOCK_REALTIME, &time_end);
 
    int result_sec = time_end.tv_sec - time_start.tv_sec;
    int result_nsec;
    const int nanoseconds = 1E9, digits = 9;
 
    if(time_end.tv_nsec > time_start.tv_nsec) {
        result_nsec = time_end.tv_nsec - time_start.tv_nsec;
    } else {
        if(result_sec > 0) {
            --result_sec;
        }
        result_nsec = nanoseconds - time_start.tv_nsec + time_end.tv_nsec;
    }
 
    std::cout << "Time calculation: " << result_sec << "." << std::setw(digits) << std::setfill('0') << result_nsec << std::endl;
 
    std::cout << "Result: = " << result << std::endl;
 
    delete [] matrix;
 
    return 0;
}
Тут моделируется т.н. stencil computation - это когда в кубе для вычисления значения в какой-то точке необходимо обратиться к всем ее соседям. В качестве производимой операции выбрано простейшее сложение.
P.S. комплируется только под Linux.
FDrum
 Аватар для FDrum
-3 / 0 / 0
Регистрация: 18.02.2010
Сообщений: 80
02.12.2012, 02:11     Производительность CPU, КЕШ, многопоточность #6
а можно это все как-то под Windows замутить?
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
02.12.2012, 09:27     Производительность CPU, КЕШ, многопоточность #7
Можно. Нужно использовать другие потоки (т.е. pthread - это чисто linux'овые потоки) и найти как сделать префетч под нужный компилятор. Либо использовать ассемблерные вставки, есть такие инстуркции prefetcht0, prefetcht1, prefetcht2 и prefetchnta. Их описания и пример использования можно найти в гугле.

Добавлено через 1 минуту
А и еще функцию clock_gettime() тоже нужно заменить.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.12.2012, 14:51     Производительность CPU, КЕШ, многопоточность
Еще ссылки по теме:

Многопоточность C++
C++ Многопоточность
C++ Не обновляется кеш для потоков

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

Или воспользуйтесь поиском по форуму:
FDrum
 Аватар для FDrum
-3 / 0 / 0
Регистрация: 18.02.2010
Сообщений: 80
02.12.2012, 14:51     Производительность CPU, КЕШ, многопоточность #8
черт, походу пойду забирать доки из универа(
уже голова болит, пилю всю неделю, только скорость копирования поменять.
Yandex
Объявления
02.12.2012, 14:51     Производительность CPU, КЕШ, многопоточность
Ответ Создать тему
Опции темы

Текущее время: 19:47. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru