Сроки выполнения программы в MATLAB;странные результаты - PullRequest
10 голосов
/ 07 сентября 2010

У меня есть программа, которую я скопировал из учебника, и которая в разы отличается от времени выполнения программы при вычислении одного и того же с использованием неинициализированного, инициализированного массива и векторов.

Однако, хотя программа работает несколько какожидается, что если запускаться несколько раз, время от времени выдаст сумасшедший результат.Ниже приведена программа и пример сумасшедший результат.

clear all; clc;

% Purpose:
% This program calculates the time required to calculate the squares of
% all integers from 1 to 10000 in three different ways:
% 1. using a for loop with an uninitialized output array
% 2. Using a for loop with a pre-allocated output array
% 3. Using vectors

% PERFORM CALCULATION WITH AN UNINITIALIZED ARRAY
% (done only once because it is so slow)

maxcount = 1;
tic;
for jj = 1:maxcount
    clear square
    for ii = 1:10000
        square(ii) = ii^2;
    end
end
average1 = (toc)/maxcount;

% PERFORM CALCULATION WITH A PRE-ALLOCATED ARRAY
% (averaged over 10 loops)

maxcount = 10;
tic;
for jj = 1:maxcount
    clear square
    square = zeros(1,10000);
    for ii = 1:10000
        square(ii) = ii^2;
    end
end
average2 = (toc)/maxcount;

% PERFORM CALCULATION WITH VECTORS
% (averaged over 100 executions)

maxcount = 100;
tic;
for jj = 1:maxcount
    clear square
    ii = 1:10000;
    square = ii.^2;
end
average3 = (toc)/maxcount;

% Display results
fprintf('Loop / uninitialized array = %8.6f\n', average1)
fprintf('Loop / initialized array =   %8.6f\n', average2)
fprintf('Vectorized =                 %8.6f\n', average3)

Результат - обычный:

Loop / uninitialized array = 0.195286
Loop / initialized array =   0.000339
Vectorized =                 0.000079

Результат - сумасшедший:

Loop / uninitialized array = 0.203350
Loop / initialized array =   973258065.680879
Vectorized =                 0.000102

Почему это происходит? (иногда сумасшедшее число на векторизации, иногда на инициализации цикла)

Где MATLAB "нашел" это число?

Ответы [ 4 ]

3 голосов
/ 07 сентября 2010

Это действительно безумие. Не знаю, что могло вызвать это, и не смог воспроизвести на моем собственном экземпляре Matlab R2010a несколько прогонов, вызванных по имени или через F5.

Вот идея отладки.

При использовании tic / toc внутри скрипта или функции используйте форму "tstart = tic", которая захватывает выходные данные. Это позволяет безопасно использовать вложенные вызовы tic / toc (например, внутри вызываемых функций) и позволяет удерживать несколько начальных и истекших периодов времени и исследовать их программно.

t0 = tic;
% ... do some work ...
te = toc(t0); % "te" for "time elapsed"

Вы можете использовать разные суффиксы "t0_label" для каждого из возвращений tic и toc или сохранять их в векторе, чтобы сохранить их до конца вашего сценария.

t0_uninit = tic;
% ... do the uninitialized-array test ...
te_uninit = toc(t0_uninit);

t0_prealloc = tic;
% ... test the preallocated array ...
te_prealloc = toc(t0_prealloc);

Попросите скрипт взломать отладчик, когда он найдет одно из больших значений.

if any([te_uninit te_prealloc te_vector] > 5)
    keyboard
end

Затем вы можете проверить рабочее пространство и возвращаемые значения из tic, что может дать некоторые подсказки.


РЕДАКТИРОВАТЬ: Вы также можете попробовать протестировать tic () самостоятельно, чтобы увидеть, есть ли что-то странное с вашими системными часами или что-то вызываемое tic / toc. Возвращаемое значение tic () выглядит как родная временная метка. Попробуйте вызвать его много раз подряд и сравнить последующие значения. Если это когда-нибудь пойдет вспять, это было бы удивительно.

function test_tic

t0 = tic;
for i = 1:1000000
    t1 = tic;
    if t1 <= t0
        fprintf('tic went backwards: %s to %s\n', num2str(t0), num2str(t1));
    end
    t0 = t1;
end

На Matlab R2010b (предварительной), который имеет int64 математику, вы можете воспроизвести подобный нелепый результат ТОС по перетасовывают ссылочный крестики значение, чтобы быть «в будущем». Похоже, что эффект от ролловера, как предложил Гэри Комтуа.

>> t0 = tic; toc(t0+999999)
Elapsed time is 6148914691.236258 seconds.

Это говорит о том, что если в таймере, который использовал toc, было какое-то дрожание, вы можете получить опрокидывание, если оно произойдет, пока вы выполняете очень короткие операции. (Я предполагаю, что toc () внутренне делает что-то вроде tic (), чтобы получить значение для сравнения входных данных.) Увеличение количества итераций может привести к тому, что эффект исчезнет, ​​потому что небольшое количество дрожания тактового импульса будет менее значительным как часть более длинного периоды tic / toc. Также объяснил бы, почему вы не видите этого в вашем нераспределенном тесте, который занимает больше времени.


ОБНОВЛЕНИЕ: я смог воспроизвести это поведение. Я работал над некоторым несвязанным кодом и обнаружил, что на одном конкретном десктопе с моделью процессора, которую мы не использовали ранее, четырехъядерным процессором Core 2 Q8400 с частотой 2,66 ГГц, тик давал неточные результаты. Выглядит как системно-зависимая ошибка в tic / toc.

На этой конкретной машине Tic / Toc будет регулярно сообщать о странно высоких значениях, как у вас.

>> for i = 1:50000; t0 = tic; te = toc(t0); if te > 1; fprintf('elapsed: %.9f\n', te); end; end
elapsed: 6934787980.471930500
elapsed: 6934787980.471931500
elapsed: 6934787980.471899000
>> for i = 1:50000; t0 = tic; te = toc(t0); if te > 1; fprintf('elapsed: %.9f\n', te); end; end
>> for i = 1:50000; t0 = tic; te = toc(t0); if te > 1; fprintf('elapsed: %.9f\n', te); end; end
elapsed: 6934787980.471928600
elapsed: 6934787980.471913300
>> 

Это проходит мимо этого. На этом компьютере tic / toc будет регулярно занижать затраченное время для операций, особенно для задач с низкой загрузкой ЦП.

>> t0 = tic; c0 = clock; pause(4); toc(t0); fprintf('Wall    time is %.6f seconds.\n', etime(clock, c0));
Elapsed time is 0.183467 seconds.
Wall    time is 4.000000 seconds.

Таким образом, похоже, что это ошибка в Tic / Toc, связанная с определенными моделями процессоров (или что-то еще, специфичное для конфигурации системы). Я сообщил об ошибке в MathWorks.

Это означает, что Tic / Toc, вероятно, дает вам неточные результаты, даже если он не производит эти безумно большие цифры. В качестве обходного пути, на этом компьютере используйте вместо этого etime (), и время только для более длинных частей работы компенсирует более низкое разрешение etime. Вы можете обернуть его в свои собственные функции tick / tock, которые используют тест for i = 1: 50000, чтобы определить, когда на текущем компьютере нарушен тик, как обычно использовать tic / toc, и предупредить их и вернуться к использованию etime () на сломанных системах.

ОБНОВЛЕНИЕ 2012-03-28: Я уже давно это видел в дикой природе, и, скорее всего, это связано с взаимодействием с таймером производительности высокого разрешения ЦП и масштабированием скорости, а также (в Windows) QueryPerformanceCounter, как здесь описано: http://support.microsoft.com/kb/895980/. Это не ошибка в tic / toc, проблема в функциях ОС, которые вызывает tic / toc. Установка параметра загрузки может обойти это.

2 голосов
/ 07 сентября 2010

Вот моя теория о том, что может происходить, основываясь на этих двух фрагментах данных, которые я нашел:

  • Существует функция maxNumCompThreads, которая контролирует максимальное количество вычислительных потоков, используемых MATLAB для выполнения задач. Цитирование документации:

    По умолчанию MATLAB использует многопоточность возможностей компьютер, на котором он работает.

    Что заставляет меня думать, что, возможно, одновременно запущено несколько копий вашего скрипта.

  • В этой теме новостной группы обсуждается ошибка в более старой версии MATLAB (R14) «в способе, которым MATLAB ускоряет M-код с помощью глобальных структурных переменных», который выглядит как Функции TIC / TOC могут использовать. Было решено отключить ускоритель с помощью недокументированной функции FEATURE :

    feature accel off
    

Соединяя эти две вещи, мне интересно, могут ли несколько версий вашего скрипта, которые работают в рабочей области, одновременно сбрасывать глобальные переменные, используемые функциями TIC / TOC , и сбивать друг друга , Может быть, это не проблема при преобразовании вашего скрипта в функцию, как это делал Amro, поскольку это разделит рабочие пространства, в которых работают две программы (то есть они не будут работать в основной рабочей области).

Это также может объяснить чрезвычайно большие числа, которые вы получаете. Как указали Гэри и Эндрю, эти числа, по-видимому, обусловлены целочисленным эффектом пролонгации (то есть целочисленное переполнение ), при котором время начала (из TIC) больше времени окончания (из TOC ). Это привело бы к огромному числу, которое все еще является положительным, потому что TIC / TOC внутренне используют беззнаковые 64-битные целые числа в качестве временных мер. Рассмотрим следующий возможный сценарий с двумя сценариями, запущенными одновременно в разных потоках:

  1. Первый поток вызывает TIC, инициализируя глобальную переменную начальным тактом (т. Е. Текущим временем).
  2. Первый поток затем вызывает TOC, и немедленное действие, которое может выполнить функция TOC, заключается в получении текущего такта.
  3. Второй поток вызывает TIC, сбрасывая глобальную меру времени начала на текущее время, которое на позже времени, только что измеренного функцией TOC для первого потока.
  4. Функция TOC для первого потока обращается к глобальной мере начала, чтобы получить разницу между ней и мерой, которую она ранее принимала. Эта разница будет приводить к отрицательному числу, за исключением того, что меры времени являются целыми числами без знака. Это приводит к целочисленному переполнению, дающему огромное положительное число для разницы во времени.

Итак, как вы можете избежать этой проблемы? Изменение ваших сценариев на функции, подобные тем, что выполнял Amro, вероятно, является наилучшим выбором, поскольку кажется, что это позволяет обойти проблему и , предотвращая загромождение рабочего пространства. Альтернативный обходной путь, который вы можете попробовать - установить максимальное количество вычислительных потоков в один:

maxNumCompThreads(1);

Это должно препятствовать одновременному запуску нескольких копий вашего сценария в основной рабочей области.

1 голос
/ 08 сентября 2010

Вот гипотеза, которая поддается проверке. В tic () / toc () Matlab должен использоваться таймер высокого разрешения. В Windows, поскольку их возвращаемое значение похоже на тактовые циклы, я думаю, что они используют вызов Win32 QueryPerformanceCounter () или, возможно, что-то еще, попадающее на счетчик меток времени RDTSC ЦП. Они, по-видимому, имеют глюки в некоторых многопроцессорных системах, упомянутых в связанных статьях. Возможно, ваша машина одна из тех, которые получают другие результаты, если планировщик процессов перемещает процесс Matlab из ядра в ядро.

http://msdn.microsoft.com/en-us/library/ms644904(VS.85).aspx

http://www.virtualdub.org/blog/pivot/entry.php?id=106

Это зависит от конфигурации оборудования и системы, что объясняет, почему другие авторы не смогли воспроизвести его.

Попробуйте использовать диспетчер задач Windows, чтобы установить привязку процесса Matlab.exe к одному ЦП. (На вкладке «Процессы» щелкните правой кнопкой мыши файл MATLAB.exe, «Установить сходство ...», снимите флажок для всех, кроме ЦП 0.) Если сумасшедшее время отсчитывается, пока установлено сходство, похоже, что вы нашли причину.

Несмотря на это, обходной путь выглядит просто для увеличения maxcount, поэтому вы рассчитываете более длительные фрагменты работы, и шум, который вы, очевидно, получаете в tic () / toc (), является небольшим по сравнению с измеренным значением. (Вы не хотите возиться с привязкой к процессору; предполагается, что Matlab легко запускается.) Если есть проблема, которая вызывает переполнение int, другие небольшие положительные числа также немного подозрительны. Кроме того, отсчет времени в высоком разрешении на языке высокого уровня, таком как Matlab, немного проблематичен. Синхронизация рабочих нагрузок до нескольких сотен микросекунд подвергает их шуму от других переходных процессов в состоянии вашей машины.

1 голос
/ 07 сентября 2010

Существует как минимум два возможных источника ошибок.Можете ли вы попытаться провести различие между 'tic / toc' и 'fprintf', просто взглянув на вычисленные значения без их форматирования

Я не понимаю скобки вокруг 'toc', но они не должны причинять вред.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...