Согласен, насчёт константости - скорее всего враньё. А насчёт скорости: если посмотреть документацию на vers-vecs , то там написано
This crate uses compiler intrinsics for bit manipulation. The intrinsics are supported by all modern x86_64 CPUs, but not by other architectures. There are fallback implementations if the intrinsics are not available, but they are significantly slower. Using this library on x86 CPUs without enabling BMI2 and popcnt target features is not recommended.
The intrinsics in question are popcnt (supported since SSE4.2 resp. SSE4a on AMD, 2007-2008), pdep (supported with BMI2 since Intel Haswell resp. AMD Excavator, in hardware since AMD Zen 3, 2011-2013), and tzcnt (supported with BMI1 since Intel Haswell resp. AMD Jaguar, ca. 2013).
Всё правильно Серёга написал, это только особенность языка, что вызов super() должен быть первым оператором в конструкторе, на уровне байт-кода это не проверяется.
Я проверил это так. Написал пару классов:
public class Parent {
private final String name;
public Parent(String name) { this.name = name;}
public String getParentName() { return name;}
}
public class Child extends Parent {
private String myName;
public Child(String childName, String parentName) {super(parentName);this.myName=childName;}
public String getFullName() { return "I am " + myName + " , a child of a " + getParentName();}
public static void main(String[] args) {
Child child = new Child("ChildClass","ParentClass");
System.out.println(child.getFullName());
}
}
Скомпилировал, и через javap дизассемблировал. Конструктор класса Child выглядит вот так:
До меня не сразу дошло, в чём суть проблемы Identity. Если нужно проверить, что две ссылки указывают на один и тот же объект через равенство, то им не обязательно быть именно ссылками на память, можно формировать их на основе полей объекта, и это сработает. Но проблема Identity состоит в том, что ссылки на два разных объекта с одними и теми же полями обязаны быть не равны.
Эта статья вызвала мой интерес не тем, что она про нейросети, а видом сжатого С-кода. Дело в том, что очень похожий стиль принят среди разработчиков на языках k и q, и интерпретаторы этих языков часто пишут в таком сжатом стиле, который мне даётся с трудом. Я подумал, что ну вот, может тут расскажут, как писать такое, поделятся секретами. А нифига, я сходил на github, и там исходники лежат в гораздо более понятном виде, и питоновский скрипт, который выполняет сжатие. Но при ближайшем рассмотрении оказалось, что питоновский скрипт делает довольно тупые действия, и автору в основном исходнике приходится самому прибегать к препроцессорной магии.
Когда я дошёл до раздела, где объясняется препроцессорная магия для матрично-скалярных и матрично-матричных операций, я сначала нифига не понимал, до тех пор, пока исходники не почитал. Дело в том, что в тексте вроде как define-ится BINARY с двумя аргументами (function и operation) в нижнем регистре, а потом в теле этого BINARY эти же аргументы стоят в верхнем регистре (FUNCTION и OPERATION), это очень сбивает с толку. Это не проблема перевода, в оригинальном тексте тоже так, в исходниках всё норм (fn и opr везде). Ну и раз уж зашла речь про BINARY, то я бы в начале проверил, что размеры матриц совпадают, fail fast и всё такое. Забавно, что он вводит поэлементное умножение и деление матриц, я такого не видел в математике, но у него находит применение в LayerNorm.
В описании математического матричного умножения у автора тоже косяк, в первом, неоптимизированном варианте остались k2 и j2.
Эта статья слишком коротка. Я с первого раза ничего не понял, рассуждения показались мне слишком абстрактными. Потом я взглянул на вашу библиотеку, и понял, что мне не показалось.
newtype W_II_II_I w i ii = W_II_II_I (w ii ii i)
Я не настоящий хаскеллист, что такое функтор я понял, что такое монада - тоже понял, стрелку уже не осилил, а вот этих ваших абстракций спасибо не надо.
Что касается вашей исходной посылки про сложности предметных областей, то программирование не создано, чтобы бороться с этим.
Самый простой способ написать эмулятор и виртуальную машину - это написать интерпретатор, с центральным бесконечным циклом, внутри которого будет происходить выборка команд с последующим switch-ем по опкодам. В случае эмулятора нет смысла делать что-то другое (типа threaded code), потому что после каждой команды нужно проделать некоторые общие вещи: посчитать число тактов, проверить, не возникло ли прерывание, проэмулировать другие компоненты, помимо CPU. Кроме того, архитектура реальных машин такова, что код хранится в памяти, то есть может быть изменён в процессе выполнения, и стек тоже находится в памяти. Это значит, что JIT/AOT применять не получится. А виртуальная машина - она "виртуальная", потому что у неё, как правило, отдельно память данных, отдельно хранилище кода, отдельно локальные переменные, отдельно стек возвратов, отдельно стек операций. То есть высокоуровневые вещи, ограничивающие всякие трюки в коде, но позволяющие JIT/AOT и прочие оптимизации.
То есть для эмуляторов отказываться от цикла со switch-ем - это, с одной стороны, усложнение кода, а с другой стороны - вообще не нужно, всё равно скорость и задержки надо эмулировать.
Вообще не в тему комментарий. Эмулятор конкретного железа не является байткод-машиной, потому что должен повторять потактово время выполнения инструкций эмулируемого железа, нет никакой необходимости добиваться некоей "максимальной" производительности.
Отличная статья! Поймал себя на том, что смотрю на нули и единицы в закодированном представлении bitmap-а, и вижу мышку.
Хочу спросить про ассемблерную процедуру: вы в ней испортили HL и A, их не надо было сохранять и восстанавливать?
И про сам язык хотел спросить. Вы положили в массив и размеры битмапа, и сам битмап. А нет в языке поддержки struct, чтобы длину и ширину класть в именованные поля?
Я не понял, зачем это может быть нужно. Я не спец в системе модулей Scheme, и не понимаю, что такое "динамическая подгрузка" модулей, но разве модуль - это не набор define-ов, которые все одновременно попадают в область видимости? Если функция инициализации попала в область видимости, то и всё остальное содержимое модуля тоже попало.
Я догадываюсь, что это может быть полезно во всяких макросах.
По мере чтения статьи у меня возникали разные вопросы, но потом я сам находил на них ответы. Чтобы это не пропало, я это сюда в виде комментария сброшу.
Если я правильно понял, то идея демо такая: буфер не очищается, на каждом шаге в него добавляются белые точки, и потом проходит блюр. Наверное, при многократных исполнениях такого цикла изображение должно стремиться к белому. Но операция деления на 4 проходит с отбрасыванием дробной части, что, в свою очередь, даёт смещение в сторону чёрного. То есть подобрав количество добавляемых белых точек можно получить относительно стабильный баланс серого.
Я так понимаю, что способ определить начало буфера через добавление константы к сегментному регистру работает, потому что тупо есть органичение, что com-файлы не могут быть больше 64кб, поэтому нефиг заморачиваться.
В том цикле, который палитру создаёт, вам точно надо mov ax, 1010hделать каждый раз внутри цикла? Может вынести в начало?
С блюром у вас занятно: для самого верхнего ряда вы обращаетесь и к предыдущим 320 байтам, которые вообще не в буфере. Кроме того, поскольку вы счётчик цикла инициализируете в 0000h, то цикл обработает 10000h байт, хотя достаточно обработать fa00h байт. Но, поскольку вы стремитесь к уменьшению размера программы, а не к скорости, то это понятно.
В цикле блюра можно было бы обойтись одним регистром, тем же SI. Я думаю, что inc si выставит флаг нуля, и вместо loop сделать переход через jnz. Если SI для этого не подойдёт, то его в цикле можно заменить на BX, он тоже умеет в адресацию со смещением.
Не могли бы вы подтвердить ваш комментарий конкретикой: подробнее рассказать, какие именно легаси и костыли в IDEA ? Особенно интересно послушать про "кучу".
Пользуюсь IDEA уже дохреналлион лет, сижу на Community и буду продолжать. JetBrains - молодцы, делают отличный продукт. Spring boot знаю, но использую по минимуму, стараюсь избегать участия в разработке CRUD-сервисов. Плагин amplicode не использовал, чуть знаком: но на прошлой неделе в нашей организации был воркшоп, на котором этот плагин презентовал сотрудник фирмы-разработчика, очень толковый парень по имени Илья. Очень надеюсь, что мне не придётся писать сервисы, в котором этот плагин бы пригодился, все эти JPA, мапперы, контроллеры - ну тоска же зелёная! К инициативе по перепаковке чужого кода отношусь нейтрально, является ли это IDE, JDK или линукс. К заманухам про "бесплатность" и "открытость" отношусь скептически, потому что IDEA CE также бесплатна и открыта. Пользоваться перепакованной IDE не буду. Сообщества там нет и не будет. К автору статьи, который отмечается под каждым комментарием, отношусь отрицательно.
Если сотрудник в процессе работы чувствует, что недостаточно профессионален для выполнения задачи или вообще для должности/позиции, пришёл к руководителю признать этот факт и попросить помощи - то это высокая степень профессионализма. Статья же напоминает известные шутки "Ну вы же профессионал/коммунист".
Дрон ощущается хорошо, с ним хорошо придумано. Пейзажи выглядят норм, реалистично, а персонажи выглядят и анимированы очень нереалистично, это очень заметно на фоне пейзажей.
Я позавчера поиграл в демо, мне понравилось, автор молодец. Головоломки несложные, атмосфера серой тоскливой зимы передана хорошо. Многие игры делают вид, что у них сложный мир, оригинальный сюжет и им есть что сказать, и эта игра не исключение, но я уже привык. Свободы исследования нет, всё линейно, стенки невидимые кругом и двери неоткрывающиеся.
Выражение "это тест".length() вернёт 8. Выражение "это тест".getBytes("UTF-8").length вернёт 15. Вы в заголовок "Content-Length" передали первое, причём сразу через sendHeaders(), чтобы улетело, а в response body передали второе.
Ох уж этот сам себя нахваливающий автор-графоман, со своими статьями "для профессионалов разработки на Java", объясняющий, что такое DI-контейнер и "откуда сервлет достаёт параметры HTTP-запроса".
У вас в первом же куске кода (пример использования сервера) лажа: вы задаёте заголовок "Content-Length" как длину строки в символах, а потом в тело ответа эту строку с кириллическими буквами кодируете в байты в UTF-8, у вас получится не 8, а 15 байт.
Контейнер у вас забавный: вам надо бины и пометить интерфейсом, и передать в setup(). Теоретически можно было бы считать, что в setup() передавать надо только те бины, которые потом через getInstance() получают, но нифига не сработает, ваш массив классов cl ограничен тем размером, который передаётся в setup(). Вообще не очень понятно, зачем marker-интерфейс Dependency, всё равно у вас все параметры конструктора должны быть внедряемыми зависимостями, иначе вы экземпляр не создадите. Метод addClassNum(), который проходится по массиву, включая незаполненную часть, и проверяющий классы через equals() - не очень производительно.
В хранилище сессий у вас утечка памяти: если пользователь не делает явно "logout", а просто закрывает страницу и уходит, то сессия останется в хранилище навечно. Поэтому не непонятно, нафига вы делали протухание сессий? Этот механизм не от хорошей жизни придуман, он может доставлять неудобство пользователю, но в настоящих http-серверах сессия вычистилась по таймеру и потом её уже взять неоткуда, а вы её удаляете и тут же создаёте новую. С вашим ограничением на количество сессий - беда, новые пользователи зайти не смогут.
Вообще с сессиями не очень наглядно вышло, лучше было бы хранить язык пользователя в ней на сервере, а не через cookie передавать.
Вот смотрю я на картинку, на которой увеличенный кусок Goody с артефактом, и смущает меня кое-что. Получается, что графика в игре примерно в два раза хуже разрешением, чем экран поддерживает. Это мне очень сомнительно, чтобы разработчики не использовали разрешение на полную. Цветные режимы CGA - это 320x200, на глаз соответствует разрешению полной картинки. Мне лень брать картинку и считать пиксели в ней. Я думаю, это отмасштабированный DosBox-ом вывод, в котором автор руками немного добавил пикселей, только с разрешением не угадал. Но статья хорошая, мне понравилась
Две ночи подряд я выходил в 23:15, брал термометр и картонку, и измерял температуру, прикрывая небо картонкой и не прикрывая. Выдерживал по 10 минут. Чередовал. Как было 21 градус, так и осталось. Даже тупо руку ладонью направить к звёздному небу и к земле - никакой разницы по ощущениям. Во всеуслышание объявляю вашу теорию ложной. Но я не в накладе, я первый раз в жизни увидел метеор!
Согласен, насчёт константости - скорее всего враньё. А насчёт скорости: если посмотреть документацию на vers-vecs , то там написано
Забавная статья. Стиль автора, обещающий жареных фактов, никуда не делся, но хоть себя не нахваливает, уже лучше.
Ага, говорили. И это, конечно же, не было опровергнуто в статье.
Всё правильно Серёга написал, это только особенность языка, что вызов super() должен быть первым оператором в конструкторе, на уровне байт-кода это не проверяется.
Я проверил это так. Написал пару классов:
Скомпилировал, и через javap дизассемблировал. Конструктор класса Child выглядит вот так:
С jvm-ассемблерами оказалось много возни, поэтому я просто шестнадцатеричным редактором переставил байты, чтобы стало вот так:
И всё отлично работает.
До меня не сразу дошло, в чём суть проблемы Identity. Если нужно проверить, что две ссылки указывают на один и тот же объект через равенство, то им не обязательно быть именно ссылками на память, можно формировать их на основе полей объекта, и это сработает. Но проблема Identity состоит в том, что ссылки на два разных объекта с одними и теми же полями обязаны быть не равны.
Эта статья вызвала мой интерес не тем, что она про нейросети, а видом сжатого С-кода. Дело в том, что очень похожий стиль принят среди разработчиков на языках k и q, и интерпретаторы этих языков часто пишут в таком сжатом стиле, который мне даётся с трудом. Я подумал, что ну вот, может тут расскажут, как писать такое, поделятся секретами. А нифига, я сходил на github, и там исходники лежат в гораздо более понятном виде, и питоновский скрипт, который выполняет сжатие. Но при ближайшем рассмотрении оказалось, что питоновский скрипт делает довольно тупые действия, и автору в основном исходнике приходится самому прибегать к препроцессорной магии.
Когда я дошёл до раздела, где объясняется препроцессорная магия для матрично-скалярных и матрично-матричных операций, я сначала нифига не понимал, до тех пор, пока исходники не почитал. Дело в том, что в тексте вроде как define-ится BINARY с двумя аргументами (function и operation) в нижнем регистре, а потом в теле этого BINARY эти же аргументы стоят в верхнем регистре (FUNCTION и OPERATION), это очень сбивает с толку. Это не проблема перевода, в оригинальном тексте тоже так, в исходниках всё норм (fn и opr везде). Ну и раз уж зашла речь про BINARY, то я бы в начале проверил, что размеры матриц совпадают, fail fast и всё такое. Забавно, что он вводит поэлементное умножение и деление матриц, я такого не видел в математике, но у него находит применение в LayerNorm.
В описании математического матричного умножения у автора тоже косяк, в первом, неоптимизированном варианте остались k2 и j2.
Эта статья слишком коротка. Я с первого раза ничего не понял, рассуждения показались мне слишком абстрактными. Потом я взглянул на вашу библиотеку, и понял, что мне не показалось.
Я не настоящий хаскеллист, что такое функтор я понял, что такое монада - тоже понял, стрелку уже не осилил, а вот этих ваших абстракций спасибо не надо.
Что касается вашей исходной посылки про сложности предметных областей, то программирование не создано, чтобы бороться с этим.
Самый простой способ написать эмулятор и виртуальную машину - это написать интерпретатор, с центральным бесконечным циклом, внутри которого будет происходить выборка команд с последующим switch-ем по опкодам. В случае эмулятора нет смысла делать что-то другое (типа threaded code), потому что после каждой команды нужно проделать некоторые общие вещи: посчитать число тактов, проверить, не возникло ли прерывание, проэмулировать другие компоненты, помимо CPU. Кроме того, архитектура реальных машин такова, что код хранится в памяти, то есть может быть изменён в процессе выполнения, и стек тоже находится в памяти. Это значит, что JIT/AOT применять не получится. А виртуальная машина - она "виртуальная", потому что у неё, как правило, отдельно память данных, отдельно хранилище кода, отдельно локальные переменные, отдельно стек возвратов, отдельно стек операций. То есть высокоуровневые вещи, ограничивающие всякие трюки в коде, но позволяющие JIT/AOT и прочие оптимизации.
То есть для эмуляторов отказываться от цикла со switch-ем - это, с одной стороны, усложнение кода, а с другой стороны - вообще не нужно, всё равно скорость и задержки надо эмулировать.
Вообще не в тему комментарий. Эмулятор конкретного железа не является байткод-машиной, потому что должен повторять потактово время выполнения инструкций эмулируемого железа, нет никакой необходимости добиваться некоей "максимальной" производительности.
Отличная статья! Поймал себя на том, что смотрю на нули и единицы в закодированном представлении bitmap-а, и вижу мышку.
Хочу спросить про ассемблерную процедуру: вы в ней испортили HL и A, их не надо было сохранять и восстанавливать?
И про сам язык хотел спросить. Вы положили в массив и размеры битмапа, и сам битмап. А нет в языке поддержки struct, чтобы длину и ширину класть в именованные поля?
Я не понял, зачем это может быть нужно. Я не спец в системе модулей Scheme, и не понимаю, что такое "динамическая подгрузка" модулей, но разве модуль - это не набор define-ов, которые все одновременно попадают в область видимости? Если функция инициализации попала в область видимости, то и всё остальное содержимое модуля тоже попало.
Я догадываюсь, что это может быть полезно во всяких макросах.
По мере чтения статьи у меня возникали разные вопросы, но потом я сам находил на них ответы. Чтобы это не пропало, я это сюда в виде комментария сброшу.
Если я правильно понял, то идея демо такая: буфер не очищается, на каждом шаге в него добавляются белые точки, и потом проходит блюр. Наверное, при многократных исполнениях такого цикла изображение должно стремиться к белому. Но операция деления на 4 проходит с отбрасыванием дробной части, что, в свою очередь, даёт смещение в сторону чёрного. То есть подобрав количество добавляемых белых точек можно получить относительно стабильный баланс серого.
Я так понимаю, что способ определить начало буфера через добавление константы к сегментному регистру работает, потому что тупо есть органичение, что com-файлы не могут быть больше 64кб, поэтому нефиг заморачиваться.
В том цикле, который палитру создаёт, вам точно надо
mov ax, 1010h
делать каждый раз внутри цикла? Может вынести в начало?С блюром у вас занятно: для самого верхнего ряда вы обращаетесь и к предыдущим 320 байтам, которые вообще не в буфере. Кроме того, поскольку вы счётчик цикла инициализируете в 0000h, то цикл обработает 10000h байт, хотя достаточно обработать fa00h байт. Но, поскольку вы стремитесь к уменьшению размера программы, а не к скорости, то это понятно.
В цикле блюра можно было бы обойтись одним регистром, тем же SI. Я думаю, что inc si выставит флаг нуля, и вместо loop сделать переход через jnz. Если SI для этого не подойдёт, то его в цикле можно заменить на BX, он тоже умеет в адресацию со смещением.
Очень хорошая статья!
Не могли бы вы подтвердить ваш комментарий конкретикой: подробнее рассказать, какие именно легаси и костыли в IDEA ? Особенно интересно послушать про "кучу".
Пользуюсь IDEA уже дохреналлион лет, сижу на Community и буду продолжать. JetBrains - молодцы, делают отличный продукт. Spring boot знаю, но использую по минимуму, стараюсь избегать участия в разработке CRUD-сервисов. Плагин amplicode не использовал, чуть знаком: но на прошлой неделе в нашей организации был воркшоп, на котором этот плагин презентовал сотрудник фирмы-разработчика, очень толковый парень по имени Илья. Очень надеюсь, что мне не придётся писать сервисы, в котором этот плагин бы пригодился, все эти JPA, мапперы, контроллеры - ну тоска же зелёная! К инициативе по перепаковке чужого кода отношусь нейтрально, является ли это IDE, JDK или линукс. К заманухам про "бесплатность" и "открытость" отношусь скептически, потому что IDEA CE также бесплатна и открыта. Пользоваться перепакованной IDE не буду. Сообщества там нет и не будет. К автору статьи, который отмечается под каждым комментарием, отношусь отрицательно.
Если сотрудник в процессе работы чувствует, что недостаточно профессионален для выполнения задачи или вообще для должности/позиции, пришёл к руководителю признать этот факт и попросить помощи - то это высокая степень профессионализма. Статья же напоминает известные шутки "Ну вы же профессионал/коммунист".
Дрон ощущается хорошо, с ним хорошо придумано. Пейзажи выглядят норм, реалистично, а персонажи выглядят и анимированы очень нереалистично, это очень заметно на фоне пейзажей.
Я позавчера поиграл в демо, мне понравилось, автор молодец. Головоломки несложные, атмосфера серой тоскливой зимы передана хорошо. Многие игры делают вид, что у них сложный мир, оригинальный сюжет и им есть что сказать, и эта игра не исключение, но я уже привык. Свободы исследования нет, всё линейно, стенки невидимые кругом и двери неоткрывающиеся.
Знаю конечно.
Выражение "это тест".length() вернёт 8. Выражение "это тест".getBytes("UTF-8").length вернёт 15. Вы в заголовок "Content-Length" передали первое, причём сразу через sendHeaders(), чтобы улетело, а в response body передали второе.
Ох уж этот сам себя нахваливающий автор-графоман, со своими статьями "для профессионалов разработки на Java", объясняющий, что такое DI-контейнер и "откуда сервлет достаёт параметры HTTP-запроса".
У вас в первом же куске кода (пример использования сервера) лажа: вы задаёте заголовок "Content-Length" как длину строки в символах, а потом в тело ответа эту строку с кириллическими буквами кодируете в байты в UTF-8, у вас получится не 8, а 15 байт.
Контейнер у вас забавный: вам надо бины и пометить интерфейсом, и передать в setup(). Теоретически можно было бы считать, что в setup() передавать надо только те бины, которые потом через getInstance() получают, но нифига не сработает, ваш массив классов cl ограничен тем размером, который передаётся в setup(). Вообще не очень понятно, зачем marker-интерфейс Dependency, всё равно у вас все параметры конструктора должны быть внедряемыми зависимостями, иначе вы экземпляр не создадите. Метод addClassNum(), который проходится по массиву, включая незаполненную часть, и проверяющий классы через equals() - не очень производительно.
В хранилище сессий у вас утечка памяти: если пользователь не делает явно "logout", а просто закрывает страницу и уходит, то сессия останется в хранилище навечно. Поэтому не непонятно, нафига вы делали протухание сессий? Этот механизм не от хорошей жизни придуман, он может доставлять неудобство пользователю, но в настоящих http-серверах сессия вычистилась по таймеру и потом её уже взять неоткуда, а вы её удаляете и тут же создаёте новую. С вашим ограничением на количество сессий - беда, новые пользователи зайти не смогут.
Вообще с сессиями не очень наглядно вышло, лучше было бы хранить язык пользователя в ней на сервере, а не через cookie передавать.
Вот смотрю я на картинку, на которой увеличенный кусок Goody с артефактом, и смущает меня кое-что. Получается, что графика в игре примерно в два раза хуже разрешением, чем экран поддерживает. Это мне очень сомнительно, чтобы разработчики не использовали разрешение на полную. Цветные режимы CGA - это 320x200, на глаз соответствует разрешению полной картинки. Мне лень брать картинку и считать пиксели в ней. Я думаю, это отмасштабированный DosBox-ом вывод, в котором автор руками немного добавил пикселей, только с разрешением не угадал. Но статья хорошая, мне понравилась
Две ночи подряд я выходил в 23:15, брал термометр и картонку, и измерял температуру, прикрывая небо картонкой и не прикрывая. Выдерживал по 10 минут. Чередовал. Как было 21 градус, так и осталось. Даже тупо руку ладонью направить к звёздному небу и к земле - никакой разницы по ощущениям. Во всеуслышание объявляю вашу теорию ложной. Но я не в накладе, я первый раз в жизни увидел метеор!