Смекни!
smekni.com

Программирование и разработка приложений в Maple (стр. 130 из 135)

В некоторых версиях релизов 6-10 пакета использование процедуры StatLib может в ряде случаев вызывать критические ошибки, связанные, прежде всего, с переполнением пакетного стэка. В этом случае рекомендуется выполнить вызов StatLib(L, abend) с последующим выполнением предложения restart пакета. Данный прием позволяет сохранять в указанных статистических файлах по меньшей мере информацию по количеству вызовов профилированных процедур на момент аварийной ситуации. Последующий вызов StatLib(L) обеспечивает возобновление процесса профилирования с прерванного момента. Вышеупомянутые ошибочные ситуации могут быть в значительной степени объяснены следующим образом.

Наш достаточно длительный опыт использования Maple релизов 4-10 в различных приложениях, включая развитие средств, расширяющих основные средства пакета, со всей определенностью выявил одно довольно существенное обстоятельство. Многие из часто используемых стандартных Maple-средств были обеспечены недостаточно развитой системой обработки специальных и ошибочных ситуаций, которые в большинстве случаев завершаются ошибками с очевидно некорректной диагностикой, например, "Execution stopped: Stack limit reached" с последующим аварийным завершением текущего сеанса. Таким образом, или Maple имеет стэк недостаточной глубины, или вышеупомянутая ситуация была вызвана (в отсутствие каких-либо циклических вычислений) ошибкой, имеющей причину некоторого другого характера. К сожалению, увеличение номеров релизов Maple пока сопровождается уменьшением их ошибкоустойчивости, да и не только этого.

Реализация алгоритма процедуры StatLib существенно базируется на представленных в книгах [41,103] процедурах DoF, Fremove, Plib, belong, _SL, tabar, а также на специальных процедурах profile и unprofile пакета для профилирования вызовов процедур. При использовании StatLib процедуры имеет место замедление вычислений и увеличение используемой памяти, величина которых зависит, прежде всего, как от количества профилируемых процедур, так и частоты их использования. Однако, ввиду относительно небольших библиотек пользователя (до 600 – 700 процедур и частоте их использования не более 600 за сеанс, исключая циклические конструкции) это обстоятельство не приводит к критическим ситуациям, связанным с использованием основных ресурсов компьютера и времени обработки. В частности, использование данного механизма для нашей библиотеки с процедурами (свыше 720), представленными в книге [103] и прилагаемой к ней Библиотеке, не дает каких-либо оснований рассматривать описанный механизм профилирования в качестве причины достаточно серьезных дополнительных издержек основных ресурсов ПК, правда, эксперименты производились на Pentium 4 c частотой 3 GHz, RAM 1 GB и HDD 120 GB.

Механизм использования StatLib процедуры сводится к следующему. В самом начале сеанса работы с пакетом выполняется вызов процедуры StatLib(L {, P}), где L – имя анализируемой библиотеки пользователя, удовлетворяющей указанным выше условиям

(P-аргумент может определять список имен процедур из библиотеки L или вне ее). Перед завершением текущего сеанса работы выполняется вызов процедуры StatLib(L, 1), который обеспечивает сохранение статистической информации в пяти специальных файлах с именами "$@#_h" (где h ∈ {depth, calls, bytes, maxdepth, time}), помещаемых в подкаталог с библиотекой L. В любой момент (динамически либо разово) посредством вызовов процедуры StatLib(L, T, {2|name} {, m}) можно получать справку по характеристикам вызовов процедур библиотеки в указанных выше разрезах.

Наиболее эффективным режимом является следующий. Каждый очередной сеанс работы с пакетом начинается вызовом StatLib(L), после которого производится текущая работа в среде пакета. Периодически рекомендуется производить пары вызовов {StatLib(L, 1), StatLib(L)} для обеспечения надежности по сохранности результатов профилирования процедур библиотеки. Перед завершением текущего сеанса выполняется вызов процедуры StatLib(L, 1), обеспечивая прекращение процесса профилирования и сохранение его результатов в упомянутых файлах. Просмотр результатов профилирования в упомянутых разрезах рассматривался нами выше. Анализ собранной статистической информации дает возможность улучшать как организацию библиотеки в целом, так и эффективность составляющих ее отдельных процедур, имеющих достаточно высокую частоту использования либо существенно использующих основные ресурсы компьютера.

Опыт использования процедуры StatLib со всей определенностью говорит о ее довольно высокой эффективности в случае решения проблем оптимизации библиотек пользователя. Механизм и методы использования процедуры StatLib достаточно подробно рассмотрены в наших предыдущих книгах [29-33,39,42-46,103]. Тогда как представленные ниже примеры достаточно наглядно иллюстрируют принципы и результаты применения процедуры StatLib.

StatLib := proc(L::{string, symbol})

local a k h S P K G H t pf unp u V T R, , , , , , , , , , , , , , , W, Z calls1 bytes1 depth1, , , , maxdepth1 time1, ; global profile_maxdepth profile_calls profile_bytes profile_depth profile_time, , , , , `$Art16_Kr9` calls2 bytes2 depth2 maxdepth2 time2, , , , , ; unp := ( ) → unassign '( `$Art16_Kr9`', 'profile_proc', op(T), seq(cat(profile_ k, ), k = R));

`if`(nargs = 2 and args 2[ ] = 'abend',

RETURN(unprofile( ), unp( ), "Abend! Execute `restart` command!",)

NULL);

W := table([1 = true, 2 =

`if`(nargs = 2 and type(args 2[ ], {'binary', 'list'({'symbol'})}), true false, ), 3 = `if`( nargs = 3 and member(args 2[ ], {'bytes', 'maxdepth', 'calls', 'time', 'depth'}) and (args 3[ ] = 2 or type(args 3[ ], 'symbol')), true false, ) 4, = `if`( nargs = 4 and member(args[2], {'bytes', 'maxdepth', 'calls', 'time', 'depth'}) and args 3[ ] = 2 and type(args 4[ ], 'numeric'), true false, )]);

`if`(W nargs[ ] = true, unassign 'W'( ), ERROR("invalid arguments %1 have been passed to the StatLib"[args] );, ) assign(K = Plib(L)), assign(R = ['bytes', 'calls', 'depth', 'maxdepth', 'time']), assign('calls1' = cat(K, "/$@_", R[2]), 'bytes1' = cat(K, "/$@_", R[1]),

'depth1' = cat(K, "/$@_", R[3]), 'maxdepth1' = cat(K, "/$@_", R[4]),

'time1' = cat(K, "/$@_", R[ ]5 )), assign(T = [seq(cat(R h[ ], `2`), h = 1 .. 5)],

V = ['bytes1', 'calls1', 'depth1', 'maxdepth1', 'time1'],

Z = [seq(cat(profile_, R h[ ]), h = 1 .. 5)], G = [ ]); `if`(nargs = 2 and args[2] = 0, RETURN(WARNING("datafiles with statistic&bsol; s have been removed out of directory with library <%1>", L), unprofile( ), op(map(Fremove, [bytes1 calls1 depth1 maxdepth1 time1, , , , ])), unp( )), NULL);

if nargs = 2 and args 2[ ] = 1 then

`if`(type(eval(profile_calls), 'table'), assign(

'calls2' = eval cat(( profile_, R[ ]2 )),

'bytes2' = eval cat(( profile_, R[ ]1 )),

'depth2' = eval cat(( profile_, R[ ]3 )),

'maxdepth2' = eval cat(( profile_, R[4])),

'time2' = eval(cat(profile_, R[5]))),

ERROR "profiling does not exist" );( )

(proc() save maxdepth2 maxdepth1, ; save calls2 calls1, ;

save bytes2, bytes1; save depth2 depth1, ; save time2 time1,

end proc )( ) RETURN unprofile( ), ( , unp( ),

WARNING("profiling of library <%1> has been completed", L)) else NULL end if;

if nargs = 3 and belong(cat(``, args 2[ ]), R) and member(whattype args[3]( ), {'symbol', 'string'}) then assign('`$Art16_Kr9`' = eval cat(( profile_, args 2[ ])), pf = cat(K, "/$@_", args[2])), `if`(type(eval(`$Art16_Kr9`), 'table'), NULL, `if`(DoF(pf) = 'file', [(proc() read pf end proc )( ), assign('`$Art16_Kr9`' = eval cat( ,( `` args 2[ ], `2`)))],

RETURN "a profiling information does not exist"));( ) assign(a = [cat(``, args 2[ ]), `$Art16_Kr9`[cat "",( args 3[ ])]]), RETURN(

`if`(type(a[2], 'numeric'), a, "procedure has been not profiled"),

`if`(type(eval(profile_proc ), 'symbol'), unp( ), NULL)) else NULL

end if;

if 3 ≤ nargs and belong(cat(``, args 2[ ]), R) and args 3[ ] = 2 then

`if`(nargs = 4 and type(args[4], 'numeric'), assign(a = args[4]), assign(a = 0 )) ;

assign(pf = cat(K, "/$@_" args[2] ,, )

'`$Art16_Kr9`' = eval cat(( profile_, args 2[ ]))), `if`( type(eval(`$Art16_Kr9`), 'table'), NULL, `if`(DoF(pf) = 'file', [

(proc() read pf end proc )( ),

assign('`$Art16_Kr9`' = eval cat( ,( `` args 2[ ], `2`)))], RETURN "a profiling information does not exist"));( )

RETURN(

tabar(`$Art16_Kr9`, 'Procedures', cat(`Procedure's `, args 2[ ]), a),

`if`(type(eval(profile_proc ), 'symbol'), unp( ), NULL)) else NULL

end if;

`if`(K ≠ false, [assign(P = march '( list K', )), assign(' 'h = nops(P))], ERROR(

"library <%1> does not exist or is not linked with the main Maple library", L))

;

`if`(nargs = 2 and type(args 2[ ], 'list'({'symbol'})), assign(S = args 2[ ]), assign(S

= [ seq(`if`(P k[ ][ ]1 [1 .. 2] ≠ ":-", cat(``, P k[ ][ ]1 [1 .. -3]), NULL), k = 1 .. h)]))

;

for k in S do

try `if`(type(eval( )k , 'procedure'), assign(' 'G = [op(G), k]), NULL) catch "": NULL "Exception handling with program modules"( ) end try end do;

`if`(G = [ ], ERROR("procedures ordered for profiling do not exist both in libr&bsol; ary <%1> and in libraries logically linked with the main Maple library", L, unprofile( ), unp( )), NULL);

try if DoF(calls1) = 'file' then null((proc() profile(op(G)); seq((proc( )x read x end proc )(eval(V h[ ])), h = 1 .. 5); seq(_SL(Z, eval(T h[ ]), h), h = 1 .. 5)

end proc )( ))

else profile op(( G))

end if

catch "%1 is already being profiled":

WARNING "profiling is already being executed!"( ) end try

end proc

> restart; StatLib(UserLib);

> MkDir("C:/Temp/Art/Kr"), type("C:&bsol;Temp/Art/Kr", dir), type("C:/Temp/Art/Kr", file);

"c:&bsol;temp&bsol;art&bsol;kr", true, false

> StatLib(UserLib, calls, 2, 7);

Procedures Procedure's calls

     Red_n 33 

     Case 31 

     Subs_all1 16 

     Subs_All 16 

     Search 10 

     holdof 9 

 

 

 CF 7 

> StatLib(UserLib, time, Case); ⇒ [time, 0.0]

> StatLib(UserLib, bytes, StatLib); ⇒ [bytes, 17980]

> seq(StatLib(UserLib, calls, h), h = [belong, tabar, Case, CF]);

[calls, 4], [calls, 1], [calls, 61], [calls, 7]

> StatLib(UserLib, time, 2, 0.05);

Procedures Procedure's time

     Adrive 0.157 

 

 

 tabar 0.062 

> StatLib(UserLib, calls, 2, 20);

Procedures Procedure's calls

     Case 76 

     Red_n 33 

 

 

 sub_1 20 

> StatLib(UserLib, bytes, 2, 20000);

Procedures Procedure's bytes

     SLj 3591160 

     tabar 2097700 

     Red_n 355168 

     Case 176172 

    type/nestlist 115256 

     Search 74416 

     Adrive 64752 

     StatLib 60944 

     Plib 42456 

     Subs_all1 38856 

     type/dir 35676 

     CF 35372 

     belong 33132 

     sub_1 28392 

 

 

 type/file 20244 

> StatLib(UserLib, 1);

Warning, profiling of library <UserLib> has been completed [Новый Maple-сеанс:

> StatLib(UserLib); CureLib("C:&bsol;rans&bsol;academy&bsol;libraries&bsol;ArtKr", x, y):

Warning, library file <C:/rans&bsol;academy/libraries&bsol;ArtKr&bsol;Maple.ind> does not exist Warning, Analysis of contents of library lib-file is being done. Please, wait!

Warning, library contains multiple entries of the following means

[Atr, CCM, CureLib, Currentdir, DAclose, DAopen, DAread, DUlib, FSSF, F_atr1, F_atr2,

FmF, Imaple, Is_Color, LibElem, LnFile, ModFile, NLP, ParProc1, RTfile, Reduce_T, SDF, SSF, Suffix, Uninstall, Vol, Vol_Free_Space, WD, WS, cdt, conSA, dslib, ewsc, gelist, sfd, mapTab, readdata1, redlt, sorttf, type/dir, type/...]; the sorted nested list of their names with multiplicities appropriate to them is in predefined variable `_mulvertools`

Warning, Analysis of contents of library lib-file has been completed! > _mulvertools;

[[F_atr2, 6], [Atr, 4], [CureLib, 3], [FSSF, 3], [SDF, 3], [SSF, 3], [Suffix, 3], [conSA, 3],

[ewsc, 3], [gelist, 3], [sorttf, 3], [type/file, 3], [CCM, 2], [Currentdir, 2], [DAclose, 2],

[DAopen, 2], [DAread, 2], [DUlib, 2], [F_atr1, 2], [FmF, 2], [Imaple, 2], [Is_Color, 2],

[LibElem, 2], [LnFile, 2], [ModFile, 2], [NLP, 2], [ParProc1, 2], [RTfile, 2], [dslib, 2],

[Reduce_T, 2], [Uninstall, 2], [Vol, 2], [Vol_Free_Space, 2], [WD, 2], [WS, 2], [cdt, 2],

[mapTab, 2], [readdata1, 2], [redlt, 2], [sfd, 2], [type/dir, 2]]

> SLj([[Vic, 63], [Gal, 58], [Sv, 38], [Arn, 42], [Art, 16], [Kr, 9]], 2);

[[Kr, 9], [Art, 16], [Sv, 38], [Arn, 42], [Gal, 58], [Vic, 63]] > StatLib(UserLib, calls, 2, 15);

Procedures Procedure's calls

     Case 96 

     Red_n 39 

     sub_1 26 

     Search 23 

     Subs_all1 19 

     Subs_All 19 

 

 

 belong 15 

> StatLib(UserLib, bytes, 2, 63000);

Procedures Procedure's bytes

     SLj 7143544 

     tabar 4929356 

     Red_n 407032 

    type/nestlist 340600 

     Case 252076 

     Search 99476 

     Adrive 84024 

     StatLib 82572 

 

 

 Plib 67216 

> StatLib(UserLib, 0); Warning, datafiles with statistics have been removed out of directory with library <UserLib>

Ввиду пояснений, сделанных выше, примеры данного фрагмента достаточно прозрачны и не требуют каких-либо дополнительных пояснений. В частности, представленная процедура StatLib весьма эффективно использовалась для улучшения функциональных характеристик пользовательской Библиотеки UserLib, содержащей процедуры, представленные в наших книгах [41,103].