パスワードを忘れた? アカウント作成
13452839 story
UNIX

高性能化のための改善が続けられているyesコマンド 68

ストーリー by headless
高速 部門より
insiderman 曰く、

「y」という文字を出力するだけのUNIXコマンド「yes」は改良が続けられており、性能が強化されているそうだ(POSTDの記事)。

yesコマンドは、単純にループを使って標準出力に「y」を出力するプログラムよりも数十倍速いという。もちろんコードも複雑になっているのだが、なかなかその手法は興味深い。ただ、本当にそのスループットが必要かはちょっと疑問ではあるが……。

元記事はGNU版yesコマンドのスループットが10.2GiB/sというReddit記事に触発され、この速度にRustで挑戦したという話のようだ。日本語訳には何か所か細かい間違いもあるので、英文を読むのが苦にならない方は原文もあわせて参照するといいだろう。

  • by ilonasive (6257) on 2017年11月11日 19時10分 (#3310780)

    GNUのyesコマンドと対照的なのがOpenBSDのyesコマンドのソース [openbsd.org]。

    ご覧のとおり見たまんまで、まったく捻りなし。

    特徴的なのが、実行開始時にpledgeというシステムコールを発効しているところ。
    これを行うことで、それ以降のシステムコールの実行を標準入出力関連のものだけに制限している。
    もしyesに脆弱性があっても、それを利用した悪さができにくいようになっている。

    改善というのは高性能化だけではない、ってことですな。

    ここに返信
    • by Anonymous Coward

      楽しいね。
      この単純なプログラムでさえ、システムコールを制限しようとする姿勢が。

      FreeBSDはどうなんだろう、と思ってみたらちょっと長くて [openbsd.org]読んでない。

      • by Anonymous Coward

        リンクミスった。
        FreeBSDのは こっち。 [github.com]
        ちなみにやってることはOpenBSD + バッファ使った性能向上かなあ。
        斜め読みというか、斜め見した感じ。

        ちなみにminix 2.0.4のyesは以下。
        yes[n++]= '\n';ってなんでやってるんだろう。
        argv[1]って最後に終端はいるよね?

        /* yes 1.4 - print 'y' or argv[1] continuously. Author: Kees J. Bot
          * 15 Apr 1989
          */
        #include
        #include
        #include
        #include

        int main(int argc, char **argv)
        {
                char *yes;
                static char y

        • by tmiura (6268) on 2017年11月11日 19時52分 (#3310801) 日記

          |yes[n++]= '\n';ってなんでやってるんだろう。
          |argv[1]って最後に終端はいるよね?

          その終端がヌルターミネータだから改行を追加しているのでは。

          ヌルターミネータを上書きして大丈夫なのかと一瞬思ったが、writeで長さ指定してた。

        • by Helion (8785) on 2017年11月11日 19時54分 (#3310802) 日記

          yes[n++]= '\n';ってなんでやってるんだろう。

          これがないと出力が改行なし ("yyyyy...") になっちゃいますね。

          • by Anonymous Coward

            なるほど。
            意味がわかったでござる。

            tmiura氏のNULL Terminatorの話も、説明されてわかった。
            \0 を \nで上書きしていると。
            writeだから\0はいらないわけね。

    • by Anonymous Coward

      plegdeは良いと思うけれど、同じ意味のfor(;;) puts()が繰り返されるのが嫌だな。
      私はV7の三項演算子使ったやつの方が好き。

      • by Helion (8785) on 2017年11月11日 19時43分 (#3310797) 日記
        これ [tuhs.org]だとループごとにargc>1の判定が入るように見えてちょっと気になります (もちろん実際には最適化されるでしょうけど)
        • by Anonymous Coward

          最適化されない気がする。引数が処理中に書き換わる可能性がゼロじゃないと。

          • by Anonymous Coward

            argc>1の評価はmain()の呼出毎に不変だから現代のコンパイラなら最適化されるよ。

            main(argc, argv)
            char **argv;
            {
                    char *p = argc>1? argv[1]: "y";

                    for (;;)
                            printf("%s\n", p);
            }

            みたいな感じに解釈されると思う。

    • by Anonymous Coward

      OpenBSD って if や for の後が単文なら {} つけない流儀?

  • by Anonymous Coward on 2017年11月11日 16時32分 (#3310734)

    一番手軽なので/dev/nullにリダイレクトしてCPU負荷張り付きとか高温時の制限機能のデバッグとかで使わせてもらってます。
    なるほど、どうりで高効率で食い潰せるわけだ。

    ここに返信
    • by Anonymous Coward

      り、りょうほーですかあああ〜と聞かれた時にも使えるしね

  • by Anonymous Coward on 2017年11月11日 15時28分 (#3310711)

    ギガyes毎秒のほうが良くないかな?

    ここに返信
    • by miyuri (33181) on 2017年11月11日 15時41分 (#3310715) 日記

      おそらく半分になって、イマイチな気分になるから、よろしくないかもしらないみたいな。

    • by Anonymous Coward

      yes コマンドの引数で繰り返す文字(や文字列)を指定できる。
      長い文字列ならば、当然遅くなるので(線形ではないだろうが)、Bytesでいい気もする。

      結構スリリング。
      #yes no | rm -ir *

  • by Anonymous Coward on 2017年11月11日 15時53分 (#3310720)

    yesコマンドなんて最初は「何だこれ?」と思ったけど
    最近はPC起動するたびに使ってる気がする
    何かと手間が省けるんだよね
    地味イーーにものぐさができる

    ここに返信
    • by Anonymous Coward on 2017年11月12日 3時02分 (#3310881)

      横棒グラフを端末でちゃちゃっと出したかったんだけど、perlを持ち出すほどじゃないよなってとき
      yes '*' | head -n 10 | tr -d '\n'
      とか
      yes '*' | head -n 10 | paste -s -d ''
      でなんとかやりくりした思い出…
      yes -d '' -n 10 '*'
      とかでぱぱっと ********** が出てくれないかなー。だめかな?UNIX原理に反するもんね

    • by Anonymous Coward

      つい

    • by Anonymous Coward

      初期のUNIXのシンプルさ、柔軟さを今に伝える貴重なプログラム。
      ...なのだが、GNU 版のソースとかを見るとロブ・パイクがUNIXは腐臭を放っていると発言したのも最もだと思わせる。

      • by Anonymous Coward

        でも例えばprintfを改良してどうにかなる問題じゃないからな。ループで問答する時のバッファをどうするかって話なんだから、まさにアルゴリズムの優劣が結果にダイレクトに反映されてるわけだ。

        • by miyuri (33181) on 2017年11月11日 16時31分 (#3310732) 日記

          アルゴリズムとは言い難い感じ。
          一行ずつチマチマ投げるよりも、ページ境界に合うのを期待した大きい領域に何行も詰め込んで投げる方が早いよねっていう。

          • by Anonymous Coward

            > 一行ずつチマチマ投げるよりも、ページ境界に合うのを期待した大きい領域に何行も詰め込んで投げる方が早いよねっていう。

            なんで後者の方が早いんですか?

            • by Anonymous Coward

              境界またがったら2ページ分の操作が要るとか
              というか、パディング分の領域が無駄になるとか
              再構成の時間がかかるとか
              いろいろ

              • Re:yes! (スコア:3, 参考になる)

                by annoymouse coward (11178) on 2017年11月11日 19時36分 (#3310793) 日記

                一番の理由はシステムコールのオーバヘッドですよ

                一行ずつチマチマ投げるとその都度システムコールが発行されます

                これが結構重たい処理になります.システムコールが発行されると,その都度,ユーザ空間とカーネル空間の切り替え,
                CPUのレジスタの保存と復帰,メモリキャッシュのフラッシュが必要になります
                またCPUのパイプラインもストールします.

                ですからこの手の高速化では
                システムコールの発行回数を最低限に抑える工夫が必須となります

                その工夫の一つが,大きなバッファを用意して,複数回のシステムコールを,一つにまとめる方法です

              • by tenokida (42811) on 2017年11月11日 23時29分 (#3310861) 日記

                printf(3)はシステムコールじゃないってのは余計な突込み?
                stdioライブラリ中のバッファ処理より高速なんだろう
                ♯改行くるとwrite(2)してるとか

                ページサイズかける文字数分の境界整列したバッファを用意しといて
                埋めた後グルグル回すとか
                #writeに渡した後の中身って保全されてると期待しちゃいかんのじゃなかったかな

          • by Anonymous Coward

            まさにアルゴリズムだと思うのだが…
            単純というだけでアルゴリズムに変わりはないでしょ。

            • by albireo (7374) on 2017年11月11日 19時56分 (#3310803) ホームページ 日記

              自分の理解ではこういうのはI/Oの効率化で、アルゴリズムというよりストラテジ
              アルゴリズムはもっとロジック寄りの処理を指すと思ってる

              --
              うじゃうじゃ
              • by Anonymous Coward

                ストラテジーよりはタクティクスかな…

            • by Anonymous Coward

              「アルゴリズム上の工夫とは言いがたい」と言いたいのでは

      • by Anonymous Coward

        in/outがハッキリしてるなら極端なパフォーマンスの問題がなければどう実装してもいいと思うけどな。

      • by Anonymous Coward

        「最もだ」

    • by Anonymous Coward
      "yes XX死ね"とか実行すると、最高に気持ちいい。
  • >ただ、本当にそのスループットが必要かはちょっと疑問
    いやいや、パイプで自動処理とかする際にも使えるし、
    ベンチマークとしてもつかえるんですよ

    部屋中がホットケーキミックスの匂いが充満してたので
    おっ!今日はホットケーキか!とおもったけど違ってた

    ここに返信
  • by Anonymous Coward on 2017年11月11日 21時25分 (#3310828)

    POSTDの記事を読んだが、やってることはバッファリングとmutexの除去くらいで、こんなん基本中の基本じゃないかね。
    こんな内容で感心されるほど、(伝統的な意味での)システムプログラミングをやってる人が減ったってことか。

    #Goが「システムプログラミング言語」を名乗ってることにイラっとしてる人。おめーはPHPやVB6の立ち位置の言語だろ。

    ここに返信
    • by Anonymous Coward

      デバイスドライバなど低レイヤの実装を業務としている開発者なら、そう(であるべき)かもしれない。
      多くの分野で求められている実装は、高能率より短納期、という状況が、背景にあるような気がする。

  • by Anonymous Coward on 2017年11月12日 0時06分 (#3310867)

    そのスループット向上によって節約される時間より、 yes が含まれるパッケージを最初のインストールのためにダウンロードしたり、アップデートの時にダウンロードするのにかかる時間の方が大きいのではないでしょうか。
    ( 特に長期で考えると CPU やメモリも性能の向上より常にネットワークのバンド幅の向上の方が遅いし、Docker のようなコンテナにもベースシステムとして yes が含まれる事も考えるとサイズが 1byte でも小さいほうがよいのではないでしょうか )

    ここに返信
    • 一方で、どうでもいいことに [y/N] を聞いてくる何かがいると yes のスループットによる節約効果がありますね。

    • by Anonymous Coward

      「そこにコードがあるから」という月並みな常套句はおいといても。

      計算機が使えるリソースが、UNIX系OSの登場時とは比べ物にならないこと、
      その一方で、計算機のこなさねばならない演算量も膨大になっていること、
      それに比して、アップデートに費やすリソースは、さほど過大でもなさそうなこと。

      といった前提条件で考えると、高速処理のために比較的大きなリソースを有効活用するアプローチが、一般論として有効と思える。
      「大きなリソースを活かせるよう、OSの設計を根本から見直すべきだ」という議論は当然あるが。

typodupeerror

長期的な見通しやビジョンはあえて持たないようにしてる -- Linus Torvalds

読み込み中...