День 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

  • 鳥の名前 その1

    Bean Machine の回顧展の次の部分を理解するには、少し余談をする必要があります。私がブログを書き続けてきた約 20 年間を振り返ってみると、組み合わせ論理に対する自分の評価についてほんの少ししか言及していないことに驚きました。次の数回のエピソードでは、それを私に紹介した素晴らしい本に基づいて簡単に紹介します。 アラバマ物語をあざけるには、故レイモンド・スマリヤン著。 数羽の鳥、おそらく有限または無限の数の鳥がいる森を想像してください。これらは珍しい鳥です。森の鳥の種名を森の鳥に呼ぶと、森の鳥が呼び返します。同じかもしれないし、違うかもしれないが、あなたが鳥の名前を言うと、鳥はあなたにその鳥の名前を返します。森の中にアカショウビンの枢機卿がいるかもしれません。オオアオサギを呼ぶと、カワセミが呼び戻します。 (写真は私によるものです。クリックすると高解像度が表示されます。) 「電話しました」と記します。 Q に P そして返事が来た R” として PQ = R。それで声をかけたら S に R そして R と答えた T、それを次のように表記します PQS = RS = T。わかりやすい方法で括弧を使用します。 PQS = (PQ)S そしてこれは違うかもしれません P(QS)。後者は「電話しました」 S に Q、そして電話しました Qさんの返答 P「。特定の鳥の名前を表すには大文字を使用し、変数を表すには小文字を使用します。 ここで検討している質問は次のとおりです。 どのような状況下で、鳥はあなたが呼んだのと同じ名前を呼び返すでしょうか? つまり、特定の鳥に対して、 y、どのような状況で行われるか yx = x? スマリヤンは、この関係を持つ鳥を「愛情」と呼んでいます。y が好きです ×」ということは、 yx = x。もし y が好きです…

  • O Apicultor e o Mapa Cognitivo

    Eu assisti recentemente O apicultorum thriller de vingança estrelado por Jason Statham como Adam Clay, um agente aposentado de uma poderosa organização clandestina conhecida como “Apicultores” que existe além da CIA. A trama começa quando a senhoria e amiga idosa de Clay, Eloise Parker, é vítima de um sofisticado golpe de phishing que drena suas…

  • 不,AI不是泡沫

    而是聽論點 有一個流行的論點是這樣的: 人1:“ AI是泡沫。” 人2:“不,不是。氣泡是當事實被炒作的時候,事實證明是錯誤的。” 人1:“不,這只是意味著它像.com Bubble一樣充氣。我們仍然有互聯網嗎?” 這 聽起來 就像一個很好的論點,但我認為不是。 在野外這個論點的完美例子。 從最近的LinkedIn互動中 請注意,我們在這裡使用“氣泡”一詞。這意味著什麼? 在很多情況下,我會同意他們的看法。 認為AI是泡沫的人 可以 說: 它是“過熱的”,或者 它是“誇大的” 或任何其他指示明顯炒作的術語 但是他們不使用這些術語。他們說的是“泡泡”。 那麼,這實際上是什麼意思? 泡沫的最單一特徵是什麼?喜歡…在現實生活中。 氣泡彈出。 這就是氣泡的整個事情。當您進入大自然時,您會看到膨脹和收縮和生存的氣泡嗎? 不,他們彈出。這就像他們的主要事情。 這是我提供的有關氣泡的清潔解釋以及是否適用任何東西。 泡沫是一種虛假的信念,其中大量投資將很快被證明是錯誤的。 .com的東西是一個泡沫,它彈出了。 但是錯誤的信念不是 Internet™ 會炸毀並流行。那就是困惑的地方。 .com泡沫是錯誤的信念,即如果您將掙扎的業務帶到互聯網上,您將立即變得富有。 那 是彈出的信念。 因此,整個AI泡沫討論的技巧是找到虛假的主張。 什麼是 錯誤的 人們對人們擁有的AI的信念,他們會過度投資,這會追溯地被視為愚蠢之後嗎? 儘管並非所有這些投資都崩潰了。 是否就像每個人都相信您是否只是“添加AI”的示例,它們會立即成為百萬富翁?或許。也許一兩年。但是這些人中的大多數已經與現實相撞。 該泡沫在2023/2024中大部分都彈出。 兩個Marcusii。 不,我認為大多數反伊人喜歡馬庫斯(Hutchins和Gary Marcus) 實際上 視為泡泡蛋白,是以下位置(我持有的位置,順便說一句): 現代AI(或AI代或您想稱之為的任何東西)將導致業務完成方式的基本變化 它將在未來3 – 10年內取代數千萬的知識工作者 它將迫使我們不僅重新考慮當前的勞動力經濟,而且重新考慮人類工作和實用性的整個概念 如果您與認為AI是泡沫的人交談,這就是他們通常的意思。 因此,問題並不是大量的星空的AI投資者是否不知道發生了什麼,這會損失金錢。它已經發生了,現在正在發生,並且將繼續。這將是過於過早或其他不明智的投資的血液。每個人都知道。那不是真正的論點。 辯論是關於這項技術是否將改變商業,經濟和社會。…

  • Steve Yegge の予測記録

    私は予測を避けるようにしています。これは勝ちのない命題です。もしあなたが正しければ、後知恵バイアスにより、あなたが明白なことを指摘しているように見えてしまいます。そして、ほとんどの予測は外れます。時々、誰かが専門家の予測をレビューするとき、それらはほとんどの場合、少なくともランダムな偶然から予想される以上に間違っており、その後、後知恵バイアスにより、それぞれの予測が滑稽なほど悪いものに見えます。 しかし、時折、かなり確実で自明ではない予測をする人に遭遇することがあります。 Steve Yegge の古い作品を再読していたのですが、彼もそのような人物の 1 人であることがわかりました。 彼の最も有名な予測はおそらく JavaScript の台頭でしょう。これは後から考えると信じられないほど明白であるため、Gary Bernhardt の『JavaScript の誕生と死』で描かれている未来は少なくとも少しはもっともらしく思えます。しかし、スティーブのブログのコメントと、HN、reddit、その他のいつもの容疑者からのコメントの両方を読めば、当時のスティーブの予測がいかに自明ではなかったのかがわかります。 スティーブはまた、2004 年に未来について 10 件の予測を投稿するほど非常に勇敢でした。彼は「それらのほとんどはおそらく間違っています。演習のポイントは演習そのものであり、どのような結果が得られるかではありません。」と述べていますが、その予測は実際にはかなり合理的です。 予測 #1: 2011 年までに XML データベースの人気がリレーショナル データベースを超えるだろう 2011 年は少し早すぎたかもしれませんし、JSON は正確には XML ではありませんが、NoSQL データベースは、「O/R マッピングを好んで行う人はいません。誰もがソリューションを求めているだけです。」という予測に示されたほぼ理由により、非常にうまくいっていました。確かに、Mongo ではデータが失われる可能性がありますが、セットアップと使用は簡単です。 予測 #2: 誰かがオープンソース Web アプリケーションをホスティングして大金を稼ぐだろう これは「たくさん」が何を意味するかによって異なりますが、これは基本的に正しいようです。 私たちはホスト型 Web サービスの時代に急速に突入しており、大企業はスケーラブルなインフラストラクチャを活用して、専門知識を持たない企業のためにデータとコンピューティングをホストしています。 振り返ってみると不可解に思える理由ですが、Amazon は主要な競合他社よりもずっと前からこのことを理解しており、他の競合他社に大きく先んじてスタートを切ることができました。 Azure が開始されたのは 2009 年であり、Google がパブリック クラウド ホスティングに本格的に取り組んだのはさらに後になってからでした。 Steve が 2004 年に予測したことを誰もが理解した今、どの企業もパブリック クラウド製品を立ち上げようとしているように見えますが、市場の競争は非常に激しく、雇用は非常に困難になっています。アリババは、市場価格の整数倍を上回る多数のオファーを出してきたにもかかわらず、依然として競争力のあるパブリッククラウドを組み立てることができるチームをまとめることができておらず、アリババほど多くの現金を費やさずに今このゲームに参入しようとしている企業は、さらに困難な状況に直面している。…

  • کلچر سیریز: گلانڈنگ کے لیے ایک مکمل گائیڈ

    Iain M. Banks’ Culture Series میں، شہریوں کے پاس ایک جینیاتی طور پر انجینیئر شدہ عضو ہوتا ہے جسے منشیات کا غدود کہا جاتا ہے جو کہ نفسیاتی مادوں کو براہ راست ان کے خون کے بہاؤ میں طلب کرتا ہے۔ دس ناولوں میں ہر گلانڈنگ مادہ کا ذکر یا بیان کیا گیا ہے: مادہ…

  • RECENSION: Avgång(er) (Julian Barnes) – Läs Skriv Svara

    I ett färskt nyhetsbrev ställde Laura Hilliger frågan om varför vi läser memoarer och biografier: Varför läser du memoarer (om du ens gör det)? Jag läser biografier och memoarer delvis för att jag försöker förstå de inre liven hos människor som är kända för saker. Källa: FBT on Glistening and Gobsmacking av Laura Hilliger Jag…

Deixe um comentário

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