День 1-1 · Феликс Гайзендорфер

День 1-1 · Феликс Гайзендорфер


День 1-1 · Феликс Гайзендорфер

Опубликовано:

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

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

Весь код и профили вы можете найти в истории этого репозитория: github.com/felixge/advent-2021.

Отказ от ответственности: в настоящее время я работаю над непрерывным профилированием Go для Datadog, но я не лаю здесь от имени своего работодателя.

Задачу дня 1-1 решить довольно легко, поэтому я быстро нашел простое решение, см. ниже.

func Answer(input string) (int, error) {
	var prev struct {
		val int64
		set bool
	}
	var increases int
	for _, line := range strings.Split(input, "\n") {
		val, err := strconv.ParseInt(line, 10, 64)
		if err != nil {
			return 0, err
		}
		if val > prev.val && prev.set {
			increases++
		}
		prev.set = true
		prev.val = val
	}
	return increases, nil
}

Это работает, но достаточно ли это быстро? Давайте проведем тест.

$ go test -count 5 -run '^$' -bench . -cpuprofile=v1.cpu.pprof > v1.txt
$ benchstat v1.txt
name      time/op
Answer-6  325ns ± 1%

Хотя вам это может показаться не таким уж плохим, это определенно не Christmas Scale™️, поэтому давайте выясним, что мы можем оптимизировать, взглянув на профиль нашего процессора как на FlameGraph:

Похоже, 44% нашего времени мы проводим в strings.Split()давайте это оптимизируем.

Глядя на FrameGraph выше, обратите внимание, что strings.Split() звонки strings.IndexByte() который реализован на ассемблере. Оказывается, мы можем вызвать это напрямую, чтобы выполнить собственное разделение новой строки:

func Answer(input string) (int, error) {
	var prev struct {
		val int64
		set bool
	}
	var increases int
	var line string
	for len(input) > 0 {
		i := strings.IndexByte(input, '\n')
		if i == -1 {
			line = input
			input = ""
		} else {
			line = input(0:i)
			input = input(i+1:)
		}
		val, err := strconv.ParseInt(line, 10, 64)
		if err != nil {
			return 0, err
		}
		if val > prev.val && prev.set {
			increases++
		}
		prev.set = true
		prev.val = val
	}
	return increases, nil
}

Это немного сложнее, но давайте посмотрим, что это нам дает:

$ benchstat v1.txt v2.txt 
name      old time/op  new time/op  delta
Answer-6   325ns ± 1%   168ns ± 2%  -48.25%  (p=0.008 n=5+5)

Сокращение времени выполнения на 48 % — похоже, у нас хорошее начало! Что дальше?

Похоже на strconv.ParseInt() стал нашим новым узким местом.

Хотя эльфы не заявляют об этом явно, они дают нам только положительные целые числа. Таким образом, мы могли бы применить тот же трюк, что и раньше, и вызвать strconv.ParseUint() напрямую, а не через strconv.ParseInt().

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

func parseInt(val string) (int64, error) {
	var intVal int64
	factor := int64(1)
	for i := len(val) - 1; i >= 0; i-- {
		c := val(i)
		if c >= '0' && c <= '9' {
			intVal += int64(c-'0') * factor
		} else {
			return intVal, fmt.Errorf("bad int: %q", val)
		}
		factor *= 10
	}
	return intVal, nil
}

Посмотрим, стоило ли оно того:

$ benchstat v2.txt v3.txt 
name      old time/op  new time/op  delta
Answer-6   168ns ± 2%    92ns ± 3%  -45.29%  (p=0.016 n=5+4)

Еще 45% — возможно, здесь мы, в конце концов, достигнем Christmas Scale™️.

Можем ли мы добиться еще большего?

Приведенный выше FlameGraph не дает нам никаких очевидных подсказок о том, что делать дальше. Но мы можем копнуть глубже. Например, давайте посмотрим, посмотрим View -> Source:

Как вы можете видеть, мы тратим довольно много времени на операцию подсрезов в режиме онлайн. 41. Это наша следующая подсказка?

v4: Ботаник-бекас

Эльфы сообщили мне, что текущее решение более чем в 3 раза быстрее, чем версия 1, что на данный момент достаточно хорошо:

$ benchstat v1.txt v3.txt 
name      old time/op  new time/op  delta
Answer-6   325ns ± 1%    92ns ± 3%  -71.68%  (p=0.016 n=5+4)

Однако они готовы предложить специальное предложение. Перейти к профилированию звезды всем, кому удастся улучшить версию v3. Здесь вы можете войти. Просто пришлите мне ссылку на ваше решение v4 в эта ветка в твиттере включая твой benchstats v3.txt v4.txt вывод, и я дам ссылку на него отсюда.

  1. Валентин Делеплас‘s решение с -87% дельта против v3
  2. Гарет Левин‘s решение с -83% дельта против v3
  3. Понтус Лейтцлер‘s решение с -74% дельта против v3
  4. @Фугиман‘s решение с -50% дельта против v3

Примечание: Приведенные выше результаты по разнице производительности получены самостоятельно. В моем собственном тестировании решение Валентина показало впечатляющие результаты. 14 ns/op и имеет -52% дельта против решения Гарета.

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

— Феликс Гейзендорфер


Подпишитесь на этот блог через RSS или по электронной почте или получайте от меня небольшие обновления через Твиттер.





Source link

Postagens Similares

  • Ufichuaji wa Jalada la Kipekee: Nipende Kama Wimbo wa Rock wa Shelly Jay Shore

    Leo kwenye tovuti ninayofuraha kumkaribisha tena Shelly Jay Shore ili kufichua jalada la Mapenzi yao yanayokuja, Nipende Kama Wimbo Wa Mwambaikitoa Agosti 25, 2026 kutoka kwa Dell! Hii ndio hadithi: Delilah ni mtunzi wa nyimbo anayetafuta jumba la kumbukumbu. Emmett ni golem iliyo tayari kutengenezwa. Kutoka kwa mwandishi anayeuza zaidi Kanuni za Ghosting inakuja riwaya…

  • Pergi Tanpa Cabang · Felix Geisendörfer

    Diterbitkan: 3 Desember 2021 Sepertinya postingan saya sebelumnya berhasil dan banyak dari Anda telah mengirimkan solusi Anda sendiri melalui twitter. Sebelum saya melanjutkan untuk memilih hari lain sebagai tantangan, saya ingin melakukan sedikit tindak lanjut untuk hari 1-1. Solusi Valentin Deleplace Mari kita mulai dengan melihat kemenangannya larutan dari Valentin Deleplace yang mencapai hasil spektakuler…

  • 2030 selvkjørende bilsats

    Det er min ære å kunngjøre at John Carmack og jeg har satt i gang en vennlig innsats på $ 10.000* til 501 (c) (3) veldedighet for vinnerens valg: Innen 1. januar 2030 vil helt autonome selvkjørende biler som møter SAE J3016 nivå 5 være kommersielt tilgjengelig for passasjerbruk i større byer. Jeg satser imotog…

  • (Sponsor) S&P Global

    Framtiden för informationsleverans är AI – och AI trivs med rena, pålitliga metadata. Det är därför S&P Global omfattar öppna webbstandarder för att göra data mer tillgängliga och maskinläsbara. Utforska våra öppna data på Dunl.org och upptäck rika metadata på Marketplace.spglobal.com. ★ Source link

  • 苦い錠剤のエンジニアリング |ダニエル・ミースラー

    私の AI エンジニアリングの随所で使用している、Bitter-Pilled Engineering (BPE) と呼ばれる新しい概念があります。 このアイデアは、リチャード・サットンのエッセイ「The Bitter Lesson」から来ています。 とりあえず、私のまとめです。 このエッセイでは、AI を制御、修正、強化しようとする人間の試みはすべて、ある種の価値がないと主張しています。なぜなら、より多くのハードウェアやより優れたアルゴリズムなどを通じて AI の知能を高めると、それ 人間のアプローチでできることよりもはるかに知性を向上させます。 私たち人間が AI には決して持たない魔法を持っていると考えるのはとても魅惑的ですが、その魔法は多くの場合単なる傲慢です。 実際にはそれよりも強いです。それだけでなく、 もっと良くならない 私たちが助けようとしても、おそらくそうなるでしょう はるかに悪い。 本質的に、実際には優れているわけではないため、優れていると思われるガイダンスによって AI のネイティブ機能を汚染することは避けるべきです。 エッセイからのいくつかの引用: 「70 年にわたる AI 研究から読み取れる最大の教訓は、コンピューティングを利用する一般的な手法が最終的には最も効果的であり、それを大幅に上回るということです。」 「私たちが望んでいるのは、私たちが発見したものを含む AI エージェントではなく、私たちと同じように発見できる AI エージェントです。」 「この恣意的な複雑さを見つけて捕捉できるメタメソッドのみを組み込む必要があります。」 「発見を組み込むと、発見プロセスがどのように行われるかを理解することが難しくなるだけです。」 私の要点: 論理、知性、効率についての私たちの考え方はおそらく原始的です したがって、AI に物事を「教える」方法にこれらのルールやアイデアをハードコーディングすべきではありません。 AI が賢くなるにつれて、第一原理に基づいて同じことを行うためのより良い方法が考え出されます。 残念ながら、私はその逆をする傾向が非常に強いので、この BPE の概念で自分自身をたたきつけなければなりません。 したがって、AI システムを構築するときの私自身の BPE ルールは次のとおりです。 自分の得意なアイデアや「賢い」アイデアをシステムに組み込んで、足場を過度に設計しないでください。代わりに、構築する足場が、より賢くなる基礎となる AI に対して堅牢で脆弱でないことを確認してください。 Source link

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *