2009-11-15 2 views
0

Я пытаюсь проецировать файл в память для работы с ним. Структуры файлов contais, поэтому я пытаюсь использовать указатель на начало одной структуры, а затем читать ее и изменять некоторую переменную. Проблема в том, что время выполнения велико, и я полагаю, что использование mmap будет меньше. Это код, любое предложение?Проецирование файла в память с помощью mmap

#include <unistd.h> 
#include <sys/stat.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/mman.h> 

int revisanotas(int fd) 
{ 
int nbytes=1; 
int nbytese=0; 
int i=0; 
int n=0; 
struct stat datos; 
fstat(fd, &datos); 
evaluacion buf; 
evaluacion* buffer=mmap(0,datos.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 
int actual = read(fd,buffer,datos.st_size); 
{ 
i++; 
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5) 
{ 
n=n+1; 
printf("Notamedia = %f\n",buffer[i].notamedia); 

buffer[i].notamedia=5; 
} 

}while (i<(datos.st_size/(sizeof(evaluacion)))); 
return 
+0

Вам не хватает 'do' после вызова' read'? –

ответ

2

Ну, во-первых, расскажите, пожалуйста, что evaluacion определяется как и поставить do там, что совпадает с while; Я предполагаю, что это сразу после строки «int actual».

Во-вторых, похоже, что вы чаще всего вызываете mmap(), чем необходимо; как часто бывает revisanotas() с тем же fd? Сам вызов mmap медленный, например malloc; скорость - это когда вы используете сопоставленный файл, в данном случае данные, на которые указывает buffer.

В-третьих, вычислите datos.st_size/(sizeof(evaluacion)) один раз за пределами цикла и измените положение while, чтобы сравнить его. Текущий код выглядит так, будто он выполняет разделение один раз на итерацию через цикл, а деления медленны.

Посмотрите, поможет ли это.

2

Требование к read() не является необходимым. Mmap()карты содержимое файла в памяти для вас - поэтому он обычно быстрее, чем чтение всего файла с помощью read(). Вы должны убрать звонок до read(). Однако есть и другие проблемы с вашим кодом.

Если вы хотите, чтобы изменения действительно отражались в файле на диске, тогда вы должны позвонить msync(buffer, dataos.st_size, MS_SYNC). Когда вы закончите, вызовите munmap(buffer, dataos.st_size), чтобы освободить сегмент разделяемой памяти. Подумайте об msync() как эквивалент общей памяти fflush() и munmap() похож на close(). Ключевое различие между munmap() и close() состоит в том, что первое не очищает буферы или не синхронизируется с диском, поэтому вам нужно сделать это самостоятельно.

+0

Большое спасибо, я удалил read(), и время резко уменьшилось :).Теперь я пытаюсь понять, как использовать msync, потому что мне нужно изменить переменную notamedia в каждой структуре, которая соответствует условию, а затем записать на диск весь файл. – Peter

+0

После завершения изменения всех значений вызовите 'msync()' на весь сегмент данных. Если изменения в каждой структуре должны быть видимыми во время модификации, тогда вызовите 'msync (& buffer [i], sizeof (buffer [i]), MS_SYNC)' после внесения изменений. Я не уверен, если вы можете с уверенностью относиться к последнему, поскольку, поскольку отдельные элементы 'buffer', вероятно, не выравниваются по страницам. Лучше делать весь сегмент за один раз после завершения цикла. –

+0

Это неправильно. Нет необходимости использовать 'msync' для внесения изменений в файл. –

0
Thanks mike for the answer, the struct is something like this and it's defined in a header file: 

struct evaluacion 
{ char id[16]; 
char apellido1[32]; 
char apellido2[32]; 
char name[32]; float nota1p; 
float nota2p; 
float notamedia; 
char photofilename[20]; 
int photosize; 
char photodata[16000]; 
}; 

Там только один FD, только один файл открыт, но многие внутри

Структуры
0

Я некоторый прогресс, я думаю, но, кажется, я не модифицируя файл. Если я запускаю программу один раз, он обнаруживает 32 переменных измененными, но если я бегу дважды все тот же, когда он должен быть изменен :(

Время выполнения теперь не плохо, я думаю, что

int revisanotas(int fd) 
{ 
int i=0; 
int n=0; 
struct stat datos; 
fstat(fd, &datos); 
int num=datos.st_size/(sizeof(evaluacion)); 
evaluacion buf; 
evaluacion* buffer=mmap(0,datos.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 
do 
{ 
i++; 
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5) 
{ 
n=n+1; 

buffer[i].notamedia=5; 
} 
msync(&buffer[i],sizeof(buffer[i]),MS_SYNC); 
}while (i<(num)); 
munmap(buffer,datos.st_size); 
return(n); 
} 
+0

Проверьте возвращаемое значение 'msync'. Я предполагаю, что он терпит неудачу, возвращает -1 и устанавливает 'errno' в' EINVAL' (22). Попробуйте вызвать 'msync (buffer, dataos.st_size, MS_SYNC)' перед вызовом 'munmap'. –

+0

Я сделал: int r = msync (buffer, datos, st_size, MS_SYNC); mmunmap (buffer, datos.st_size), Кажется, что msync возвращается 0 Исправить, если я ошибаюсь, но мне нужно что-то сделать, чтобы перезаписать исходный файл, описанный «fd»? или как только я освобожу память, а запись с msync будет записана в файл? – Peter

0

Я думаю, что сейчас работает :), код выглядит следующим образом. Прокомментируйте, если вы видите что-то не так:

int revisanotas(int fd) 
{ 
int i=0; 
int n=0; 
struct stat datos; 
fstat(fd, &datos); 
int num=datos.st_size/(sizeof(evaluacion)); 

evaluacion* buffer=mmap(0,datos.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
do 
{ 
i++; 
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5) 
{ 
n=n+1; 
buffer[i].notamedia=5; 
} 

}while (i<(num)); 
int r=munmap(&buffer[0],datos.st_size); 

return(n); 
} 

Спасибо всем за помощь.

Смежные вопросы