LINUX.ORG.RU

[OpenMP] Всё болит, ничего не помогает

 


0

0

Есть у меня программа, в нераспараллеленой версии работает корректно, всегда, valgrind на неё не ругается, gcc предупреждений не выдаёт. Когда я её распараллеливаю с помощью openmp (только одна функция распараллелена) у неё появляется один забавный глюк. Если я программу запускаю просто так, то она работает; если указываю OMP_NUM_THREADS=2 или 4, то тоже работает без проблем, но если я ставлю OMP_NUM_THREADS=3 или 5, то она может дойти до конца, всё записать и зависнуть, совсем. Проверено на двух машинах: на gcc-4.3.3 и 4.4.3. Пробовал проверить valgrind'ом, но оказалось, что он не поддерживает openmp (можно добавить поддержку, но нужно пересобирать компилятор). Скачал вчера intel thread checker — он тоже ничем не помог — при зависании программы он зависает вместе с ней :) Если запустить thread checker с независающим вариантом, то он выдаёт предупреждения практически на всё (218 штук), при этом от этих предупреждений картина не проясняется, вообще.

Посоветуйте мне что-нибудь для отлова подобных ошибок. Может быть кто-нибудь сталкивался уже с подобным? Могу показать код если кто-то хочет на него смотреть :)

★★★
Ответ на: комментарий от Booster

Логи чего?
Про deadlock то понятно, но не ясно где он вообще может там случиться.

GArik ★★★
() автор топика
#include "main.h"


int main(int argc, char *argv[])
{
	if(argc < 3)
	{	printf("specify filenames on command line\n");
		return 0;  }

	int err_code;
	memmgr mgr;
	err_code = mgr.set_file(argv[1]);
	if(err_code)
	{	err("unable to open file: %s", argv[1]);
		return 1;  }
	SegyFile of(*mgr.get_segy_file());
	err_code = of.create(argv[2]);
	if(err_code)
	{	err("unable to create file: %s", argv[2]);
		return 1;  }
	
	resmgr rmgr;
	rmgr.set_size(mgr.get_segy_file()->getsampcnt());

	unsigned long trcnt = mgr.get_segy_file()->gettrcnt();
	unsigned long sampcnt = mgr.get_segy_file()->getsampcnt();
	unsigned long next_line_beg = 0;
	printf("progress: %6.2f %%", 0.f);
#pragma omp parallel \
	shared (mgr, rmgr, of) \
	shared (next_line_beg, trcnt) \
	firstprivate (err_code)
{
	unsigned long line_beg;
	unsigned long line_size = 0;
	unsigned long prev_line_size = 0;
	float **line = (float **)malloc(1024 * sizeof(*line));
	char **hdrs = (char **)malloc(1024 * sizeof(*hdrs));
	float **res = (float **)malloc(1024 * sizeof(*res));
	while(next_line_beg < trcnt)
	{
#pragma omp critical (mgr)
{
		line_beg = next_line_beg;
		err_code = mgr.read_line(line_beg, 21, 4, line_size);
		if(!err_code)
			next_line_beg += line_size;
}
		if(err_code)
		{	err("unable to read line");
			goto end;  }

#pragma omp critical (mgr)
		err_code = mgr.get_chunk(line_beg, line_size, line);
		if(err_code)
		{	err("unable to get chunk");
			goto end;  }

#pragma omp critical (mgr)
		err_code = mgr.get_hdrs(line_beg, line_size, hdrs);
		if(err_code)
		{	err("unable to get headers");
			goto end;  }
		
#pragma omp critical (rmgr)
		err_code = rmgr.reget_mem(prev_line_size, line_size, res);
		if(err_code)
		{	err("unable to reget mem");
			goto end;  }

		/// чего-то с этими данными делаем
		process_line(line, line_size, sampcnt, res);
		/// записываем результат

#pragma omp critical (of)
		err_code = put_result(of, hdrs, res, line_beg, line_size);
		if(err_code)
		{	err("unable to write result");
			goto end;  }
		
#pragma omp critical (mgr)
		err_code = mgr.release_chunk(line_beg, line_size);
		if(err_code)
		{	err("unable to release chunk");
			goto end;  }

		prev_line_size = line_size;
		//printf("line_size = %lu\n", line_size);
#pragma omp single
{
		printf("\rprogress: %6.2f %%", mgr.get_progress() * 100.f);
		fflush(stdout);
} // omp single
	} // while(next_line_beg
end:
	free(res);
	free(hdrs);
	free(line);
} // omp parallel
#pragma omp barrier
	printf("\rprogress: %6.2f %%\n", 100.f);
	of.close();
	//if(err_code)
	//	return 1;
	return 0;
}

GArik ★★★
() автор топика
Ответ на: комментарий от GArik

Может, я все забыл и впал в маразм, но разве можно ставить #pragma omp barrier вне parallel? Там же и так один поток. Попробуй убррать последний барьер.

tim239 ★★
()
Ответ на: комментарий от tim239

> Может, я все забыл и впал в маразм, но разве можно ставить #pragma omp barrier вне parallel?
Вроде можно, в любом случае вставка барьера перед скобкой результат не меняет.

GArik ★★★
() автор топика
Ответ на: комментарий от rha

> по поводу barrier скажу, что он выполняется неявно по выходу из parallel ЕМНИП
Ммм... для директив, у которых есть неявный barrier есть предложение nowait, а у parallel такого нету. Опять же по вашей логике он может быть лишним, но он явно не может приводить к зависанию.

GArik ★★★
() автор топика

Хахах, спасибо всем, вы открыли мне глаза. Там в omp single был неявный барьер и иногда одни потоки ждали остальных на явном, а остальные висели на неявном. Поставил omp single nowait и всё стало хорошо.

GArik ★★★
() автор топика
Ответ на: комментарий от GArik

parallel необычная деректива. Она определяет область жизни параллельных задач. Эта область создатся мастером, поэтому отсутствие неявного barrier наводило бы на мысли, а кто продолжает работать после выхода из параллельной области.

И в мануале сказано:

There is an implied barrier at the end of a parallel region. After the end of a parallel region, only the master thread of the team resumes execution of the enclosing task region.

rha
()
Ответ на: комментарий от rha

Спасибо большое, буду читать :)

GArik ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.