Производительность запросов WMI

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Производительность запросов WMI

Сообщение ger_kar » 20.06.2011 (Пн) 20:38

В интернете можно найти множество примеров получения сведений посредством WMI. Как правило предлагается следующий вариант:
Пример получения CPU ID:
Код: Выделить всё
Set objWMIService = GetObject("winmgmts:\\" & STR_COMP & "\root\CIMV2")
Set objColItems = objWMIService.ExecQuery("SELECT * FROM Win32_Processor", , 48)
For Each objColItem In objColItems
        strCPUID = objColItem.ProcessorId
Next

Подобный код генерируют и различные генераторы кода такие как WMICodeCreator, Scriptomatic и другие. Однако запросы вида SELECT * FROM выполняются крайне медленно, почему это проиходит, я и хотел спросить у форумчан.
То-же запрос, но более конкретизированный: "SELECT ProcessorId FROM Win32_Processor" выполняется на порядок быстрее. Естественно это можно было-бы объяснить тем, что в первом случае запрос выбирает большее количество элементов коллекции и задержка связанна именно с этим.
Тогда по идее самым быстрым вариантом должен быть вариант с прямым полученим объекта:
GetObject("winmgmts:Win32_Processor='CPU0'").
Делаю небольшую тестовую программку:
Код: Выделить всё
Sum Main()
    Dim objWMIService As Object
    Dim objColItems As Object, objColItem As Object
    Dim strCPUID As String, strMBID As String
    Dim Time11, Time12, Time13, Time14
    Const STR_COMP As String = "."
    Time11 = Timer
    '======= Вариант 1 (самый быстрый) ========
    Set objWMIService = GetObject("winmgmts:\\" & STR_COMP & "\root\CIMV2")
    Set objColItems = objWMIService.ExecQuery("SELECT ProcessorId FROM Win32_Processor", , 48)
    For Each objColItem In objColItems
        strCPUID = objColItem.ProcessorId
    Next
    Set objColItems = objWMIService.ExecQuery("SELECT SerialNumber FROM Win32_BaseBoard", , 48)
    For Each objColItem In objColItems
        strMBID = objColItem.SerialNumber
    Next
    Time12 = Timer
    '======= Вариант 2 =======
    Set objWMIService = GetObject("winmgmts:\\" & STR_COMP & "\root\CIMV2")
    Set objColItems = objWMIService.ExecQuery("SELECT * FROM Win32_Processor", , 48)
    For Each objColItem In objColItems
        strCPUID = objColItem.ProcessorId
    Next
    Set objColItems = objWMIService.ExecQuery("SELECT * FROM Win32_BaseBoard", , 48)
    For Each objColItem In objColItems
        strMBID = objColItem.SerialNumber
    Next
    Time13 = Timer
    '====== Вариант 3 =======
    Set objWMIService = GetObject("winmgmts:Win32_Processor='CPU0'")
    strCPUID = objWMIService.ProcessorId
    Set objWMIService = GetObject("winmgmts:Win32_BaseBoard='Base Board'")
    strMBID = objWMIService.SerialNumber
    Time14 = Timer
    MsgBox "Вариант 1 - " & Time12 - Time11 & vbCrLf & _
           "Вариант 2 - " & Time13 - Time12 & vbCrLf & _
           "Вариант 3 - " & Time14 - Time13 & vbCrLf & _
           "CPU - " & strCPUID & vbCrLf & "MB - " & strMBID, vbInformation
End Function

Тестирую и сильно удивляюсь - вариант с непосредственным полученим объекта, по времени исполнения такой же как и SELECT * FROM .
Ради интереса подключаю библиотеку Microsoft WMI Scripting V1.2 Library, объявляю переменные с соответсвующими типами, вместо типа Object и ситуация в принципе остается без изменений.
Кто может объяснить такое поведение?
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Производительность запросов WMI

Сообщение Хакер » 20.06.2011 (Пн) 20:47

ger_kar писал(а):Ради интереса подключаю библиотеку Microsoft WMI Scripting V1.2 Library, объявляю переменные с соответсвующими типами, вместо типа Object и ситуация в принципе остается без изменений.

Ну так, не IDispatch же причина задержек.

WMI уходит своими корнями сразу в режим ядра. Значит там что-то сидит и создаёт задержку в особых ситуациях, например какой-нибудь кривой драйвер устройства, или драйвер диагностической/справочной утилиты (вроде AIDA32) или драйвер антивируса.

Копать надо, сначала убедись, что проблема одинаково проявляется на всех системах.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Производительность запросов WMI

Сообщение ger_kar » 20.06.2011 (Пн) 21:20

Хакер писал(а):Ну так, не IDispatch же причина задержек.

Совершенно верно, просто не удержался от эксперимента, и получил прогнозируемый результат, в отличии от запроса с прямым получением объекта ;) .
Хакер писал(а):Копать надо, сначала убедись, что проблема одинаково проявляется на всех системах.

Ну, по крайней мере на 5 компах я проверил + на виртуалке с "голой" системой - ситуация схожая, разве что на "старушках" этот разрыв еще больше.
Кстати заодно и другую статистику собрал: На всех проверенных мною машинах ProcessorId везде присутствовал, в отличии от SerialNumber из колекции Win32_BaseBoard, на трех машинах из 5 возвращалость пустое значение.
Интересно, если тест реализовать на других языках на C++ например, то каков будет результат? Си я конечно не знаю, но логично предположить, что результат будет таким же. Хотя в жизни все бывает.
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Производительность запросов WMI

Сообщение Хакер » 20.06.2011 (Пн) 21:23

Так, ну * это вилдкард, который захватывает все поля. Посмотри, какие поля приходят. Затем методом исключения убирай поля, пока производительность вдруг не вскочит вверх. Затем все поля кроме выявленного возвращай назад, убеждаясь, что именно выявленное поле вызывает задержку. Затем оглашай имя выявленного поля, чтобы мы смогли подумать над ним, ну и думай над ним сам.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Производительность запросов WMI

Сообщение ger_kar » 20.06.2011 (Пн) 21:42

Кстати хорошая идея. Потестирую. Надо кстати ище на Win7 попробовать. Ну и продолжу дальше собирать статистику. Кстати еще очень интересно собрать статистику по Win32_Processor - ProcessorId и Win32_BaseBoard - SerialNumber для защиты с привязкой к железу. Просматривая форум я натыкался на подобные вопросы, но однозначного ответа так и не встретил. В принципе с Win32_BaseBoard - SerialNumber уже и так все понятно, а вот с процессором статистика предстваляет интерес.
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16477
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Производительность запросов WMI

Сообщение Хакер » 20.06.2011 (Пн) 21:51

Может быть там есть поле, которая соответствует показателю, который рассчитывается во времени. Например «Clocks Per Second», которая реально измеряет число тактов за секунду. Естественно, что для этого должна пройти эта самая секунда.

Ну, это условный пример, чисто предположение.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Производительность запросов WMI

Сообщение ger_kar » 21.06.2011 (Вт) 19:55

Вобщем нашел тормоз, им оказалось свойство LoadPercentage, причем что самое интересное, тормозит оно не во время самой выборки, а во время обработки коллекции в цикле. А LoadPercentage это не что иное, как загрузка процессора в процентах.
Хакер писал(а):Может быть там есть поле, которая соответствует показателю, который рассчитывается во времени.

Ну Хакер ты даешь, ты настоящий телепат, не иначе :)
Единственное, что не понятно, почему третий вариант получения объекта напрямую тоже тормозит, я нахожу этому только единственное логическое объяснение - языковая констукция позволяет указать путь к объекту непосредственно, но сам алгоритм его получения видимо такой же как и во втором случае, т.е. сначала получается вся коллекция и из нею выделяется искомое. Надо распределить это по разным процедурам и глянуть что получиться в отладчике.
Бороться и искать, найти и перепрятать

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Производительность запросов WMI

Сообщение ger_kar » 21.06.2011 (Вт) 21:20

Посмотрел в отладчике, скомпилированный код разный. В случае прямого получения объекта, никаких циклов в скомпилированном коде нет, а все корни уходят в DLL Kernel32 и основное действо разворачивается там.
Бороться и искать, найти и перепрятать


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

    TopList