Продолжая тему предыдущего поста, я хочу рассказать, как я пришёл к тому, чтобы переписать парсер под безусловные переходы и получить до 2х буста производительности
Для начала, стоит рассказать, как у меня этот самый парсер вообще устроен. Кратко - это обычный for-range по слайсу байт, и вложенный большой свитч по состояниям парсера.
Занимаясь предельной оптимизацией парсера (в который у меня всё по итогу и упирается), я додумался, что вместо того, чтобы при каждой итерации делать свитч по состоянию, я могу воспользоваться тем, что состояние обычно редко меняется (проход по пути запроса, ключу/значению заголовка, etc.), а значит, свитч в теле цикла у меня лишний. А свитч-то не маленький, на 32 состояния.
Подумал, и решил вынести независимые циклы по слайсу байт в кейсы свитча по состояниям. И тут я столкнулся с проблемой: я в парсере сохраняю негласную конвенцию о написании кода - практически везде, где нужно сравнение байта с 1 и более вариантов, я пишу свитч. А как известно, break в свитче прерывает этот самый свитч. А мне надо прерывать также цикл. Идея использовать if-else цепочку меня категорически отталкивает.
И тут я вспомнил о безусловных переходах! Панацея, подумал Штирлиц. И начал вставлять лейблы в парсер. Как оказалось позже, это вам не шахматы, тут думать надо. Решил проблему кардинально: убрал полностью главный цикл, свитч по состояниям вынес в начало функции для того, чтобы исходя из последнего состояния, сделать переход в нужную часть кода. Для "одноразовых" участков (участков, которые сразу же меняют состояние дальше), правда, пришлось немного покопипастить, но в целом терпимо. Запустил бенчмарки - парсер стал от 14% до 300% быстрее. Великолепно, подумал Миллер
Post #145
88