Вопрос про стэк и таблицу строк

Тема в разделе "WASM.BEGINNERS", создана пользователем Antolflash, 18 янв 2010.

  1. Antolflash

    Antolflash New Member

    Публикаций:
    0
    Регистрация:
    14 дек 2008
    Сообщения:
    167
    Я слышал, что вроде-как Стэк (в смысле тот, который адресуется регистрами ESP и EBP) - самый быстрый вид памяти, в том смысле, что доступ к нему быстрее, чем обращение просто по адресу памяти. Я вот не понимаю, если вершина стэка адресуется регистром ESP (а заполняется стэк от больших адресов к меньшим, то бишь каждый push вычитает из esp), а к любому элементу в стеке можно получить доступ а-ля mov eax, [esp+что-то], то стэк находится в одном адресном пространстве со всеми остальными вещами, лежащими в памяти (например - динамически выделенные строки), и почему-же тогда стэк быстрее??? Правильно ли я понимаю, что быстрота скрыта исключительно в инструкциях push и pop которые быстрее кладут и вынимают, чем movы?
    И ещё один вопрос. Я тут прочёл про таблицу строк в C++ и не поверил, глянул код, генерируемый студией при объявлении то-то вроде char m[] = "String". Смотрю, через основные регистры в память по адресу m перекидывается строка из совершенно другого адреса. То бишь строка лежит в двух местах - в массиве и в месте, откуда её перекинули в массив - в таблице строк. Зачем так дублировать?
     
  2. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Стек -- почти такая же память, как и вся остальная. Грубо говоря, куда esp указал, там и стек. Единственное ее отличие -- в конце стека находится специальная страница, обращение к которой приведет к исключению, и ОС добавит памяти к стеку (очень грубое описание, но для простоты пусть будет так). Во всем остальном -- все точно также, как с остальной памятью. Более того, в момент создания потока эта память выделяется почти также как и "обычная" память.

    Стек может быть быстрее т.к. во-первых, он УЖЕ выделен к моменту выполнения потока, во-вторых, обращения в стеке обычно более-менее локальны (т.е. находятся по относительно блищким адресам) и дольше выживают в TLB и обычном кэшах.

    При желании можно выделить память самому (через VirtualAlloc, например), сделать 'mov esp, eax' и продолжить выполнение. Все будет работать также, как и в обычной программе. Желательно выделять 1 мегабайт (RESERVE | COMMIT), т.к. это и есть размер стека по-умолчанию (отличие в том, что при "штатном" использовании стека, RESERVE делается на 1 MB, а COMMIT, кажется на 64 KB).

    А про строку ничего не понял. Думаю, стоит привести пример.
     
  3. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Antolflash
    Я бы сказал, что ситуация как раз с данной точки зрения должна быть прямо противоположная. В связи с зависимостью по esp (а также необходимостью изменения этого самого esp) пропускаемость десятка push при запихивании аргументов будет ниже, чем десятка mov по подряд идущим адресам стека. Т.е. код вида:
    push 1
    push 2
    ...
    push 10
    должен по идее отрабатывать медленнее, чем код:
    sub esp,10*4
    mov [esp],10
    mov [esp+4],9
    ...
    mov [esp+9*4],1
    В остальном, как сказал Mika0x65, память стека может быть быстрее только за счёт большей вероятности кэширования в силу частоты обращений к стеку (ну или механизмов оптимизации, направленных специально на кэширование именно стековой памяти).

    Mika0x65
    Что за "штатное" использование? Сколько в заголовке PE указано, столько и выделяется/резервируется. Каких-то значений по умолчанию AFAIK нету.
     
  4. Rockphorr

    Rockphorr Well-Known Member

    Публикаций:
    0
    Регистрация:
    9 июн 2004
    Сообщения:
    2.615
    Адрес:
    Russia
    Antolflash
    нет не правильно
    быстрота стека в том что он используется хорошо известная область памяти для обмена данными по значению
    другим словами передать блок данных через стек быстрее и проще чем городить для этого аналогичный механизм
     
  5. Rockphorr

    Rockphorr Well-Known Member

    Публикаций:
    0
    Регистрация:
    9 июн 2004
    Сообщения:
    2.615
    Адрес:
    Russia
    Antolflash
    имхо это результат того что вы не все сообщили компилятору объявляя массив
    ну а он в свою очередь страхуется применяя фокусы по умолчанию,
    которые вы тоже можете указать в настойках
     
  6. Antolflash

    Antolflash New Member

    Публикаций:
    0
    Регистрация:
    14 дек 2008
    Сообщения:
    167
    Мне не ясен смысл фразы "хорошо известная область памяти". Машине не всё равно, по какому адресу ей обращаться, на то она и RAM, что Random. Вот если жёсткий диск, то да, обращения по рядом-стоящим местам быстрее. Поясните, пожалуйста.
     
  7. Antolflash

    Antolflash New Member

    Публикаций:
    0
    Регистрация:
    14 дек 2008
    Сообщения:
    167
    Ага, точно, вычисления а-ля [esp + 4*n] являются самыми быстрыми. Вроде даже есть всякие вычислительный фишки в стиле lea eax, [edx + 4*n], чтобы быстро считать выражения с прибавлением к числу степени двойки.
    А push каждый раз делает dec esp и только потом mov, что медленнее.
     
  8. Antolflash

    Antolflash New Member

    Публикаций:
    0
    Регистрация:
    14 дек 2008
    Сообщения:
    167
    Ага, т.е. стек нужен только как механизм по передаче аргументов, созданию локальных переменных, а главное их однозначной и простой зачистке (не надо помнить, где ты выделил память, просто pop и всё зачистил)
     
  9. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    l_inc
    Я имел в виду, что по умолчанию в заголовок как раз прописывается 1MB/64KB. Неудачно выразился, видимо.

    Antolflash
    Самое первостепенное, на мой взгляд -- сохранение адресов возврата. Переменные при желании можно все глобальные сделать. Правда, некоторое архитектуры (например, ARM) могут возлагать сохранение адреса возврата на программиста (или компилятор).
     
  10. Antolflash

    Antolflash New Member

    Публикаций:
    0
    Регистрация:
    14 дек 2008
    Сообщения:
    167
    Действительно.
     
  11. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Mika0x65
    Зависит от компилятора. В фасме по умолчанию прописывается вообще 4КБ/4КБ. Или имелся в виду также и "компилятор по умолчанию"? :)
     
  12. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    l_inc
    Ну да. Среди всех моих знакомых только один начал с *nix/gcc. Все остальные -- Win/cl :). Думаю, это верно и в случае Antolflash.
     
  13. Rockphorr

    Rockphorr Well-Known Member

    Публикаций:
    0
    Регистрация:
    9 июн 2004
    Сообщения:
    2.615
    Адрес:
    Russia
    машине действительно все равно какой участок оперативки используется под стек, но
    заключается в том что вы просто расставляете инструкции push pop call ret в то время как данные пишутся и читаются автоматически в том смысле что вам не нужно корректировать esp/sp
     
  14. Antolflash

    Antolflash New Member

    Публикаций:
    0
    Регистрация:
    14 дек 2008
    Сообщения:
    167
    И какое отношение это имеет к быстродействию?
     
  15. Rockphorr

    Rockphorr Well-Known Member

    Публикаций:
    0
    Регистрация:
    9 июн 2004
    Сообщения:
    2.615
    Адрес:
    Russia
    Antolflash
    дык наишите хранилище аналогичное стеку и сравните время работы процедур чтения записи хранилища с временем пуш и поп
     
  16. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Antolflash
    Не слушайте Rockphorr. :) Он здесь по приказу влиятельных лиц из международной службы компьютерной безграмотности занимается распространением дезинформации.
    Тут, кстати, leo заглядывал вчера. Если он снизойдёт (no sarcasm) здесь отписаться, то всё, что он скажет, будет истиной в первоинстанции и не подлежать сомнению.
     
  17. Rockphorr

    Rockphorr Well-Known Member

    Публикаций:
    0
    Регистрация:
    9 июн 2004
    Сообщения:
    2.615
    Адрес:
    Russia
    l_inc
    :<)
     
  18. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    Antolflash
    Раньше это так и было но начиная с Core 2 / Phenom это вобщем-то пофик, у интелов работает stack-engine, у аэмдешек не помню как это разруливается, но тоже достаточно эффективно. Так что работа со стеком практически так же эффективна, как и с плоской памятью. Но можно попробовать придумать вариант, где mov все-таки эффективнее push/pop поэтому, имхо, все же стоит предпочитать второй вариант.
     
  19. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    А вот и не снизойду (in sarcasm) :lol:
    В #2 и #3 в общих чертах все сказано верно.
    Стек это не "самый быстрый вид памяти", а во-первых, наиболее часто используемая область памяти (имеется в виду не весь мегабайтный стек, а ограниченный набор адресов вблизи текущего ESP, используемый при вызове процедур) и соотв-но эта область памяти как правило всегда находится в кэше процессора. Во-вторых, "выделение" памяти в стеке под временные\локальные переменные осуществляется простым sub esp практически "мгновенно" по сравненю с "неторопливыми" Heap\VirtualAlloc.

    Ну и насчет push\pop тоже в основном верно - работать быстрее обычных mov они никак не могут, но и преувеличивать их тормоза тоже не стоит, т.к. разрабы камней не зря свой хлеб кушают и предпринимают соответствующие меры для исключения тормозов. Поэтому "радостно просветленный" вывод Antolflash
    для современных суперскалярных камней является неверным, во-первых, потому, что при mov [esp+X] тоже сначала вычисляется адрес esp+X и "только потом mov", во-вторых, потому, что процессор по любому не мешает в одну кучу операции вычисления адреса и изменения регистров, и соотв-но push\pop просто разбиваются на 2 микрооперации - одна вычисляет адрес ESP+X для mov-а, а другая, формально точно такая же, изменяет регистр ESP <- ESP+X, причем эти операции могут выполняться одновременно. В PentiumM и Core2 пошли еще дальше и придумали так называемый stack engine, который автоматически ведет учет всех приращений ESP операциями push\pop\call\ret и соотв-но сразу после декодирования заменяет их на mov [ESPo+ESPd], где ESPo - некоторое значение ESP перед серией push\pop и т.п., ESPd - текущее приращение. Таким образом, удалось избавиться как от дополнительного мопа на каждый push\pop, так и от зависимости push\pop друг от друга. В итоге в PM и Core2 push\pop вообще практически не отличаются от обычных mov, а в P3 и P4 они лишь добавляют по лишнему мопу (что может "слегка" притормозить выполнение АЛУ-операций, идущих вперемежку с push\pop, а на длинных сериях push или pop как раз и не сказывается, т.к. выполняются параллельно на другом блоке). И только на Атлонах push\pop могут вдвое снизить проп.способность на длинных сериях, да и то не потому, что у них сами push\pop какие-то особо тормозные, а потому что mov-ы в Атлонах "шибко крутые" и могут выполняться по 2 шт. за такт, а push\pop ес-но только по 1 за такт из-за изменения ESP
     
  20. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    кеширование + работа конвейера. проц не может обработать несколько пушей одновременно, т.к. неизвестно значение регистра esp в момент загрузки инструкции.