Что нового

"Быстрая" работа с памятью процесса(чтение)

ZlojBoter

Новичок
Сообщения
55
Репутация
0
В общем дело такое: существует библиотека функций работы с памятью. Даже возможно не одна, а несколько. Самое первое, что находил по этому поводу, года 2-3 назад это NomadMemory.
Покамест, запросы мои были невелики, скорости работы функций считывания памяти мне хватало, потом дело пошло в гору, и ряд функций активно использующих чтение памяти, приходилось оптимизировать, уменьшая "нагрузку", чем уменьшалась "возможная" эффективность их работы.
Потом, вдруг внезапно обнаружил у моих "коллег", занимающихся теми же процессами автоматизации в онлайн игре, что скорость считывания у них раз в 100 выше. Они насчет нее не заморачиваются вовсе. Пишут они не на автоите, а на дельфи и с++, в основном. Тобишь, функции чтения работают у них как-то "более напрямую" что ли.
Пробовал помимо NomadMemory еще и библиотеку WinAPI, но скорость считывания оказалась ровно такой же +/- 10%. Покопался в самих функциях, и понял,что они мало чем отличаются от аналогичных из библиотеки NomadMemory.
Просто для примера: на то, чтобы считать 100000 раз по 4 байта информации, требуется в среднем 7 секунд на старом компе, на новом же компе раза в 2-3 поменьше.
Отсюда вопрос: есть ли какие-нибудь функции, работающие с памятью "по шустрее", или сталкивался ли кто-нибудь с такой проблемой на автоите, и самое главное: как решал проблему?


Забыл добавить: если нагрузить программу непрерывным считыванием из памяти через эти функции, то нагрузка на ядро составляет 100%. То есть, нет каких-то "тормозящих процессов", которые заставляют программу просто "ждать". Видимо, в память постоянно загружаются и выгружаются длл, на что и уходит основная масса времени...
 

sims

Осваивающий
Сообщения
184
Репутация
24
У меня DLL из вложения читает сто тысяч раз из другого процесса за 120 миллисекунд.
В ней функция, аналогичная WinAPI (по сути, dll лишь обвертка для WinAPI функции.)
Код:
ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, Size, lpNumberOfBytesRead)
 
Автор
Z

ZlojBoter

Новичок
Сообщения
55
Репутация
0
sims, не совсем только понятно, как этим пользоваться. Запускать длл как апи функции с тем же синтаксисом что и kernel32.dll?, просто заменив названия длл, занеся ее предварительно в реестр? или как еще...
 

sims

Осваивающий
Сообщения
184
Репутация
24
В реестре dll регистрировать не надо. Просто вызывайте из нее эту функцию, так же как вы это делаете с WinAPI.

Только подозреваю что дело не в функции, а в медленной работе AutoIt скрипта. Он ведь интерпретируется, а это намного медленнее чем выполнение скомпилированной программы.
 
Автор
Z

ZlojBoter

Новичок
Сообщения
55
Репутация
0
Re: \"Быстрая\" работа с памятью процесса(чтение)

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


Добавлено:
Сообщение автоматически объединено:

попробовал с этой длл. Вообще не работает функция у меня. насколько я понял, сделать надо было так:
Код:
Func _WinAPI_ReadProcessMemory2($hProcess, $pBaseAddress, $pBuffer, $iSize, ByRef $iRead)
	Local $aResult = DllCall("ReadProcessMemory.dll", "bool", "ReadProcessMemory", "handle", $hProcess, _
								"ptr", $pBaseAddress, "ptr", $pBuffer, "ulong_ptr", $iSize, "ulong_ptr*", 0)
	If @error Then Return SetError(@error, @extended, False)
	$iRead = $aResult[5]
	Return $aResult[0]
EndFunc   ;==>_WinAPI_ReadProcessMemory

Пробовал также указывать полный путь к файлу
 

sims

Осваивающий
Сообщения
184
Репутация
24
ZlojBoter [?]
скомпилированном скрипте
У AutoIt нет компилятора в традиционном понимании этого слова.
В место компиляции, скрипт склеивается интерпретатором, и поэтому скорость выполнения намного ниже чем скорость работы скомпилированных программ.
Думаю что придется часть программы вынести в dll (или полностью переписать прогу на компилируемый ЯП). Иначе, производительность не поднять.
 
Автор
Z

ZlojBoter

Новичок
Сообщения
55
Репутация
0
Re: \\\\\\\"Быстрая\\\\\\\" работа с памятью процесса(чтение)

sims, размер вашей дллки 3.5кб а размер кернел32 - ~900кб. Разница скорости загрузки может сказаться ведь? Проблема только в том, что вообще не работает сама длл у меня, может, что-то делаю не так. Если в ней вместо всего набора функций кернел32, только работа с памятью процесса, и вызов функции имеет тот же синтаксис, то в чем может быть проблема?


Добавлено:
Сообщение автоматически объединено:

Такс, понял, работает она но жуууутко медленно работает. За 1 секунду успевает только 1000 раз считаться при помощи этой dll :shok:


Добавлено:
Сообщение автоматически объединено:

Попробовал сделать так:
Код:
DllOpen("ReadProcessMemory.dll")

перед циклом со считыванием из памяти загрузил длл, подумал, может она выгружается постоянно.
Результат - скорость возросла. 100000 считываний за 12 секунд, однако против 7 секунд - результата работы штатной кернел32.
Мдя...чего то я не понимаю :stars:


Добавлено:
Сообщение автоматически объединено:
 

sims

Осваивающий
Сообщения
184
Репутация
24
ZlojBoter [?]
Результат - скорость возросла. 100000 считываний за 12 секунд, однако против 7 секунд - результата работы штатной кернел32.
У меня же (как писал выше) 100 тысяч считываний через эту dll, производится за 0.1 секунды, т. е. в 70 раз быстрее. Правда, прога не на AutoIt-е, а на одном из компилируемых ЯП. Из этого можно сделать вывод, что низкая скорость из-за медленного выполнения (интерпретации) скрипта.
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
ZlojBoter
А зачем вам такая скорость? Может процесс и не пишет с такой скоростью в себя данные, какой смысл тогда от такого скоростного чтения?
 
Автор
Z

ZlojBoter

Новичок
Сообщения
55
Репутация
0
А зачем вам такая скорость? Может процесс и не пишет с такой скоростью в себя данные, какой смысл тогда от такого скоростного чтения?
Дело в том, что это не единичное считывание одного и того же параметра. Я произвожу циклически считывание всех окружающих игроков. Это до ~700 чаров максимум(обычно не больше 200), у которых нужно считать сразу ряд данных: 3 координаты, параметры земля/вода/воздух, жив/мертв, ид кастуемых скиллов и др. И самое главное, желательно, чтобы это производилось в сотые доли секунды, иначе работа бота не будет синхронизирована. При той скорости считывания, что я могу достигнуть при помощи средств автоита, по видимому цель не достижима. Вернее, максимально возможная эффективность работы программы не достижима. В моем случае, приходится довольствоваться той скоростью что есть, однако, когда нужно отследить, кто по тебе что кастует, и немедленно отреагировать, срабатывает значительно медленнее чем хотелось бы. Ну и еще, одна из существенных проблем заключается в том, что скрипт отжирает на свою работу при такой нагрузке ядро целиком. На одно-двухъядерных компах это проблема, на новых же 4-6-8 ядерных компах проблема не так существенна конечно...
 

sims

Осваивающий
Сообщения
184
Репутация
24
ZlojBoter [?]
При той скорости считывания, что я могу достигнуть при помощи средств автоита, по видимому цель не достижима.
Обычно в таких случаях, код который должен быстро выполнятся, переносят в dll. http://autoit-script.ru/index.php?topic=3776.0


На одно-двухъядерных компах это проблема, на новых же 4-6-8 ядерных компах проблема не так существенна конечно...
Ошибаетесь. AutoIt не поддерживает многопоточность и скрипт выполняется на одном ядре, а остальные простаивают.
В вашем случае, лучше вынести код в DLL, в которой он будет выполнятся в нескольких потоках (по числу процессоров/ядер) и тогда получите максимальную производительность на многоядерных процессорах.
 
Автор
Z

ZlojBoter

Новичок
Сообщения
55
Репутация
0
AutoIt не поддерживает многопоточность и скрипт выполняется на одном ядре, а остальные простаивают.
я имел ввиду немного другое. Работа клиента игры не тормозится работой программы. Проблема в этом была. А многопоточность мне не нужна :smile: Я ведь сам могу ее создать. Пусть это будет не та многопоточность которая обычно имеется ввиду, но я ведь могу заставить скрипт запустить два и более экзешников и вести между ними связь. Заставив каждый выполнять часть работы. Один например пойдет считывать данные с начала списка игроков другой с конца) Синхронизация работы в таком случае конечно печаль бида но что поделаешь...
 

sims

Осваивающий
Сообщения
184
Репутация
24
ZlojBoter [?]
запустить два и более экзешников и вести между ними связь
Чтобы достичь той же производительности какая у нативных прог выполняющихся на одном ядре, нужен 100 ядерный процессор и 100 запущенных копий проги.

А синхронизация сведет на нет такую псевдо-многопоточность. Ведь на нее будет затрачиваться время и ресурсы компа.
 
Автор
Z

ZlojBoter

Новичок
Сообщения
55
Репутация
0
Re: \"Быстрая\" работа с памятью процесса(чтение)

можно читать не "ячейку" 7 раз в блоке, а весь блок памяти сразу. Скажем вот так:
идея не плоха, такая мысль возникала давно у меня, только я не знал как ее реализовать. Попробую потестить ваш вариант.


Добавлено:
Сообщение автоматически объединено:

Такс, тестирую данную схему:
Код:
For $i=1 To 100000
$_Struct = 'float;'
$_Info = _Ilum_MemRead( $x, $_Struct, 0 )
Next


Время 6 секунд

Код:
For $i=1 To 100000
$_Struct = 'float; float; float; float; float;'
$_Info = _Ilum_MemRead( $x, $_Struct, 0 )
Next

время 7.5 секунд

тоже самое со 100 ячейками:
49 секунд

попробовал еще:
с 20 ячейками:
14 секунд.

добавил перебор элементов через DllStructGetData:

Код:
For $i=1 To 100000
$_Struct = 'float; float; float; float; float; float; float; float; float; float; float; float; float; float; float; float; float; float; float; float; '
$_Info = _Ilum_MemRead( $x, $_Struct, 0 )
For $j=1 To 20
DllStructGetData( $_Info, $j )
Next	
Next


время выполнения 40 секунд.
Тоже видать прожорливая функция.

Из всего могу сделать вывод, что в разы увеличить производительность действительно можно. Способ конечно не "резиновый". Эффективность тем выше, чем "плотнее" друг к другу будут стоять нужные ячейки. Структуру из 100+ элементов таскать ради 5-7 элементов равномерно распределенных в ней, думаю по времени будет почти тоже самое, что и по отдельности считывать.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
ZlojBoter,
Если Вы постоянно читаете память в одну и ту же структуру, то создайте ее один раз, получите ее размер и Ptr, а в функции выполняйте только вызов DllCall. И проверку IsArray уберите туда же. Так должно работать значительно быстрее.
 
Автор
Z

ZlojBoter

Новичок
Сообщения
55
Репутация
0
Re: \"Быстрая\" работа с памятью процесса(чтение)

Если Вы постоянно читаете память в одну и ту же структуру, то создайте ее один раз, получите ее размер и Ptr, а в функции выполняйте только вызов DllCall. И проверку IsArray уберите туда же. Так должно работать значительно быстрее.
Ок, попробую. Только там не всегда получаются одни и те же смещения. В ряде случаев приходится иметь дело с хеш таблицей.


Добавлено:
Сообщение автоматически объединено:

тестирую новую схему вынес за массив некоторые функции, повторяющиеся:
Код:
$_Struct = 'float;'
$_vBuffer = DllStructCreate($_Struct)
$ptr=DllStructGetPtr($_vBuffer)
$size=DllStructGetSize($_vBuffer)
For $i=1 To 100000
$_Info = _Ilum_MemRead2( $x, $_Struct, 0 )
Next

результат 4.5 сек вместо 6.2, уже радует.

с 5-ю ячейками: 5.3 сек вместо 7.9

с 20-ю: 8 вместо 14

со 100: 21 вместо 46

с 20-ю(+ перебор): 30 секунд вместо 36.

Результат безусловно радует.
 
Верх