Недавно я столкнулся с «забавной» проблемой, связанной с реализацией CRTL в Microsoft. tmpfile
помещает временные файлы в корневой каталог и полностью игнорирует каталог временных файлов. Это имеет проблемы с пользователями, которые не имеют прав доступа к корневому каталогу (скажем, в нашем кластере). Более того, использование _tempnam
потребует от приложения не забыть удалить временные файлы, что невозможно без значительного количества переделок.
Поэтому я укусила пулю и написала Win32-версию всех подпрограмм ввода-вывода (create_temp, read, write, seek, flush), которые вызывают соответствующий метод. Одна вещь, которую я заметил, - это ужасная производительность библиотеки.
Результаты теста:
CRTL: 4:30.05 elapsed
Win32: 11:18.06 elapsed
Stats measured in my routines:
Writes: 3129934 ( 44,642,745,008 bytes)
Reads: 935903 ( 8,183,423,744 bytes)
Seeks: 2205757 (2,043,782,657,968 bytes traveled)
Flushes: 92442
Пример использования метода CRTL v. Win32:
int io_write(FILE_POINTER fp, size_t words, const void *buffer)
{
#if !defined(USE_WIN32_IO)
{
size_t words_written = 0;
/* read the data */
words_written = fwrite(buffer, sizeof(uint32_t), words, fp);
if (words_written != words)
{
return errno;
}
}
#else /* !defined(USE_WIN32_IO) */
{
DWORD bytesWritten;
if (!WriteFile(fp, buffer, words * sizeof(uint32_t), &bytesWritten, NULL)
|| (bytesWritten != words * sizeof(uint32_t)))
{
return GetLastError();
}
}
#endif /* USE_WIN32_IO */
return E_SUCCESS;
}
Как видите, они практически идентичны, но производительность (в режиме выпуска) сильно отличается. Время, проведенное в WriteFile
и SetFilePointer
, превосходит время, потраченное в fwrite
и fseeko
, что кажется нелогичным.
Идеи
ОБНОВЛЕНИЕ: perfmon отмечает, что fflush
примерно в 10 раз дешевле, чем FlushFileBuffers
, а fwrite
примерно в 1,1 раза медленнее, чем WriteFile
. Конечным результатом является огромная потеря производительности, когда FlushFileBuffers
используется так же, как и fflush
. Также нет изменений от FILE_ATTRIBUTE_NORMAL
до FILE_FLAG_RANDOM_ACCESS
.