Дано: некий процесс ведет лог своей работы, ожидаемый максимальный размер лога порядка нескольких Мбайт.
Процесс ресурсоемкий, сильно загружает CPU, вероятно использует файл подкачки и периодически считывает данные с диска.
Требуется: сохранять лог в файл без ущерба для скорости работы процесса
Решения, которые пришли мне в голову:
1. Хранить лог в виртуальной памяти и сохранять при выходе неприемлемо, т.к. довольно велика вероятность аварийного завершения процесса.
2. Открывать и закрывать файл для каждой записи в отдельности — медленно.
3. Можно создать объект ядра "файл" и писать туда при помощи WriteFile, но не хотелось бы тормозить процесс до завершения функции. Асинхронная запись через WriteFile не подходит, так как нужна совместимость с Win9x.
4. Создать проекцию файла с флагом PAGE_READWRITE, спроецировать на адресное пространство и писать туда, чтобы Win сама сохраняла изменения на HDD, когда представится такая возможность.
Верны ли мои рассуждения ? Даст ли последний вариант выигрыш в производительности ?
Hello AlexEagle, you wrote:
> Я бы посоветовал писать в пайп, который разгребается другим процессом.
Этот вариант заведомо медленней, чем если бы записью занимался сам процесс
(будет тратиться дополнительное время на отправку/прием/переключение
процессов)
Здравствуйте, Slava Antonov, Вы писали:
SA>А зачем его постоянно открывать/закрывать?
Я имел в виду, придется постоянно открывать\закрывать, если писать в файл средствами C, например, fwrite.
При аварийном завершении процесса изменения не будут внесены, если файл не закрывать каждый раз с помощью fclose.
Выполнять fopen\fclose при записи каждого сообщения — долго, так что этот вариант не подходит.
При использовании проекции файла основной процесс может быть аварийно закрыт с помошью среды разработки или диспетчера задач, но, мне кажется, винда сохранит содержимое проекции, прежде чем удалять ее (м.б., я не прав).
В крайнем случае, можно запустить крошечный вспомогательный процесс, который при старте откроет ту же проекцию и спокойно сохранит ее при аварийном закрытии основного, после чего самоустранится.
Все это имхо, и хотелось бы услышать еще комментарии.
Здравствуйте, Akai, Вы писали:
A> Товарищи ! A> Есть следующая проблема:
A> Дано: некий процесс ведет лог своей работы, ожидаемый максимальный размер лога порядка нескольких Мбайт. A>Процесс ресурсоемкий, сильно загружает CPU, вероятно использует файл подкачки и периодически считывает данные с диска.
A> Требуется: сохранять лог в файл без ущерба для скорости работы процесса
A> Решения, которые пришли мне в голову: A>1. Хранить лог в виртуальной памяти и сохранять при выходе неприемлемо, т.к. довольно велика вероятность аварийного завершения процесса. A>2. Открывать и закрывать файл для каждой записи в отдельности — медленно. A>3. Можно создать объект ядра "файл" и писать туда при помощи WriteFile, но не хотелось бы тормозить процесс до завершения функции. Асинхронная запись через WriteFile не подходит, так как нужна совместимость с Win9x. A>4. Создать проекцию файла с флагом PAGE_READWRITE, спроецировать на адресное пространство и писать туда, чтобы Win сама сохраняла изменения на HDD, когда представится такая возможность.
A> Верны ли мои рассуждения ? Даст ли последний вариант выигрыш в производительности ?
Создаешь дополнительный поток с низким приоритетом и очередь сообщений. Рабочий поток все пишет в эту очередь, а дальше его не волнует. А вот дополнительный поток будет все это дело разгребать, и по мере возможности записывать в файл. Как раз для меньшего влияния надо поставить ему маленький приоритет.
Здравствуйте, Akai, Вы писали:
A>Здравствуйте, Slava Antonov, Вы писали:
SA>>А зачем его постоянно открывать/закрывать?
A>Я имел в виду, придется постоянно открывать\закрывать, если писать в файл средствами C, например, fwrite. A>При аварийном завершении процесса изменения не будут внесены, если файл не закрывать каждый раз с помощью fclose. A>Выполнять fopen\fclose при записи каждого сообщения — долго, так что этот вариант не подходит.
Если Вы так боретесь за портабельность кода, есть ANSI C ф. fflush. Она Вам поможет избежать многократных открытий/закрытий файла. Правда это не снимает проблемы траты времени на синхронные операции записи.
Я бы сделал так: быстрый поток скидывает лог в некий контейнер типа FIFO, медленный поток (с пониженным приоритетом) разгребает его пользуясь обычными синхронными операциями записи на диск, подтверждая каждую запись вызовом fflush или FlushFileBuffers.
Здравствуйте, TarasCo, Вы писали:
TC>Здравствуйте, Akai, Вы писали:
TC>Если Вы так боретесь за портабельность кода, есть ANSI C ф. fflush. Она Вам поможет избежать многократных открытий/закрытий файла. Правда это не снимает проблемы траты времени на синхронные операции записи.
TC>Я бы сделал так: быстрый поток скидывает лог в некий контейнер типа FIFO, медленный поток (с пониженным приоритетом) разгребает его пользуясь обычными синхронными операциями записи на диск, подтверждая каждую запись вызовом fflush или FlushFileBuffers.
смотря как критично потерять лог, если потеря нескольких записей возможна, то на таймере в 1 с сбрасывать fflush и никакой головной боли синхронизации и потоков.
и опять мы начинаем оптимизировать, не замерив, (или нам результаты замеров не доложили).
---
С уважением,
Сергей Мухин
Re[5]: Сохранение лога ресурсоемкого процесса
От:
Аноним
Дата:
23.06.04 11:02
Оценка:
Спасибо за ответы...
Терять сообщения лога, особенно последние, не хотелось бы, поэтому, наверное, лучше создавать процесс с низким приоритетом и передавать ему для сохранения (например, через пайп)
Кто-нибудь может объяснить, чем плох мой вариант с проекцией ?
В MSDN по поводу записи в проекции сказано:
The actual writing to the file on disk is handled by the system. Data is not actually transferred at the time the file-mapping object is written to. Instead, much of the file input and output (I/O) is cached to improve general system performance.
Или этот кэшированный вывод все-таки будет существенно тормозить процесс ?
Замеры доложить не могу, т.к. проект будет еще расти и расти, а класс, который пишет логи, нужен уже сейчас. Желательно сразу на пальцах прикинуть, какой механизм будет оптимальным.
Здравствуйте, Аноним, Вы писали:
А> Или этот кэшированный вывод все-таки будет существенно тормозить процесс ?
А> Замеры доложить не могу, т.к. проект будет еще расти и расти, а класс, который пишет логи, нужен уже сейчас. Желательно сразу на пальцах прикинуть, какой механизм будет оптимальным.
1.
тут есть два кеша. один грубо говоря программный или С-ный, второй системный.
когда С/C++ программа пишет данные, то они попадают в программный буфер (для консольного ввода-вывода и для устройств (com1) буфера нет), и после накопления буфера или явно по flush отдаются системе. После этого система скидвает на диск, возможно не сразу, а с задержкой.
Если мы ожидаем, что приложение будет падать (написано что-ли плохо?), то нам надо делать flush а система успеет записаться, если мы ожидаем, что будет падать машина (либо железо, либо питание), то проще купить UPS.
2. в таких случаях лучше написать интерфейс к логу и сделать его элементарным — время 10 мин. а после работы всего проекта менять (если потребуется) имплементацию лога. Иначе может оказаться, что все силы уйдут на лог, а на приложение ничего не останется.
Здравствуйте, SergeMukhin, Вы писали:
SM>1. SM>тут есть два кеша. один грубо говоря программный или С-ный, второй системный. SM>когда С/C++ программа пишет данные, то они попадают в программный буфер (для консольного ввода-вывода и для устройств (com1) буфера нет), и после накопления буфера или явно по flush отдаются системе. После этого система скидвает на диск, возможно не сразу, а с задержкой. SM>Если мы ожидаем, что приложение будет падать (написано что-ли плохо?), то нам надо делать flush а система успеет записаться, если мы ожидаем, что будет падать машина (либо железо, либо питание), то проще купить UPS.
Не совсем понимаю... Какой C-шный кэш ? Если мы пишем что-то в проекцию, оно должно сразу попадать в виртуальную память. Иначе как быть с заявленной MS когерентностью ?
Кроме того, я так понял, что FlushViewOfFile заставляет систему немедленно сбросить содержимое измененных страниц проекции на HDD.
Т.е. механизм такой — создаем проекцию и по мере необходимости пишем туда сообщения — без Flush, чтобы не было тормозов. Система эти сообщения потихоньку сохраняет на HDD, когда есть такая возможность, используя какой-то свой кэш.
Одновременно с этим проекция открыта вспомогательным процессом — спутником.
Если наш процесс рухнет, объект ядра "проекция" не будет уничтожен, т.к. счетчик использующих процессов у него не обнулится, а уменьшится с 2 до 1. В этом случае процесс-спутник просекает, что основной процесс вылетел, flush'ит проекцию и завершается сам.
Все сообщения должны сохраниться.
Я не прав ?
SM>2. в таких случаях лучше написать интерфейс к логу и сделать его элементарным — время 10 мин. а после работы всего проекта менять (если потребуется) имплементацию лога. Иначе может оказаться, что все силы уйдут на лог, а на приложение ничего не останется.
Дело в том, что лог как раз нужен во время разработки проекта. По этой же причине предполагается падение приложения — всякое может быть в ходе наших экспериментов. После релиза его вообще можно отключить или свести число записей к минимуму. Поэтому имплементация нужна сразу.
A> Не совсем понимаю... Какой C-шный кэш ? Если мы пишем что-то в проекцию, оно должно сразу попадать в виртуальную память. Иначе как быть с заявленной MS когерентностью ? A> Если наш процесс рухнет, объект ядра "проекция" не будет уничтожен, т.к. счетчик использующих процессов у него не обнулится, а уменьшится с 2 до 1. В этом случае процесс-спутник просекает, что основной процесс вылетел, flush'ит проекцию и завершается сам. A> Все сообщения должны сохраниться. A> Я не прав ?
зачем так сложно?
ставим try/catch и записываем лог при падении, или через деструктор.
SM>>2. в таких случаях лучше написать интерфейс к логу и сделать его элементарным — время 10 мин. а после работы всего проекта менять (если потребуется) имплементацию лога. Иначе может оказаться, что все силы уйдут на лог, а на приложение ничего не останется.
A> Дело в том, что лог как раз нужен во время разработки проекта. По этой же причине предполагается падение приложения — всякое может быть в ходе наших экспериментов. После релиза его вообще можно отключить или свести число записей к минимуму. Поэтому имплементация нужна сразу.
гм мы говорили все это время о скорости работы ОТЛАДОЧНОГО лога? ставь try/catch и не мудри.
---
С уважением,
Сергей Мухин
Re[9]: Сохранение лога ресурсоемкого процесса
От:
Аноним
Дата:
23.06.04 13:05
Оценка:
SM>гм мы говорили все это время о скорости работы ОТЛАДОЧНОГО лога? ставь try/catch и не мудри.
Ну... Типа, мой вариант несколько железобетоннее.
Хотя в самом деле, стоит ли мучаться ? Пусть flush'ится в потоке с низким приоритетом и в catch...
Если уж приложение что-то из ряда вон выходящее сотворит, может и вспомогательный процесс не помочь...
Здравствуйте, Аноним, Вы писали:
SM>>гм мы говорили все это время о скорости работы ОТЛАДОЧНОГО лога? ставь try/catch и не мудри.
А> Ну... Типа, мой вариант несколько железобетоннее.
только он на порядок сложней и значит сам может содержать ошибки.
А> Хотя в самом деле, стоит ли мучаться ? Пусть flush'ится в потоке с низким приоритетом и в catch...
если это в отдельном thread то надо синхронизовать, а зачем:? пиши так как есть, а в конце по деструктуру (или try/catch __try/__finaly) скидывай все и закрывай.
пройдет в 99.9% и делов то 5 строк, больше обсуждаем
А> Если уж приложение что-то из ряда вон выходящее сотворит, может и вспомогательный процесс не помочь...
Здравствуйте, SergeMukhin, Вы писали:
SM>Здравствуйте, Аноним, Вы писали:
SM>>>гм мы говорили все это время о скорости работы ОТЛАДОЧНОГО лога? ставь try/catch и не мудри.
А>> Ну... Типа, мой вариант несколько железобетоннее.
SM>только он на порядок сложней и значит сам может содержать ошибки.
А>> Хотя в самом деле, стоит ли мучаться ? Пусть flush'ится в потоке с низким приоритетом и в catch...
SM>если это в отдельном thread то надо синхронизовать, а зачем:? пиши так как есть, а в конце по деструктуру (или try/catch __try/__finaly) скидывай все и закрывай. SM>пройдет в 99.9% и делов то 5 строк, больше обсуждаем
А>> Если уж приложение что-то из ряда вон выходящее сотворит, может и вспомогательный процесс не помочь...
Короче перед тем как говорить о проектировании логирования надо ответить на след вопросы: насколько часто надо логироваться, насколько важно сохранить инфолрмацию, как сильно будет загружен процессор другими потоками, как долго надо логировать значения. А то получается общаетесь на абстрактную тему.