• Чем загрузчик в виртуальных процессорах отличается от реального? Какой жизненный цикл запущенной ОС на виртулальном?

    gbg
    @gbg
    Любые ответы на любые вопросы
    на виртуальном процессоре

    1. Современные системы виртуализации используют реальный процессор. Есть конечно и системы, которые эмулируют процессор программно, но это когда речь идет об эмуляции между архитектурами - например, код для ARM запускают на x86.
    2.
    так как образы ос для виртуалок, чет немного другие, а что в них другого в этом вопрос

    отличия в драйверах. "Обычная" ОС должна работать в виртуализации без проблем.
    3.
    А значит. Ram может расти.

    Не вполне верно. Верхний предел RAM задается при старте машины. RAM можно уменьшить, но не увеличить.

    Для современного процессора, выполнение гостевой ОС - это выполнение обычной программы, просто в какие-то моменты он перехватывает обращения к железу и подсовывает туда код гипервизора. Если же мы говорим о программной реализации процессора, то памятью может быть просто массив байтиков.
    Ответ написан
    Комментировать
  • Почему в с# в стуктурах с static void* ptr указателем этот указтаель не равен нулю при инициализации?

    vabka
    @vabka Куратор тега C#
    Токсичный шарпист
    // в откладке показывает TRUE, но как-будто false отрбатывает

    Предположу, что это просто глюк дебаггера. У меня он вообще не может прочитать значение Ptr и пишет вот что:

    Failed to read static field: Статическая переменная недоступна, поскольку еще не инициализирована. (Исключение из HRESULT: 0x8013131A). The error code is CORDBG_E_STATIC_VAR_NOT_AVAILABLE, or 0x8013131A.

    Может быть, дебаггер пытается разыменовать указатель

    Но если попытаться вывести в консоль значение Ptr, то будет 0:
    unsafe {
      void* x = null; // Можно выводить и Env.Ptr - будет тот же результат
      Console.WriteLine((nint)x); // 0
    }
    Ответ написан
    Комментировать
  • Как в архитектурах risc одинаковые виртуальные адреса разных контекстов задач различаются?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    В risc вроде там куча csr регистров

    Вот на этом месте остановись. RISC -- это не конкретный набор инструкций и регистров, это принцип организации набора инструкций. RISC-процессоры все разные, возьми крнкретный и разбирайся с ним, не вали их все в одну кучу, не ставь на вопрос теги процессоров которые не имеют к нему отношения.

    на разных компиляторах одна си операция ассемблируется то в комбинацию lui + addi, то в комбинацию auipc +addi

    Ты указал ARM в тегах, но у ARM нет инструкций lui и auipc. Такие инструкции есть у RISC-V.
    Если ты посмотришь в The RISC-V Instruction Set Manual, раздел 2.4 Integer Computational Instructions, то увидишь, что опкод lui загружает константу собранную из 20 битов непосредственного значения из инструкции и 12 нулевых младших битов в целевой регистр, а auipc прибавляет такую же точно константу к PC и загружает в целевой регистр результат сложения, и в этом вся разница между ними.

    где какая используется не совсем понимаю.

    lui используется для генерации констант, которые не зависят от того, где расположен код, а auipc для генерации констант, которые двигаются вместе с кодом. Т.е. Если ты хочешь вызвать функцию, которая находится дальше чем ±2К от точки вызова, ты можешь сгенерировать её адрес инструкцией auipc, и полученный код будет работать одинаково, независимо от того, по какому адресу он будет размещён. А если тебе надо поместить в регистр константу, например 0x12345678, то ты можешь это сделать парой инструкций lui rd, 0x12345 ; addi rd, rd, 0x678 и значение константы будет всегда одинаковым, вне зависимости от того, где будет этот код.

    Каким образом одинаковые адреса различаются. Или они просто не могут быть одинаковыми(типа ос позаботиться)?

    Если есть MMU и он используется ОС, то есть и виртуальные адреса и они могут быть одинаковыми у разных процессов. Если MMU нет или он не используется, то ОС размещает все процессы в одном адресном пространстве, нет смысла говорить отдельно о виртуальных адресах, поскольку они равны физическим, адреса выделяемые ОС разным процессам могут быть как одинаковыми (например несколько процессов запущенных из одного исполняемого образа могут использовать один и тот же код и константные данные), так и разными (например изменяемые данные разные у всех процессов, а стеки разные у всех потоков).

    Как они в tlb обрабатываются, если вдруг они реально могут быть одинаковыми, и там нету ни каких дополнительных индексов процесса)

    Выбери конкретную процессорную архитектуру -- обсудим. у многих RISC-архитектур есть ASID, который идентифицирует адресное пространство и записывается вместе с виртуальным адресом в TLB. Но в любом случае ASID -- это просто оптимизация для повышения производительности, когда он отсутствует или переполняется ОС должна сбрасывать содержимое TLB при переключении адресного пространства.

    У ARM есть регистры TTBR с примерно той же функцией, что и cr3 в x86.
    У RISC-V есть CSR satp, содержащий ASID и базовый адрес корневого каталога страничных таблиц. Об этом можно прочитать в разделе 4.1.12 Supervisor Address Translation and Protection (satp) Register спецификации The RISC-V Instruction Set Manual Volume II: Privi....
    Ответ написан
    Комментировать
  • Как записать функцию в память, и вызвать по адресу c# небезопасный код?

    petermzg
    @petermzg
    Самый лучший программист
    Для этого нужно погрузиться в WinAPI.
    Вам следует сначала изучить флаги защиты страниц памяти, код может исполнятьтя только в странице памяти с флагом PAGE_EXECUTE.
    Потом нужно понимать в 32 или 64 битной среде выполняется код и какой calling convention нужен для функции, так как у 32 битной версии много типов передачи параметров cdecl, cdecl, fastcall, у 64 битной в основном fastcall.
    Ответ написан
    Комментировать
  • Зачем нужно выравнивание больше чем двойное машинное слово? Директива p2align 4 и более?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему нужно 512-356 байт нулями заполнять, почему нельзя продолжить дальше. Ведь следующая после 86*4 байт инструкция(или переменная) будет выровнена

    А вот еслы бы ты тупо взял и прочитал документацию на директиву .p2align, то у тебя таких вопросов не было бы. Потому что никто не заполняет 512-356 байт после. .p21lign выравнивает текущий адрес по заданной степени двойки. Обычно для этого есть аппаратные причины, например базовый регистр таблицы векторов прерываний может иметь 9 младших бит зафиксированных в 0. Или вот по границе страницы MMU выравнивают данные в ELF-файлах, чтобы можно было установить отдельно разрешения RX для кода и констант и RW для изменяемых данных.

    для получения элемента допустим table[index_nBit] можно применять операцию ИЛИ вместо сложения. Что быстрее. В этом ли дело

    Нет, не в этом.
    Ответ написан
    1 комментарий
  • Какой есть Алгоритм оптимизации перерасчета прочности соединений полигонов в системе при приложение силы?

    begemot_sun
    @begemot_sun
    Программист в душе.
    В общем случае для статической реализации - это система линейных уравнений с № неизвестными.
    Для динамической реализации - это система дифференциально-интегральных уравнений.
    Дальше копайте методы их решений.
    Ответ написан
    Комментировать
  • Какой есть Алгоритм оптимизации перерасчета прочности соединений полигонов в системе при приложение силы?

    Griboks
    @Griboks
    Ничего не понятно. Что такое 2d полигоны и балочные/нитевые/прямые/непрямые соединения, прямоугольники? Причём здесь дерево? Как алгоритм связан с количеством полигонов, если речь про расчёт соединений? Что именно рассчитывать, если соединения абсолютно нерастяжимые? Опишите, пожалуйста, задачу физически/математически.

    Если рассуждать абстрактно, то из точки приложения сила распространяется по дереву с затуханием, которое обусловлено коэффициентом сопротивления вращению абсолютно неупругой ветки относительно абсолютно неупругого ствола. Тогда можно найти минимально вращающегося родителя, затем рассчитать вращение потомков рекурсивно. Вращение потомка = собственное вращение + вращение родителя. Инерцией, натяжением, упругостью пренебрегаем. Родитель вращает потомков как жестко фиксированную систему материальных точек. Потомок вращает родителя как коэффициент сопротивления, т.е. ненмого вращается сам, немного вращает родителя.
    Ответ написан
    Комментировать
  • Какие части ПО могут быть общие у 2 операц. систем Wind-ы на 2 дисках разных? Лагает рабочий стол?

    @res2001
    Developer, ex-admin
    Возможно глюки какого-то из драйверов, может быть видео драйвера.
    Видимо, драйвер один и тот же используется в обеих виндах. Поэтому и ведет себя одинаково. Сам драйвер установлен в разные метса, но он один и тот же.
    Попробуйте обновить драйвер с сайта производителя. Или если уже стоит последняя версия - понизить версию.

    На счет загрузки ЦП - 10-20%% может быть не показатель. Если ядер много, а 10-20%% это средняя цифра по всем ядрам, то одно из ядер может быть загружена на 100%, а остальные по 1%. В менеджере задач включите отображение графика загрузки ЦП для всех ядрер.
    Ответ написан
    Комментировать
  • Какие части ПО могут быть общие у 2 операц. систем Wind-ы на 2 дисках разных? Лагает рабочий стол?

    @Drno
    Поставь вин10 ltsc
    Отключи автообновление драйверов виндой
    Отключи автообновление
    Установи драйвера с сайта производителя
    ручками
    Ответ написан
    3 комментария
  • Какие части ПО могут быть общие у 2 операц. систем Wind-ы на 2 дисках разных? Лагает рабочий стол?

    3r1k
    @3r1k
    the quieter you become, the more you hear
    рабочий стол начинает лагать. окна не перемешаются. списки под мюню ними обновляются с задержкой, скролы с задержкой, перемещение мышки с задержкой


    такое поведение характерно при переполнении буфера GPU.
    при таких условиях frame buffer нагружается на 100% и начинаются подобные лаги.
    Ответ написан
    5 комментариев
  • Почему StringBuilder при вызове метода ToString() копирует содержимое?

    vabka
    @vabka Куратор тега C#
    Токсичный шарпист

    Потом как правило объект StringBuilder находиться в методе, и сразу. умирает, то есть он вполне может использовать стек а не кучу

    Нет, не может, тк размер финальной строки заранее не известен, а если очень много памяти на стеке выделять, то его просто порвёт.


    Потом вообще почему любое new String (char[] ) копирует массив? почему не оборачивает

    Потому что string имеет контракт "никогда и ни при каких условиях содержимое строки не будет изменено". Если просто оборачивать, то этот контракт легко будет нарушить.

    А так да, можно и быстрее, если ты сможешь доказать, что ты никак не изменишь буфер, на котором основана строка после того, как можно будет использовать экземпляр string.

    Например как в случае со string.Create где ты можешь прокинуть лямбду, котороя сможет как угодно менять содержимое строящейся строки.
    string.Create выделяет память только один раз
    Ответ написан
    Комментировать
  • Какой смысл команды dup в JVM байт коде? И что за индексы локальных переменных?

    mayton2019
    @mayton2019 Куратор тега Java
    Bigdata Engineer
    Какой смысл команды dup в JVM байт коде?

    Жаль что ты не программировал на калькуляторе МК 60. Это целая эпоха.

    Значит есть разные пути к вычислению арифметики. Например если тебе надо возвести в квадрат число 5 на регистровой машине - то ты должен загрузить регистр R1 числом. Потом регистр R2. И потом найти такую команду умножения которая свяжет регистры R1 и R2 и перемножит и сохранит еще где-то результат. В силу современного зоопарка процессоров практически нереально создать такой абстрактный байткод который бы эффективно отображался на опкоды разных железяк. Поэтому решили забить на регистровую машину. И использовать стек как хранилище операндов для операций. Разумеется в JVM есть и аналоги регистров но с ними не выполняются операции. ЕМНИП. Если хошь что-то сложить или вызвать функцию - то положи на стек и там-же получи результат. И если вернуться к возведению числа 5 в квадрат это может быть так

    положить 5 на стек.
    дублировать
    вызвать функцию умножения


    На каком-нибудь языке Forth это было-бы тремя командами
    5 DUP * .
    Результат - на вершине стека.

    Это кратко записывается. Но это несет абсолютно ту-же смысловую нагрузку для арифметики.

    Почему их только 256 может быть?

    А чорт его знает. Так решили. Решили что 256 регистров это капец какой максимум для процедуры или функции. Послушай ради интереса видосы про процессор Эльбрус. Там тоже интересно с регистрами сделано.

    о есть на этапе генерации байт кода, сюда можно было после команды, просто адрес сразу впихнуть. И скорость выполнения должна же быть быстрее.

    Я думаю что твое предположение о том какой код соберет JIT не совсем верное.
    Вместо спора я предлагаю взять какой-то тестовый сценарий и подсмотреть какой
    будет собран код. Я знаю что скептики Java обычно после изучения вопроса глубже
    меняют свою точку зрения. Ну по крайней мере перестают считать Java
    "медленным покемоном". Java действительно была слоупоком во времена Jdk 1.1.
    Но щас это не так.

    Несколько лет назад я мерял производительность floating-point вычислений на приложении
    которое рендерит зеркальные шары. И разница между С++ и Java была не сильно большая.
    10 секунд на сях и 12 секунд на втором языке соотв. Хотя этот тест узкий и он просто
    показывает частный случай.
    Ответ написан
    4 комментария
  • Какой смысл команды dup в JVM байт коде? И что за индексы локальных переменных?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Java
    Седой и строгий
    Когда разрабатываешь сложные системы, стоит оперировать простыми абстракциями. А виртуальная машина - это очень сложно. Попытки кроилова на количестве операций в байткоде приведут к необходимости писать более сложный, менее стабильный и менее производительный код виртуальной машины.

    Значения локальных переменных хранятся в нативном массиве, выделяемом в каждом кадре стека вызовов. Для примитивных типов в нём хранятся сами значения, для ссылочных - ссылки в кучу. На этапе генерации байткода потому нельзя впихивать напрямую адреса, что байткод должен быть переносимым, неизвестно как может быть устроена память машин, на которых его могут выполнять.
    Ответ написан
    1 комментарий
  • Почему StringBuilder при вызове метода ToString() копирует содержимое?

    Alexeytur
    @Alexeytur
    String и char[] это разные вещи с точки зрения среды выполнения. char[] это изменяемый объект, можно по индексу изменить значение отдельного элемента. String это неизменяемый объект, операции изменения строки на самом деле создают копии оригинального объекта строки.
    Поэтому, если нужно создать строку через множество операций, используют StringBuilder, чтобы не было множества выделений/освобождений памяти.
    Ответ написан
    Комментировать
  • Как в runtime вставить в метод код, рефлексия, кодогенерация?

    vabka
    @vabka Куратор тега C#
    Токсичный шарпист
    Есть два варианта:
    https://www.postsharp.net/
    https://github.com/Fody/Fody
    А вот в рантайме, емнип, нельзя менять код.
    Но можно сгенерировать абсолютно новый код (новый класс с новым методом) через System.Reflection.Emit
    Ответ написан
    Комментировать
  • Что происходит во время прерывания в многопоточной среде? Или прерывания посреди прерывания?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    откуда прерывания знают адрес, куда им вернуть результат.

    Прерывания не знают. Это работа ОС -- организовать информацию так, чтобы при получении прерывания разобраться, откуда оно, зачем, и что с ним делать.

    Прерывание в коде int 21h и прочие Это какое?

    Любое прерывание инициируемое инструкцией int -- программное. В отличие от прерывания, инициируемого уровнем или фронтом сигнала подключённого к контроллеру прерываний.

    Вообще, кажется, если понять, что программные прерывания на x86 используются просто как удобный способ вызывать функции ядра, т.е. делать системные вызовы, то путаницы должно стать меньше. Не думай о них как о прерываниях, думай о них просто как о вызовах функций ядра. Ядро делает всё для того, чтобы для приложения это именно так и выглядело.

    выполнение прерывания std::cin>>line; Может и сутки длиться.

    Системного вызова. std::cin >>line в конце концов превращается в системный вызов read.

    Вот как по пунктам для этой команды. (С условием что есть еще 1 поток жаждущий ЦП).

    Можно запустить такую программу, узнать её PID, выполнить где-нибудь cat /proc/<PID>/stack и увидеть следующую картину:
    [<0>] wait_woken+0x67/0x80
    [<0>] n_tty_read+0x426/0x5a0
    [<0>] tty_read+0x135/0x240
    [<0>] new_sync_read+0x115/0x1a0
    [<0>] vfs_read+0xf4/0x180
    [<0>] ksys_read+0x5f/0xe0
    [<0>] do_syscall_64+0x33/0x80
    [<0>] entry_SYSCALL_64_after_hwframe+0x44/0xa9

    Т.е. поток выполнил системный вызов (ksys_read), зашёл в VFS, добрался до функции чтения в драйвере терминала (tty_read) и перешёл в состояние ожидания в глубине этой функции (wait_woken). Когда драйвер терминала получит данные для программы, он разбудит её поток и системный вызов завершится. До тех пор этот поток будет не готов к выполнению и скедулер ОС просто не будет выделять ему время.

    Мне кажется, что тебе было бы полезно прочитать вторую и третью книжки (Understanding the Linux Kernel и Linux Kernel Developmen) из моего списка.
    Ответ написан
    Комментировать
  • Как происходит доступ к эл. массива на уровне ядра? Malloc выделяет непрерывную физическую память?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как происходит доступ к эл. массива на уровне ядра?

    Так же как и на уровне приложения -- через трансляцию виртуального адреса в физический.

    Например массив Int* arr = new int[1024*1024*1024] он как храниться?

    Если мы для определённости возьмём linux, то у ядра есть несколько разных способов выделения памяти, в зависимости от того, для чего эта память выделяется. Есть наиболее простой и стандартный kmalloc который выделяет память непрерывную как виртуально так и физически. Обычно этим механизмом нельзя выделить большой непрерывный кусок. Есть vmalloc, который выделяет непрерывную виртуально, но возможно прерывную физически память. Есть get_free_pages который выделяет непрерывные страницы физической памяти, возможно, не отображаемые ни в какие виртуальные адреса. Есть Contiguous Memory Allocator который при старте системы резервирует кусок непрерывной физической памяти и может аллоцировать оттуда куски по запросу.
    Важный момент состоит в том, что аллокации делаемые ядром linux через упомянутые интерфейсы всегда обеспечиваются физической памятью, у памяти ядра нет пейджинга.

    А физическая, для массива то же? Ведь, так будет доступ намного быстрее?

    Почему быстрее? С точки зрения процессора всё равно будет трансляция виртуального адреса в физический, если повезёт -- попадание в TLB, если не повезёт -- ходить по каталогам и таблицам страниц в памяти.

    получается эмулятор каждый адрес вычислять что ли?

    Простой эмулятор -- да, наверно. Умный эмулятор может кешировать эту информацию, например именно это свойство даёт QEMU большую часть его Q.
    Ответ написан
    Комментировать
  • Зачем нужно выравнивание памяти? Точнее, почему процессор обращается 2 раза к невыравниным данным?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Вопрос такой что отвечая на него можно новую книгу написать. Тут даже С не причем. А причем - архитектура процессора x86. Кстати тут еще надо кеш-линии рассмотреть. Это фокус такой. Что если тебе надо 1 байт прочитать
    из произвольного адреса, современная архитектура этого не умеет. Она читает (обычно) кусок памяти шириной в 64 байта. Это обзывается кеш-линия. И уже из нее будет прочитан нужный байт. Отвечающие верно сказали выше. Еще можно добавить такое (условное правило) что тип данных должен лежать в сегменте данных по адресу кратному самому размеру типа. Тоесть int должен лежат на адресах кратных 4, long - 8 байт и так далее. Вот насчет MMX/SSE не знаю.
    Ответ написан
    1 комментарий
  • Как оптимально организовать структуру памяти, Кучу? Как она реализована в виртуальных машинах?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Там не происходиит копирование данных. Просто среда выаолнения запоминает, что переменная a лежит вон там внутри "массива" кучи. При чтении оттуда данных все происходит за одну асскмблерную операцию, как если бы вы читали из int.

    Пишущим на си++ из-за концепции указателей это все должно быть понятнее. При выделении данных на куче просто какой-то указатель указывает куда-то в кучу и все.
    Ответ написан
    Комментировать