time left for file copy
От: Аноним  
Дата: 08.11.07 16:39
Оценка:
Добрый вечер.

Пишу программу которая выполняет ф-ию заливки стуктуры файлов с одного место в другое (к примеру нужно переписать все файлы из директории c:\Windows\ в указанную директорию). Задача в том что я не могу правильно написать алгоритм подсчета времени.


function TFormCopy.CalculateTime(newReaded: Int64; maxSize : Int64): Int64;
var
    nowTime, timeSpent : Cardinal;
    bytePerSec : Integer;

begin
    Result := -1;
    if newReaded = 0 then Exit;

    nowTime := MilliSecondOfTheDay(Now);
    if lastTime = 0 then
    begin
        lastTime := nowTime;
        Exit;
    end;

    timeSpent := nowTime - lastTime;
    if timeSpent > 0 then
    begin
        bytePerSec := newReaded div timeSpent;
        if bytePerSec <= 0 then
            bytePerSec := 1;
        Result := Floor(maxSize - newReaded) div bytePerSec;
    end;
    lastTime := nowTime;
end;


Эта ф-ия возращает время в секундах. newReaded — сколько байт уже считано всего.
Вызываю эту функцию из диалога в котором подсчитывается для пользователя премерное время завершения, данные беру у Thread'a в котором происходит копирование. Ф-ия вызывается раз в 250 сек. по таймеру.

Что я делаю не так?
Re: time left for file copy
От: VEAPUK  
Дата: 08.11.07 17:59
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Эта ф-ия возращает время в секундах. newReaded — сколько байт уже считано всего.

А>Вызываю эту функцию из диалога в котором подсчитывается для пользователя премерное время завершения, данные беру у Thread'a в котором происходит копирование. Ф-ия вызывается раз в 250 сек. по таймеру.

А>Что я делаю не так?

Что такое newReaded, т.е. сколько прочитано после последнего вызова CalculateTime или сколько всего прочитано в последнем "задании"?
Если первое, то (maxSize — newReaded) больше реального остатке, если второе, то bytePerSec := newReaded div timeSpent больше реальной скорости за последний интервал.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: time left for file copy
От: a18 Россия  
Дата: 09.11.07 12:45
Оценка:
А>Эта ф-ия возращает время в секундах. newReaded — сколько байт уже считано всего.

1) Судя по названию функции "MilliSecondOfTheDay", вы работаете с миллисекундами, т.е. надо где-то делить/умножать на 1000.
2) Если newReaded — это сколько прочитано всего, то последнюю строчку (lastTime := nowTime) надо убрать.
3) В свете вышеизложенного, вместо глобальной переменной lastTime (ИМХО это плохой стиль вообще), можно будет передать
в функцию параметр startTime: Cardinal, который будет присваиваться снаружи один раз при старте копирования.
Re: time left for file copy
От: Кодт Россия  
Дата: 09.11.07 14:32
Оценка: 12 (1)
Здравствуйте, <Аноним>, Вы писали:

А>Что я делаю не так?


Нужно определиться с двумя вещами:
— метод измерения
— метод экстраполяции

У тебя есть зависимость p<->t, показывающая процент выполнения и потраченное время. p(0)=0, p(t_end)=100%.
(Можно пересчитать проценты в байты — это дела не меняет).

Можно предположить, что зависимость линейна, но на деле это не так: примешиваются и неровности скорости выполнения, и взаимодействие выполнения с измерением.
Например, фактическая p(t) — это одинаковые ступеньки вдоль линейной асимптоты, а период измерений не совпал с периодом ступенек. В измеренной функции будут биения.
Поэтому постоянное сэмплирование по таймеру — не всегда хорошая затея. А частота измерений 4 раза в секунду — вообще не оправдана.

Ну ладно, вернёмся к экстраполяции.
p(t) = p_now+v_now*(t-t_now)
решаем уравнение ? t_end : p(t_end)=100%
t_end = t_now+(100%-p_now)/v_now

Тут есть две крайности:
1) Моментальная скорость. Проблема в том, что моментальная скорость постоянно прыгает — и по причине внезапных разгонов/тормозов, и из-за ступенчатой природы выполнения.
Как следствие, t_end станет метаться то в "почти сейчас", то в "никогда потом".
2) Средняя скорость от начала работы: v_now=p_now/t_now. Если в начале были тормоза, то ожидаемое время будет постоянно завышено, а если тормоза возникли сейчас, — то наоборот, занижено.

Лучше исходить из средней скорости за последние несколько секунд. Для этого заводится окно измерений p(t) с постоянной или переменной частотой сэмплирования. Размер окна следует выбирать так, чтобы он охватывал несколько ступенек.
Если скорость выполнения упала, и в окне много повторяющихся значений p(t), то можно понизить частоту, при этом длительность окна вырастет, а объём памяти сохранится.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: time left for file copy
От: a18 Россия  
Дата: 09.11.07 16:29
Оценка: 99 (3)
К>Лучше исходить из средней скорости за последние несколько секунд. Для этого заводится окно измерений p(t) с постоянной или переменной частотой сэмплирования. Размер окна следует выбирать так, чтобы он охватывал несколько ступенек.

Кстати, в фин. анализе иногда используется взвешенное скользящее среднее (EMA), которое позволяет вообще обойтись без запоминания всех значений окна — требуется помнить только одно предыдущее значение:
http://en.wikipedia.org/wiki/Exponential_moving_average#Exponential_moving_average
ИМХО будет очень красиво работать!
Re[3]: time left for file copy
От: Кодт Россия  
Дата: 09.11.07 16:46
Оценка:
Здравствуйте, a18, Вы писали:

a18>Кстати, в фин. анализе иногда используется взвешенное скользящее среднее (EMA), которое позволяет вообще обойтись без запоминания всех значений окна — требуется помнить только одно предыдущее значение:

a18>http://en.wikipedia.org/wiki/Exponential_moving_average#Exponential_moving_average
a18>ИМХО будет очень красиво работать!

Очень интересно!
Правда, остаются вопросы:
— как подобрать альфу
— как интерполировать измерения (ступеньками, трапециями, экспонентами),
чтобы
— уменьшить влияние частоты сэмплирования (поскольку чем выше частота, тем отчётливее получатся ступеньки — хотя наша задача ещё и сгладить их)
— получить приемлемый результат с минимумом дерготни
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: time left for file copy
От: a18 Россия  
Дата: 09.11.07 17:26
Оценка:
a18>>Кстати, в фин. анализе иногда используется взвешенное скользящее среднее (EMA), которое позволяет вообще обойтись без запоминания всех значений окна — требуется помнить только одно предыдущее значение:
a18>>http://en.wikipedia.org/wiki/Exponential_moving_average#Exponential_moving_average
a18>>ИМХО будет очень красиво работать!

К>Очень интересно!

К>Правда, остаются вопросы:
К>- как подобрать альфу
К>- как интерполировать измерения (ступеньками, трапециями, экспонентами),
К>чтобы
К>- уменьшить влияние частоты сэмплирования (поскольку чем выше частота, тем отчётливее получатся ступеньки — хотя наша задача ещё и сгладить их)
К>- получить приемлемый результат с минимумом дерготни

По ссылкам там, оказывается, ещё одна подобная статья есть:
http://en.wikipedia.org/wiki/Exponential_smoothing#The_exponential_moving_average
... с диагнозом: "There is no formally correct procedure for choosing a"
На практике обычно берут, как и написано в первой статье, alpha = 2/(N+1), где N — период обычной скользящей средней (SMA), поведение которой нас устраивает.

По ощущениям, чтобы пользователю было интересно наблюдать за результатами предсказания, можно сделать частоту измерений 1 раз в секунду и N взять порядка 10..50 — для копирования файлов должно быть приемлемо. Кстати, при большИх N ещё есть проблема начального выплеска — если первое измерение будет неадекватно большим (а для случая копирования файлов это весьма вероятно), то функция потом будет слишком долго "приходить в себя". Возможно, тут оправдано взять в качестве первого значения не x0, а просто чистый 0.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.