Std :: vector заполнения время от 0 мс до 16 мс после определенного порога? - PullRequest
1 голос
/ 11 июля 2010

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

Это в основном добавляет положение мыши на MouseMove. Эта точка является точкой USERPOINT и имеет маркеры Безье, потому что в конечном итоге я сделаю Безье, и поэтому я должен перенести их в вектор.

Так что в основном MousePos -> USERPOINT. USERPOINT добавляется к std::vector<USERPOINT>. Затем в моей функции UpdateShape () я делаю это:

DrawingPoints определяется следующим образом:

std::vector<std::vector<GLdouble>> DrawingPoints;


Contour[i].DrawingPoints.clear();



 for(unsigned int x = 0; x < Contour[i].UserPoints.size() - 1; ++x)
         SetCubicBezier(
             Contour[i].UserPoints[x],
             Contour[i].UserPoints[x + 1],
             i);

SetCubicBezier () в настоящее время выглядит так:

void OGLSHAPE::SetCubicBezier(USERFPOINT &a,USERFPOINT &b, int &currentcontour )
{
std::vector<GLdouble> temp(2);

    if(a.RightHandle.x == a.UserPoint.x && a.RightHandle.y == a.UserPoint.y 
        && b.LeftHandle.x == b.UserPoint.x && b.LeftHandle.y == b.UserPoint.y )
    {

        temp[0] = (GLdouble)a.UserPoint.x;
        temp[1] = (GLdouble)a.UserPoint.y;

        Contour[currentcontour].DrawingPoints.push_back(temp);

        temp[0] = (GLdouble)b.UserPoint.x;
        temp[1] = (GLdouble)b.UserPoint.y;


        Contour[currentcontour].DrawingPoints.push_back(temp);

    }
    else
    {
         //do cubic bezier calculation
        }

Так что по причине кубического Безье мне нужно сделать USERPOINTS в GlDouble [2] (поскольку GLUTesselator принимает статический массив double.

Так что я сделал некоторое профилирование. На ~ 100 баллов, код:

 for(unsigned int x = 0; x < Contour[i].UserPoints.size() - 1; ++x)
         SetCubicBezier(
             Contour[i].UserPoints[x],
             Contour[i].UserPoints[x + 1],
             i);

Потребовалось 0 мс для выполнения. затем около 120, он прыгает до 16 мс и никогда не оглядывается назад. Я уверен, что это связано с std :: vector. Что я могу сделать, чтобы он оставался на 0мс. Я не возражаю против использования большого количества памяти при генерации формы, а затем при удалении излишка, когда форма завершена, или что-то вроде этого.

Ответы [ 4 ]

12 голосов
/ 11 июля 2010

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

А именно, таймеры обычно не имеют хорошего разрешения. Ваши результаты до 16 мс, вероятно, просто на самом деле 1 мс - 15 мс неправильно сообщается в 0 мс. В любом случае, если бы мы могли рассказать вам, как сохранить его на 0 мс, мы были бы богатыми и знаменитыми.

Вместо этого выясните, какие части цикла занимают больше всего времени, и оптимизируйте их. Не работайте в направлении произвольной меры времени. Я бы порекомендовал получить хороший профилировщик, чтобы получить точные результаты. Тогда вам не нужно угадывать, что медленно (что-то в цикле), но вы можете увидеть, какая часть медленная.

1 голос
/ 12 июля 2010

Если вы на самом деле синхронизировали только второй фрагмент кода (как вы указали в своем посте), то вы, вероятно, просто читаете из вектора. Это означает, что причиной не может быть стоимость перераспределения вектора. В этом случае это может произойти из-за проблем с кэшем ЦП (т. Е. Небольшие наборы данных могут быть прочитаны с молниеносной скоростью из кэша процессора, но всякий раз, когда набор данных больше, чем кэш [или когда поочередно производится чтение из разных мест памяти), процессор должен получить доступ к оперативной памяти, которая значительно медленнее, чем доступ к кэшу.

Если часть кода, которую вы профилировали, добавляет данные к вектору, тогда используйте std :: vector :: reserve () с соответствующей емкостью (числом ожидаемых записей в векторе) перед заполнением.

Однако рассмотрим два общих правила для профилирования / бенчмаркинга:

1) Используйте методы измерения времени с высокой точностью разрешения (как уже говорилось, разрешение вашего таймера слишком низкое)

2) В любом случае, запустите фрагмент кода более одного раза (например, 100 раз), получите общее время всех запусков и разделите его на количество запусков. Это даст вам некоторые реальные цифры.

1 голос
/ 12 июля 2010

Вы можете использовать vector::reserve(), чтобы избежать ненужных перераспределений в DrawingPoints:

Contour[i].DrawingPoints.reserve(Contour[i].size());    
for(unsigned int x = 0; x < Contour[i].UserPoints.size() - 1; ++x) {
   ...
}
0 голосов
/ 13 июля 2010

Здесь много догадок.Хорошие догадки, я думаю, но, тем не менее, догадки.И когда вы пытаетесь измерить время, которое занимают функции, это не говорит вам, как они его принимают.Вы можете увидеть, если вы попробуете разные вещи, которые изменят время, и из этого у вас может быть какое-то предположение о том, что отнимало время, но вы не можете быть в этом уверены.что занимает время, вам нужно поймать его, когда оно занимает это время, и выяснить наверняка, что оно делает.Один из способов - пошагово выполнить код на этом уровне инструкций, но я подозреваю, что об этом не может быть и речи.Следующий лучший способ - получить образцы стеков.Вы можете найти профилировщики, основанные на образцах стека.Лично я полагаюсь на ручную технику по причинам, указанным здесь .

Обратите внимание, что на самом деле речь не идет об измерении времени.Речь идет о том, чтобы выяснить, почему тратится это дополнительное время, а это совсем другой вопрос.

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