Блокноты MuPAD® будут демонтированы в будущем релизе. Используйте live скрипты MATLAB® вместо этого.
Live скрипты MATLAB поддерживают большую часть функциональности MuPAD, хотя существуют некоторые различия. Для получения дополнительной информации смотрите, Преобразовывают Notebook MuPAD в Live скрипты MATLAB.
Профилирование является способом измериться, где программа проводит время. MuPAD® обеспечивает функцию prog::profile
, чтобы помочь вам идентифицировать узкие места производительности в своем коде. Используйте эту функцию, чтобы анализировать производительность сложных вложенных вызовов процедуры. Для более простых фрагментов кода измерение времен выполнения более удобно и может дать вам достаточно информации, чтобы идентифицировать узкие места производительности.
Функция prog::profile
оценивает код, который вы хотите профилировать, и возвращает профильный отчет. Отчет содержит:
Таблица, показывающая время ваш код, потраченный на каждую функцию (общее количество и усредненный на один вызов), количество вызовов этой функции, дочерних элементов этой функции, и так далее. Информация для наиболее в большой степени используемых функций появляется на верхних строках таблицы. Первая строка в этой таблице представляет общее время выполнения.
График зависимости, показывающий саму функцию, функции, которые это вызывает (дочерние элементы) и функции, которые вызывают эту функцию. График также показывает синхронизацию и количество призывов к каждой функции.
По умолчанию prog::profile
не измеряет уровень одного вызовов функций ядра.
Однако, когда prog::profile
измеряет уровень библиотечных функций, это также распечатывает накопленное время, которое система проводит в функциях ядра. Чтобы измерить уровень одного вызова функции ядра, используйте prog::trace
, чтобы проследить ту функцию ядра.
Предположим, что вы хотите записать процедуру, которая проверяет, появляется ли каждое целое число от 1 до 1 000 в 1000×1000 матрица случайных целых чисел. Прямой подход должен записать процедуру, которая проверяет каждый элемент матрицы, продолжающей строка строкой и столбцом столбцом:
f := proc(M, n, x) begin for j from 1 to n do for k from 1 to n do if M[j, k] = x then return(TRUE) end_if end_for end_for; return(FALSE) end_proc:
Используйте linalg::randomMatrix
, чтобы создать 1000×1000 матрица случайных целых чисел:
matrixSize := 1000: M := linalg::randomMatrix(matrixSize, matrixSize, Dom::Integer):
Затем вызовите процедуру f
1000 раз, чтобы проверять, появляется ли каждый номер от 1 до 1 000 в той матрице:
g := proc() begin f(M, matrixSize, i) $ i = 1..1000 end_proc:
Измерение времени должно было запустить процедуру, g
показывает, что процедура требует оптимизации. Несмотря на то, что узкое место производительности в этой процедуре очевидно, не всегда легко идентифицировать узкие места производительности в более сложных процедурах. Функция time
не указывает, где процедура проводит большую часть своего времени выполнения:
time(g())
62023.876
Чтобы получить полный профильный отчет, который показывает синхронизации для всех внутренних вызовов функции, используйте prog::profile
:
prog::profile(g()):
percent usage of all
| time self per single call
| | time self
| | | time children per single call
| | | | time children
| | | | | calls/normal exit
| | | | | | calls/remember exit
| | | | | | | calls/errors
| | | | | | | | [index] function name
--------------------------------------------------------------------------------------------------------------------
100.0 109982.9 109982.9 . . 1 . . [0] procedure entry point
--------------------------------------------------------------------------------------------------------------------
45.9 . 50467.2 . 27149.6 3019825 . . [1] (Dom::Matrix(Dom::Integer))::_index_intern
19.7 . 21689.3 . 5460.3 3019825 . . [2] Dom::Integer::coerce
16.7 . 18373.1 . 77616.9 3019825 . . [3] (Dom::Matrix(Dom::Integer))::_index
12.7 14.0 13984.8 96.0 95990.0 1000 . . [4] f
5.0 . 5460.3 . . 3019825 . . [5] Dom::Integer::convert
. 8.0 8.0 109974.9 109974.9 1 . . [6] g
--------------------------------------------------------------------------------------------------------------------
index %time self children called [index] name
---------------------------------------------------------------------------------------------
[0] 100.0 109982.8 0 1 procedure entry point
8.0 109974.8 1 [6] g
---------------------------------------------------------------------------------------------
50467.24 27149.65 3019825 [3] (Dom::Matrix(Dom::Integer))::_index
[1] 45.9 50467.24 27149.65 3019825 (Dom::Matrix(Dom::Integer))::_index_intern
21689.30 5460.346 3019825 [2] Dom::Integer::coerce
---------------------------------------------------------------------------------------------
21689.30 5460.346 3019825 [1] (Dom::Matrix(Dom::Integer))::_index_intern
[2] 19.7 21689.30 5460.346 3019825 Dom::Integer::coerce
5460.346 0 3019825 [5] Dom::Integer::convert
---------------------------------------------------------------------------------------------
18373.13 77616.89 3019825 [4] f
[3] 16.7 18373.13 77616.89 3019825 (Dom::Matrix(Dom::Integer))::_index
50467.24 27149.65 3019825 [1] (Dom::Matrix(Dom::Integer))::_index_intern
---------------------------------------------------------------------------------------------
13984.84 95990.02 1000 [6] g
[4] 12.7 13984.84 95990.02 1000 f
18373.13 77616.89 3019825 [3] (Dom::Matrix(Dom::Integer))::_index
---------------------------------------------------------------------------------------------
5460.346 0 3019825 [2] Dom::Integer::coerce
[5] 5.0 5460.346 0 3019825 Dom::Integer::convert
---------------------------------------------------------------------------------------------
[6] 0.0 8.0 109974.8 1 g
13984.84 95990.02 1000 [4] f
---------------------------------------------------------------------------------------------
Time sum: 109982.873 ms
Верхние строки профильного отчета указывают, что процедура проводит большую часть своего времени, получая доступ к каждому элементу матрицы. Чтобы улучшать производительность, перепишите процедуру так, чтобы это могло получить доступ к меньшему количеству элементов матрицы в каждом вызове процедуры f
. Например, используйте алгоритм на основе метода деления пополам:
f := proc(M, n, x) begin if (M[1] - x)*(M[n] - x) > 0 then return(FALSE) elif (M[1] - x)*(M[n] - x) = 0 then return(TRUE); else a := 1: b := n: while (b - a > 1) do if is(b - a, Type::Odd) then c := a + (b - a + 1)/2 else c := a + (b - a)/2 end_if; if M[c] - x = 0 then return(TRUE) elif (M[a] - x)*(M[c] - x) < 0 then b := c: else a := c: end_if; end_while; end_if; return(FALSE) end_proc:
Прежде, чем вызвать процедуру f
, необходимо преобразовать матричный M
в список и вид тот список. Сортировка списка, который содержит 104 записи, является дорогой операцией. В зависимости от количества вызовов процедуры f
эта операция может потенциально устранить увеличение производительности, которую вы получаете путем улучшения процедуры сам f
:
g := proc() local M1; begin M1 := sort([op(M)]): f(M1, matrixSize^2, i) $ i = 1..1000 end_proc:
Для них конкретный матричный размер и количество вызовов f
, реализовывая bisectional алгоритм все еще эффективны несмотря на время, требуемое отсортировать список:
time(g())
3840.24
Профильный отчет показывает, что процедура тратит наиболее часто выполнение вызовы функции g
и op
. Это вызвано тем, что реализация алгоритма двоичного поиска добавила новые дорогие операции в g
(преобразование матрицы к списку и затем сортировке списка). Профильный отчет, сгенерированный для вызова процедуры g()
, очень длинен. Этот пример показывает только верхнюю часть отчета:
prog::profile(g()):
percent usage of all
| time self per single call
| | time self
| | | time children per single call
| | | | time children
| | | | | calls/normal exit
| | | | | | calls/remember exit
| | | | | | | calls/errors
| | | | | | | | [index] function name
-------------------------------------------------------------------------------------------------
100.0 3884.2 3884.2 . . 1 . . [0] procedure entry point
-------------------------------------------------------------------------------------------------
56.1 2180.1 2180.1 1704.1 1704.1 1 . . [1] g
33.0 1280.1 1280.1 188.0 188.0 1 . . [2] (Dom::Matrix(Dom::Integer))::op
6.1 0.2 236.0 . . 1000 . . [3] f
3.2 0.1 124.0 . . 1000 . . [4] `p -> [coeff(p, All)][2..-1]`
1.5 0.1 60.0 . . 1000 . . [5] `l -> l.[Rzero $ r - nops(l)]`
0.1 2.0 4.0 . . 2 . . [6] Dom::Integer::hasProp
. . . . . 2 . . [7] DomainConstructor::hasProp
. . . . . . 9981 . [8] is
-------------------------------------------------------------------------------------------------
Рекомендуемый подход для того, чтобы улучшать производительность вашего кода должен использовать функции MuPAD, если это возможно. Например, MuPAD обеспечивает функцию has
для проверки, содержит ли один объект MuPAD другой объект MuPAD. Перепишите свой код с помощью функции has
и комбинируя процедуры f
и g
:
g := proc() local M1; begin M1 := {op(M)}: has(M1, i) $ i = 1..1000 end_proc:
Эта процедура также преобразовывает матричный M
в набор. Преобразование матрицы к набору может уменьшать число элементов. (MuPAD удаляет дублирующиеся элементы набора.)
Время выполнения для вызова процедуры g()
является самым коротким среди этих трех реализаций:
time(g())
1520.095
Профильный отчет показывает, что процедура проводит большую часть своего времени выполнения, получая доступ 1000×1000 матрица случайных целых чисел и преобразовывая его в набор. Этот пример показывает только верхнюю часть профильного отчета:
prog::profile(g()):
percent usage of all
| time self per single call
| | time self
| | | time children per single call
| | | | time children
| | | | | calls/normal exit
| | | | | | calls/remember exit
| | | | | | | calls/errors
| | | | | | | | [index] function name
----------------------------------------------------------------------------------------------
100.0 1556.1 1556.1 . . 1 . . [0] procedure entry point
----------------------------------------------------------------------------------------------
78.9 1228.1 1228.1 188.0 188.0 1 . . [1] (Dom::Matrix(Dom::Integer))::op
9.0 140.0 140.0 1416.1 1416.1 1 . . [2] g
8.2 0.1 128.0 . . 1000 . . [3] `p -> [coeff(p, All)][2..-1]`
3.9 0.1 60.0 . . 1000 . . [4] `l -> l.[Rzero $ r - nops(l)]`
. . . . . 2 . . [5] Dom::Integer::hasProp
. . . . . 2 . . [6] DomainConstructor::hasProp
----------------------------------------------------------------------------------------------