В некоторых версиях релизов 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\ 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\ 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:\Temp/Art/Kr", dir), type("C:/Temp/Art/Kr", file); "c:\temp\art\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:\rans\academy\libraries\ArtKr", x, y): Warning, library file <C:/rans\academy/libraries\ArtKr\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].