Скорость предкомпиляции?

отредактировано 10:39 Раздел: FastReport 4.0
Используем встроенный в наше ПО FR

Используем для создания форм в приложении.
До сих пор всё было нормально, но...
Столкнулись с проблемой долгой загрузки FR (предпосылки, что проверяется синтаксис или происходит предкомпиляция ...)

В коде прописано следующее (сама форма пустая):

написал:
procedure OnStartReport(Sender: TfrxComponent);
var
str: string;
begin
FormShow('DialogPage1');

ShowMessage('Start');
str:='weoirun vq2394punvqp948nq9p38rucpw9me8rxu9qpwe8urcm9qw8uercmn9qw8urn9qw8eurn9';//Произвольная строка
//5000 (5 тыс) подобных строк
ShowMessage('Finish');
end;

При этом открытие просходи около 1 минуты!!! :)
Время между двумя ShowMessage - меньше секунды.

Подскажите - как строить подобные формы?

Комментарии

  • xlaalaaxlaalaa Минск
    отредактировано 10:39
    Рекомендую воспользоваться продуктом AQTime компании AutomatedQA. С помощью реализованного там Performance-profiler вы легко определите, что же именно в вашем случае тормозит загрузку.
  • отредактировано August 2009
    xlaalaa написал: »
    Рекомендую воспользоваться продуктом AQTime компании AutomatedQA. С помощью реализованного там Performance-profiler вы легко определите, что же именно в вашем случае тормозит загрузку.

    Согласен, тормозит.
    И тормозит имеенно при открытии этого отчета. Такое подозрение, что оно его при открытии компилит каждый раз. И чем больше строк кода, тем дольше. В случае Asparagus'а 5000 строк обычного присвоения тормозит целую минуту.
    Была у меня идея каким-то образом скомпилить отчет один раз, а потом его просто запускать как-то. Но пока я не догодался как.

    Может кто подскажет? А то сложные большие отчеты открывать по минуте как-то неприкольно.
  • отредактировано 10:39
    Под открытием подразумевается запуск отчета на выполнение(PrepareReport) или загрузка шаблона (LoadReport) ?
    Если выполнение, то это нормальное явление для скрипта.
    Т.к. при каждом запуске скрипт парсится и на его основе собирается XML, поэтому чем больше скрипт - тем дольше компиляция.
  • xlaalaaxlaalaa Минск
    отредактировано August 2009
    Измерение с помощью AQtime для примера Asparagus'а показывает, что основное время от момента начала загрузки до момента выдачи сообщения "Start" занимает работа процедуры TfsScript.AddCodeLine (см. картинку) время ее работы заняло 41,56 % от общего времени. Вызываемые из нее функции диспетчера памяти тоже заняли существенный процент времени.

    Предполагаю, что ускорить процесс компиляции отчетов можно изменив алгоритм работы этой функции. Избавившись от громоздких вызовов
      sl.CommaText := FUnitLines.Values[UnitName];
      if sl.IndexOf(LineN) = -1 then
      sl.Free;
    
    заменив их на что нибудь более быстрое.

    Подумайте, может у кого нибудь получиться. Поделитесь тогда опытом :)

  • отредактировано 10:39
    написал: »
    Под открытием подразумевается запуск отчета на выполнение(PrepareReport) или загрузка шаблона (LoadReport) ?
    Если выполнение, то это нормальное явление для скрипта.
    Т.к. при каждом запуске скрипт парсится и на его основе собирается XML, поэтому чем больше скрипт - тем дольше компиляция.

    Нет, я говорю не про дизайн моду, а про запуск на выполнение.
    А по поводу XML... а можно с этого места подробнее?!
    Может можно изготовить этот XML один раз, а постоянно его просто подсовывать как-то?

    xlaalaa, а процедура эта в исходниках компонента?
  • xlaalaaxlaalaa Минск
    отредактировано 10:39
    Drag написал: »
    Нет, я говорю не про дизайн моду, а про запуск на выполнение.
    xlaalaa, а процедура эта в исходниках компонента?

    Измерял время именно запуска на выполнение (а не дизайнер). В наше программе форма отчета, при запуске на выполнение грузится из файла (из потока типа TStream) и сразу запускается на выполнение Prepare.

    Процедура эта в исходниках компоненты, см. скришот. Файл исходника fs_interpreter.pas.

    При загрузке полагаю основное время тратилось на функцию frxXmlToStr 4% пятая строчка на скриншоте. К стати, там если детали посмотреть тоже есть на чем с экономить например на Delete-ах из Result-а :) но это мелочи.

    Основное конечно работа интерпретатора при построении отчета.

    PS: Сейчас у меня времени нет чтобы подумать на тем как подправить алгоритм процедуры TfsScript.AddCodeLine и протестировать его. Может из читателей форума кто ни будь что то предложит. А вообще поиграть с программкой AQTime рекомендую всем программистам. Весьма интересное занятие. :)
  • xlaalaaxlaalaa Минск
    отредактировано August 2009
    Девиз: Reporting must be fast! And more and more fast!!!
  • отредактировано 10:39
    В моем случае тоже грузим из файла, который лежит в БД.
        Report.LoadFromStream(Stream);
        InitReport(Report);
    

    Или ты храниш сразу Xml?? У меня храниться в бинарном виде.
  • xlaalaaxlaalaa Минск
    отредактировано August 2009
    Drag написал: »
    В моем случае тоже грузим из файла, который лежит в БД.
        Report.LoadFromStream(Stream);
        InitReport(Report);
    

    Или ты храниш сразу Xml?? У меня храниться в бинарном виде.


    У нас формы Xml грузятся из ресурсных файлов (это что то типа ZIP архивов)
    fReport.Clear;
    fReport.LoadFromStream(strm);
    fReport.PrepareReport(true);
    

    как то так.
  • отредактировано August 2009
    Да, я покопался и нашел вот тут: fs_iilparser.pas
    procedure TfsILParser.DoCompoundStmt(xi: TfsXMLItem; Prog: TfsScript; Statement: TfsStatement);
    var
      i: Integer;
    begin
      for i := 0 to xi.Count - 1 do
        DoStmt(xi[i], Prog, Statement);
    end;
    
    xi.Count у меня 5800, а DoStmt вызывает там этот самый AddCodeLine.
    Я так понял, что именно тут идет обработка всего скрипта (пока не понял для чего).
    Так вот оптимизация того кода мало что дает, ну может выигрыш в несколько секунд.
    Можно ли весь этот процесс избежать вообще?

    P.S. Поставил себе AQTime, так он сказал, что интегрится в мою делфу 2007 не будет, так как не понял версии сервиспака. Я ее переставил, он вроде установился, но в интерфейсе я его не нашел, потом он угробил делфу, пол дня промучался... мож как то можно работать с ним без интеграции?
  • отредактировано 10:39
    Drag написал: »
    Нет, я говорю не про дизайн моду, а про запуск на выполнение.
    А по поводу XML... а можно с этого места подробнее?!
    Может можно изготовить этот XML один раз, а постоянно его просто подсовывать как-то?
    Скрипт работает так, есть базовый XML с описанием языка, этот XML читается и идет разбор самого текста на основе этого XML.
    Причем чтение не последовательное, там будут постоянные поиски и хождения по нодам (что собственно и ест большую часть времени при компиляции).
    Ну и на основе текста и базового шаблона языка строится промежуточный скрипт, который тоже представляет собой XML - он и исполняется.
    Сохранение промежуточного кода конечно возможно, но тут потребуется значительная доработка.

    По поводу оптимизации о которой писал xlaalaa, можно сделать примерно следующие:

    procedure TfsScript.AddCodeLine(const UnitName, APos: String);
    var
      sl: TStringList;
      LineN: String;
      i : Integer;
    begin
      i := FUnitLines.IndexOf(UnitName);
    
      if (i = -1) then
      begin
        sl := TStringList.Create;
        sl.Sorted := True;
        FUnitLines.AddObject(UnitName, sl);
      end else
      begin
        sl := TStringList(FUnitLines.Objects[i]);
      end;
    
      LineN := Copy(APos, 1, Pos(':', APos) - 1);
      if sl.IndexOf(LineN) = -1 then
      begin
        sl.Add(LineN);
      end;
    end;
    
    function TfsScript.IsExecutableLine(LineN: Integer; const UnitName: String = ''): Boolean;
    var
      sl: TStringList;
      i: Integer;
    begin
      Result := False;
    
      i := FUnitLines.IndexOf(UnitName);
      if (i = -1) then Exit;
    
      sl := TStringList(FUnitLines.Objects[i]);
      if sl.IndexOf(IntToStr(LineN)) <> -1 then
        Result := True;
    end;
    
    
    procedure TfsScript.Clear;
    var
      i: Integer;
      item: TObject;
    begin
      i := 0;
      while i < FItems.Count do
      begin
        item := FItems.Objects[i];
        if (item is TfsRTTIModule) or
          ((item is TfsCustomVariable) and
           (TfsCustomVariable(item).AddedBy = TObject(1))) then
          Inc(i)
        else
        begin
          item.Free;
          FItems.Delete(i);
        end;
      end;
      FStatement.Clear;
    
    
      for i := 0 to FUnitLines.Count - 1 do
        FUnitLines.Objects[i].Free;
    
      FUnitLines.Clear;
    
      FErrorPos := '';
      FErrorMsg := '';
      FErrorUnit := '';
    end;
    
    
    procedure TfsScript.ClearItems(Owner: TObject);
    var
        i: Integer;
    begin
      RemoveItems(Owner);
      FStatement.Clear;
    
      for i := 0 to FUnitLines.Count - 1 do
        FUnitLines.Objects[i].Free;
    
      FUnitLines.Clear;
    end;
    

    Т.е. избавляемся от промежуточных присвоений текста, вместо этого храним объекты списков в FUnitLines. И включаем сортировку у локального списка, что значительно снизит время поиска.
    Код особо не проверял, но работать должен.
    Если проблем не возникнет, то возможно включу код в текущую сборку.
  • отредактировано 10:39
    Мда. Товарищи разработчики FastReport 4.0.
    Неужели большие отчеты должны так тормозно загружатся? И ничего с этим нельзя поделать?
  • отредактировано 10:39
    написал: »
    Т.е. избавляемся от промежуточных присвоений текста, вместо этого храним объекты списков в FUnitLines. И включаем сортировку у локального списка, что значительно снизит время поиска.
    Код особо не проверял, но работать должен.
    Если проблем не возникнет, то возможно включу код в текущую сборку.

    Спасибо, сейчас попробую и отпишусь
  • отредактировано 10:39
    ОООО... поразительно! открылся почти моментально!
    Аж настораживает как-то. Ну будем тестить.
    -=Den=-, Спасибо!
  • xlaalaaxlaalaa Минск
    отредактировано 10:39
    Drag написал: »
    P.S. Поставил себе AQTime, так он сказал, что интегрится в мою делфу 2007 не будет, так как не понял версии сервиспака. Я ее переставил, он вроде установился, но в интерфейсе я его не нашел, потом он угробил делфу, пол дня промучался... мож как то можно работать с ним без интеграции?

    Интеграцией в дельфи не пользовался ни разу. С AQTime удобнее работать как с отдельным приложением. Приемы работы с AQTime очень хорошо описаны в документации (правда только на английском).

    Вообще это мощнейший инструмент для разработчиков Delphi, C++, С#. Сего помощью проблемы производительности и утечек памяти щелкаются как семечки :)

    -=Den=- спасибо! тоже будем тестировать, как появится время.

Оставить комментарий

Многофункциональный текстовый редактор. Чтобы отредактировать стиль параграфа, нажмите TAB, чтобы перейти к меню абзаца. Там вы можете выбрать стиль. По умолчанию не выбран ни один стиль. Когда вы выберете текст, появится встроенное меню форматирования. Нажмите TAB, чтобы войти в него. Некоторые элементы, такие как многофункциональные вставки ссылок, картинок, индикаторов загрузки и сообщений об ошибок могут быть вставлены в редактор. Вы можете перемещаться по ним, используя стрелки внутри редактора и удалять с помощью клавиш delete или backspace.