Quadpart c что это
Манипулирование LARGE_INTEGERS
Я конвертирую код с C на С++ в MS dev studio под win32. В старом коде я делал некоторые высокоскоростные тайминги с помощью QueryPerformanceCounter() и делал несколько манипуляций с полученными значениями __int64, в частности минусом и делением. Но теперь под С++ я вынужден использовать LARGE_INTEGER, потому что это возвращает QueryPerformanceCounter(). Но теперь на строках, где я пытаюсь выполнить некоторые простые математические вычисления, я получаю сообщение об ошибке:
ошибка C2676: двоичный ‘-‘: ‘LARGE_INTEGER’ не определяет этот оператор или преобразование в тип, приемлемый для предопределенного оператора
Я попытался передать переменные в __int64, но затем получим:
ошибка C2440: “тип cast”: невозможно преобразовать из “LARGE_INTEGER” в “__int64”
LARGE_INTEGER – это объединение 64-разрядного целого числа и пары 32-разрядных целых чисел. Если вы хотите выполнить 64-разрядную арифметику на одном, вам нужно выбрать 64-битный int из объединения.
Поскольку QuadPart определяется как LONGLONG, то же самое, что __ int64.
Как говорится в Документация в разделе Примечания:
Структура LARGE_INTEGER на самом деле является объединением. Если ваш компилятор имеет встроенную поддержку для 64-битных целых чисел, используйте член QuadPart для хранения 64-битного целого числа. В противном случае используйте элементы LowPart и HighPart для хранения 64-битного целого числа.
Итак, если ваш компилятор поддерживает 64-битные целые числа, используйте quadPart следующим образом:
В дополнение к ответам, если вы хотите построить LARGE_INTEGER со значением, отличным от нуля, вы можете назначить детали с низким и высоким параметрами отдельно. LowPart является первым, как определено в объединении, и единственная highPart подписана.
Как использовать QueryPerformanceCounter?
недавно я решил, что мне нужно перейти от использования миллисекунд к микросекундам для моего класса таймера, и после некоторых исследований я решил, что QueryPerformanceCounter, вероятно, моя самая безопасная ставка. (Предупреждение о Boost::Posix то, что он может не работать на Win32 API, немного отпугнуло меня). Однако, я не совсем уверен, как это реализовать.
4 ответов:
эта программа должна выводить число, близкое к 1000 (Windows sleep не так точен, но он должен быть похож на 999).
The StartCounter() функция записывает количество тиков счетчик производительности имеет в CounterStart переменной. Элемент GetCounter() функция возвращает количество миллисекунд, начиная с StartCounter() последний раз вызывался как двойник, так что если GetCounter() возвращает 0.001, то это было около 1 микросекунды с StartCounter() называлась.
если вы хотите иметь вместо того, чтобы затем использовать таймер секунд изменить
или если вы хотите микросекунды, то используйте
но на самом деле речь идет об удобстве, так как он возвращает двойной.
использование (скобки для предотвращения переопределений):
вывод из примера использования:
предполагая, что вы находитесь на Windows (если это так, вы должны пометить свой вопрос как таковой!), на эта страница MSDN вы можете найти источник для простого, полезного HRTimer класс C++, который обертывает необходимые системные вызовы, чтобы сделать что-то очень близкое к тому, что вам нужно (было бы легко добавить GetTicks() метод ему, в частности, делать ровно что вам требуется).
Я бы расширил этот вопрос с примером драйвера NDIS при получении времени. Как известно, KeQuerySystemTime (имитируется под NdisGetCurrentSystemTime) имеет низкое разрешение выше миллисекунд, и есть некоторые процессы, такие как сетевые пакеты или другие IRPs, которые могут нуждаться в лучшей метке времени;
пример так же просто:
где делитель 10^3 или 10^6 в зависимости от требуемого разрешения.
p.s. тестил в console application.
пока модератор не пришел, советую поменять тему
Посльзоваться следующим образом(поправте если что-то не так):
А вообще говоря, надо читать документацию и писать код внимательней. В твоем примере ты вычисляешь количество тактов, прошедших между двумя последовательными вызовами QueryPerformanceCounter, а твой Sleep там вообще ниприкак.
mayami3
Всё нормально, и крайне просто. Есть просто некий высокоточный таймер.
ЗЫ И не называй единственный нормальный таймер в Win32 х. ей.
onyXMaster
Клёво, только я ещё в base64 читать не научился :/
mayami3
Читай свою-же тему, мой пост №8.
Там есть метод GetElapsedSec(), он возвращает время в секундах, между последним вызовом Reset (или временем создания объекта класса) и текущим моментом вызова GetElapsedSec().
Ты просто толком не разобрался, а начал наезжать.
Надо было пример изучить.
В терминах моего класса нужно делать GetElapsed() / GetFreq(), чтобы тики конвертнуть в секунды или просто вызывать GetElapsedSec(), который сам сделает преобразования в секунды.
В терминах QPC нужно разницу двух QPC разделить на то, что возвращает QueryPerformanceFrequency (частота в секунду).
Причем это деление лучше делать преобразовав результаты вызовов QPC и QPF в double или float.
Получать данные из QPC, QPF лучше в __int64, тогда тебе будут доступны мат. методы этого типа.
Например так:
cppguru
Открывай IE 🙂
onyXMaster
Ишак вообще ничего не кажет. В мозилле хоть текст был.
NULL_PTR
Ghost2
cppguru
Спасибо, вы пролили свет.
crazy25
Твой таймер я изучил и внимательно. Просто я очень неправильно замерял. Как заметил cppguru я
замерял разницу между двумя вызовами QueryPerformanceCounter. Вот и вся проблема.
Всем спасибо. Тема закрыта.
LARGE_INTEGER Union
Represents a 64-bit signed integer value.
The LARGE_INTEGER structure is actually a union. If your compiler has built-in support for 64-bit integers, use the QuadPart member to store the 64-bit integer. Otherwise, use the LowPart and HighPart members to store the 64-bit integer.
QuadPart — это LONGLONG, который в свою очередь __int64. Работая с QuadPart мы посути работаем с __int64. Правильно понимаю?
ArtemSmirnov
> Для чего в union дважды одинаковые структуры содержатся?
К одной можно обращаться просто как:
А вот только зачем писать DWORD и LONG, когда они оба long?
Как увеличить LARGE_INTEGER
Я пытаюсь увеличить LARGE_INTEGER в C ++, но я получаю следующую ошибку.
Ошибка C2397: преобразование из «LONGLONG» в «DWORD» требует сужающего преобразования
Понятия не имею, что я делаю не так. Это очень простая проблема, я пытался пересобрать проект, но ошибка просто не исчезла.
эти строки — то, что я пробовал, все они дают ту же ошибку.
Решение
Вы можете просто напрямую использовать Quadpart. Обратите внимание, что это целое число длиной 64 бита. также известен как long long и __int64 компилятором MS и gcc. Поскольку это простой старый тип данных, компиляторы поддерживают все арифметические и побитовые операции, выполняемые с ним.
Определение БОЛЬШОГО ИНТЕГЕРА
LARGE_INTEGER является простым объединением C и поэтому не предоставляет никаких конструкторов. Однако вы можете использовать агрегатный инициализатор C, чтобы инициализировать его нулем.
Используя QuadPart, вы можете манипулировать LARGE_INTEGER так же, как любое длинное целое число …
ВАЖНО: MS использует объединение LARGE_INTEGER для передачи таких длинных длинных значений как по историческим причинам, так и для принудительного выравнивания длинных длинных. Некоторые из API Windows будут зависать, если Quadpart не выровнен правильно. Поэтому просто приведение __int64 * к LARGE_INTEGER * при вызовах Windows API не является хорошей практикой.
В 64-битных окнах 64-битное приращение, т.е. li.Quadpart ++, является атомарной операцией.
Другие решения
В качестве проблемы, решаемой @CodyGray в комментариях, я предложил это решение. операция еще атомная, так как atomic_store касается только переменных x а также y являются локальными для потока и метода.
Вечный вопрос измерения времени
Казалось, закончились долгие обсуждения в форумах, как измерить время работы алгоритма, какие функции использовать, какую точность ожидать. Жаль, но опять придется вернуться к этому вопросу. На повестке дня, как лучше измерить скорость работы параллельного алгоритма.
Сразу скажу, что не дам точного рецепта. Я сам недавно столкнулся с проблемой измерения скорости работы параллельных алгоритмов и не являюсь экспертом в этом вопросе. Эта заметка носит скорее исследовательский характер. Я буду рад услышать ваше мнение и рекомендации. Думаю, вместе мы разберемся с проблемой и выработаем оптимальное решение.
Задача состоит в измерении времени работы участка пользовательского кода. Раньше для этой задачи я использовал класс следующего вида:
Данный класс основан на использовании функции GetThreadTimes, которая позволяет разделить время, затраченное на работу пользовательского кода, и время работы системных функций. Класс предназначен для оценки времени работы потока в пользовательском режиме, и поэтому используется только возвращаемый параметр lpUserTime.
Измерять время работы можно используя такие инструментальные средства, как Intel Parallel Amplifier, но часто удобно измерять время изнутри программы. Например, это позволяет записать значения в лог. Поэтому мы все-таки попробуем создать класс для замера скорости.
Рассмотрим пример кода, вычисляющий некоторое число. Используем для измерения времени работы класс Timing.
В таком виде механизм измерения времени ведет себя как ожидалось и на моей рабочей машине выдает, скажем, 7 секунд. Результат корректен даже для многоядерной машины, так как неважно какие ядра будут использованы в процессе работы алгоритма (см. рисунок 1).
Рисунок 1 — Работа одного потока на многоядерной машине.
Теперь представим, что мы хотим использовать в нашей программе возможности многоядерных процессоров и хотим оценить, что нам дает распараллеливание алгоритма на основе технологии OpenMP. Распараллелим наш код, добавив одну строчку:
Теперь программа печатает на экран время работы 1.6 секунд. Поскольку используется машина с 4 ядрами, хочется сказать «Ура, мы получили ускорение в 4 раза и замер времени работы это подтверждает».
Огорчу. Мы измеряем не время работы алгоритма, а время работы главного потока. В данном случае измерение кажется достоверным, поскольку основной поток работал столько же, сколько и дополнительные. Поставим простой эксперимент. Явно укажем использовать 10 потоков, а не 4:
Это ожидаемый результат, хотя мы хотели получить совсем иное. Было создано 10 потоков. Каждый из которых отработал порядка 0.7 секунд. Именно это время работал и основной поток, время которого мы замеряем, используя класс Timing. Как видите, такой способ неприменим для измерения скорости программ с параллельными участками кода. Для наглядности отобразим это на рисунке 2.
Рисунок 2 — Так может выглядеть работа 10 потоков, на машине с четырьмя ядрами.
Конечно, всегда можно использовать функцию time(), но ее разрешающая способность низкая, она не позволяет разделить время работы пользовательского и системного кода. Дополнительно на время могут влиять другие процессы, что также может сильно искажать измерения времени.
Любимой функцией многих разработчиков для измерения скорости является QueryPerformanceCounter. Давайте построим измерение скорости с ее использованием. В простом виде класс для измерения будет выглядеть следующим образом:
К сожалению, на многоядерной машине, так делать больше нельзя. 🙂 Вот что сказано по поводу этой функции в MSDN:
On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL). To specify processor affinity for a thread, use the SetThreadAffinityMask function.
Произведем усовершенствования и привяжем главный поток к одному ядру:
Данный способ измерения по-прежнему подвержен тому же недостатку, что невозможно отделить время работы системного и пользовательского кода. Если на ядре выполняются другие задачи, то результат измерения также будет весьма неточен. Однако как мне кажется, такой способ все же применим к параллельному алгоритму в отличии GetThreadTimes. Если это не так, то прошу меня поправить!
Измерим, что покажут классы Timing и Timing2 на различном количестве потоков:
Сведем данные в таблицу, показанную на третьем рисунке.
Рисунок 3 — Время работы алгоритма в секундах измеренное с помощью функций GetThreadTimes и QueryPerformanceCounter на четырехядерной машине.
Как видно из таблицы, пока количество потоков не превышает количества ядер, функция GetThreadTimes дает результат схожий с QueryPerformanceCounter, что может приводить к ощущению, что производятся корректные измерения. Однако при большем количестве потоков на ее результат полагаться уже нельзя.
Жду ваших комментариев и описаний способов, как лучше измерять время работы параллельных алгоритмов.