тогда ответ на вопрос: нет, это фантастика потому что сегмент с глобальными переменными теоретически будет прокеширован первым.
t00x Глобальные переменные используются только в твоем коде, поэтому в кэш они попадают только при первом к ним обращении из твоего кода (кстати при старте проги их даже в ОЗУ может не быть из-за хитростей файл-маппинга образа). А вот стэк используется и загрузчиком и функциями АПИ, поэтому при старте часть стэка точно в кэше и в процессе работы из-за частых push\pop\call\ret вероятность нахождения адресов локальных переменных в кэше теоретически выше, чем у глобальных
файл-маппинг - надстройка ОС, и не есть обязательна. функцию, использующую локальные переменные, вызывает основная программа. основная программа выполняет некоторые действия до вызова функции (инициализация) обычно с глобальными переменными. не говоря о том, что передача параметров функции может проходить без использования стэка.
leo имеет ввиду то, что файл-маппинг юзается при загрузке образа PE. и секция с глобальными переменными может и не подгрузится сразу.
t00x Если поспорить захотелось, то давай уж сразу Агнеру Фогу отпиши, а мы люди скромные - только известные истины повторяем и заученные кодинг-рулы Ну ладно, чтобы не беспокоить лишний раз доктора попробую еще раз пояснить Файл-маппинг, как уже заметил n0name, рулит при подкачке страниц твоей проги. Если прожка маленькая в несколько Кб, то она ес-но целиком грузится в память, но страница секции данных все равно оказывается не инициализированной и при первом обращении к данным возникает отказ страницы с приличными тормозами - конкретные цифры можешь посмотреть тут. В приличных по объему прогах страницы секции инициализированных данных (.data) вообще могут сразу не загружаться с диска, т.к. загрузчику ОС они нафиг не нужны, и поэтому они грузятся по мере обращения твоей проги к данным. Неинициализированные данные (.data?) с диска не грузятся, но при первом обращении также вызывают отказы страниц (как и VirtualAlloc). Стек же ес-но используется системой при загрузке и инициализации образа, поэтому на момент передачи управления твоей проге ес-но и 1-2 страницы стека уже инициализированы и все адреса в Х-окрестности esp сидят в кэше. Ладно - можно считать, что тормоза при первом обращении к данным это фигня из области теории. Но при работе программы стек используется постоянно, причем в основном в ограниченном наборе адресов в сотни байт - единицы килобайт, поэтому эта рабочая область как правило всегда находится в кэше и т.к. она постоянно читается и перезаписывается, то даже может никогда и не выгружаться из кэша в ОЗУ (разве что по завершению проги или при переключении контекста на другой прожорливый поток). Поэтому если есть необходимость хранить временные промежуточные данные при работе процедуры (в разумном кол-ве ес-но , то (теоретически) это лучше делать в стэке, чем в глобальных переменных. Хотя и глобальные переменые тоже никто не запрещает использовать, но тут должен соблюдаться свой кодинг-рул локализации данных, т.е. одновременно и интенсивно используемые данные должны располаться рядом (данные как известно грузятся в кэш линейками\ секторами по 64\128 байт)
leo, это все хорошо в теории. Но здесь то разговор о многозадачных ОС, где при переключении процессов переключается и стэк и сегмент данных. Так что, нередкость ситуация, когда без разницы будет, где находятся переменные. Хочу заметить, что это происходит с любой программой, так что непонятно, к чему ты про все это? Точно. А есть еще стандартное начало почти любой проги: Код (Text): .data szTitle db "name window",0 .data? hInstance dd ? .... .code call GetModuleHandle, 0 mov [hInstance], eax call MakeWindow/Dialog, offset szTitle Особенно во всяких там дельфях и сях Не раз и не два видел, как в стэке выделяется до нескольких сотен килобайт Где при этом находится кэш, можно только предполагать. :-? Так ведь так оно и есть, на практике. Ведь любая прога имеет глобальные переменные, к которым она обращается при старте. ЗЫ: Я не собираюсь спорить, просто высказал свое мнение. Я тоже одно время верил в Фога. Под однозадачной средой его теория прекрасно работала, в тестах. Но когда начал применять ее в винде, то очень быстро понял, что не стоит особо сильно заморачиваться с кэшем, все равно почти все зависит от других процессов. Хотя, иногда, его трюки с намеренной подгрузкой данных в кэш вполне работают, правда нестабильно
leo в Вашем профессионализме сомнений нет 8-) (здесь доктора никому не понадобятся). Суть такова: логика работа программы должна доминировать над логикой работы ОС. потому, что если бы это было не так, то всё процессорное время отводилось бы операционной системе для её благих нужд (как то маппинг). вопрос можно перефразировать: кеширован ли целевой адрес (64\128)? в любом случае, локальные переменные - это переменные функции, которая вызывается из основной программы (после инициализации). выделение памяти под локальные переменные функции происходит 2 способами: 1) sub esp, ...; - нет обращения к памяти = нет в кеше. 2) push ... (n раз); - глупо для n > 2. механизм, названный "стэк", хорош только для описания взаимодействия между основной программой и вызываемыми функциями; собственно он нигде больше не используется (ещё для сохранения регистров). работа с механизмом "стэк" удобна не своим "быстродействием", а тем что очевидна ясность добавления данных. И большинство ошибок возникает во время использования этого механизма.
AndNot, t00x Во-первых, рекомендация о преимущественном использовании стека основывается на общем принципе локализации расположения и повторном использовании данных, а об отказах страниц и начальной загрузке я упомянул лишь до кучи. Во-вторых, эта рекомендация сродни выравниванию кода и данных - в большинстве практических случаев и то и другое мало что дает, но зато гарантирует от неприятностей в особых случаях при неудачном стечении обстоятельств. По сути: 1) Кэш работает с линейками\секторами, поэтому если интенсивно используемые промежуточные переменные расположены в одной линейке - это есть большой гуд и думаю с этим никто спорить не будет. 2) Кэш устроен по наборно-ассоциативному принципу, поэтому данные с адресами, кратными алиасингу кэша, претендуют на один набор и могут конфликтовать\вытеснять друг друга. В пеньках алиасинг L1 равен или кратен размеру страницы 4К, поэтому адреса, различающиеся на целое число страниц потенциально конфликтуют между собой. В P6 и AMD кратность 4К при неудачных обстоятельствах может также давать тормоза при STLF (store-to-load forwarding), например когда производится запись по одному адресу в секцию .data? и затем читаются данные с тем же смещением из секции .data - получается облом на голом месте 3) В итоге если в процедуре используются только локальные временные переменные (речь ес-но не о многокилобайтных массивах , то они занимают одно вхождение набора кэша (way) и 3 вхождения из 4-х остаются свободными - можно смело заниматься обрабатоткой (последовательной) до 3-х массивов данных без опасности вытеснения переменных из L1. А вот если еще заюзать глобальные константы и переменные из .data и .data? (да еще и из .code , то можно нарваться на ситуацию, когда они попадут в один набор кэша и при обработке более одного-двух массивов будут периодически возникать конфликты и вытеснения данных из L1 с соответсвующими притормаживаниями. Разумеется тут все дело в локализации даных, т.е. лучше\безопаснее хранить временые переменные процедуры в одном месте, а не прыгать из одной секции\страницы в другую, поэтому с таким же успехом можно вместо локальных переменных использовать только глобальные, лишь бы они лежали кучкой в одном месте, а не были разбросаны. Если это не соблюдается, то отсюда и вытекает рекомендация - при интенсивных вычислениях может быть лучше скопировать константы\параметры в стек, чем прыгать за ними по разным адресам, засоряя кэш. Поэтому (с точки зрения быстродействия) стековые переменные это не панацея, а лишь рекомендация как можно избежать конфликтов и уменьшить нагрузку на кэш - не более того t00x Это чисто логическое "выделение" памяти, а с точки зрения кэша это просто повторное использование части уже давно выделенной и закэшированной памяти, т.к. N-е число тактов или нано\микро-секунд назад по этому адресу хранился адрес возврата или локальная переменная другой функции. Другими словами стэк - это по сути та же куча (heap), где один и тот же адрес множество раз переназначается (логически) разным переменным, т.е. для кэша это одна и таже переменная, а по логике программы - разные
leo Область видимости переменных в программе - вот на чём основывается рекомендация об использовании локальных переменных. Рассмотрим архитектуру программного обеспечения в теории, в общем виде без зверюшек, шифрованных программ и т.д. 1) есть программы, которые имеют 1-2 функции и считают результат; 2) есть программы, которые имеют цикл обработки сообщений и мнооого функций, вызываемых (в большинстве своём) из главного цикла; 3) в программах есть рекурсивные, и подпрограммы глубина вложенности которых может достигать >5 (не говоря об их размерах - чем больше, тем чаще обращается к глобальным переменным); 4) добавьте, если что-то пропустил. Рассмотрим модели загрузки стэка, исходя из множества этих программ (будем считать, что все сегменты равнодоступны). В 1) случае вообще нет смысла обращаться в стэку. Во 2) случае, чем чаще главная функция (и мнооого других) обращается к глобальным переменным, тем больше вероятность затереть нужную линейку кеша. Особенно если функции имеют большой размер. В 3) вообще непонятно, насколько вырастет стэк, и какие линейки кеша останутся. в языке C вообще рекомендовано передавать параметры процедурам в виде адресов. команды push\pop используют очередь FIFO и не подходят для других целей.
t00x Уф-ф, разговор слепого с глухим Вспомни вопрос с которого разгорелся сыр-бор и твой первый ответ на который я вынужден был возразить и уточнить, что 1) именно стек кэшируется первым (возьми элементарную прогу и посмотри в Оле, что при передаче управления на OEP весь стэк уже забит мусором, оставленным загрузчиком, хотя твоей проге еще никто и слова не давал и страницы глобальных данных даже еще не инициализированы) 2) работа с переменными в стеке сама по себе не быстрее, чем с глобальными переменными, но условия кэширования при использовании компактно расположенных переменных лучше, чем разбросанных по разным секциям и рекомендация использовать стек основывается именно на принципе локализации данных (если они разбросаны, то для критических по скорости функций может быть лучше скопировать их в стек в одно место) Спрашивается: при чем тут область видимости и "архитектура программного обеспечения" ? Или ты сам с собой разговариваешь ?
это относится к области видимости переменных в программе (локальные\глобальные)? или надо все подряд переменные, в т.ч. глобальные в стэк пихать? архитектура программного обеспечения - относится к кеширование стэка. и написано для того, чтобы показать, что вероятность вытеснения линейки стэк-данных из кеша L1 при обработке больших массивов, глубоких вложениях подпрограмм и рекурсии увеличивается.