ことの経緯

「インドリ氏のOpenMP記事の問題点〜再び」(id:ange1:20100723)に端を発し、「技術者失格」(id:ange1:20100730) で指摘を追加した、CodeZineのインドリ氏の記事OpenMPにおける変数の扱いと並列リダクションですが、予想以上に話が長くなったので、経緯をまとめることにしました。
情報なりコメントが色々分散しているというのもありますし。
id:busaikuro:20100402 での井戸端談義、私とCodeZine編集部との遣り取り、インドリ氏のblogでの記事掲載状況やコメントの遣り取りが中心となります。

時系列での経緯

  1. 7/21 CodeZineの記事の掲載*1
  2. 7/22 CodeZineの記事を見る
    • Sodaさん*2のコメント、id:busaikuro:20100402#c112182636 により、記事の掲載を知る。
    • 記事を見て思わず出たコメントは、「何やってんだ、あのバカ。」これは特に、後述するomp漏れに依る所が大きい。
  3. 7/23 指摘記事を書く
    • 「インドリ氏のOpenMP記事の問題点〜再び」(id:ange1:20100723) を書く。主な指摘事項は3点。
    • 1点目は、OpenMPで言うところのprivate変数を、「スレッドプライベート変数」と称する点。OpenMPには別途threadprivate変数というのがあるため、紛らわしい。とは言え、他の2点が酷いため霞んで見える。
    • 2点目は、データレース。shared変数を、同期*3なしで更新しているサンプル*4について。
    • 3点目は、ompの漏れ。OpenMPの正しい指示行“#pragma omp 〜”から omp が抜けていたため、有効な指示行になっていなかった。*5これだけならばtypoであるが、サンプルの実行結果も、omp漏れのコードから得られたと考えられる不適切なものであるため、不誠実だと非難した。*6
  4. 7/24 編集部へクレーム
    • CodeZine編集部へクレームメールを送り、対処を要請する。焦点は次の3点。
    • インドリ氏の記事の品質が酷いものであること。
    • 品質の酷い記事を放置することは、デマの拡散*7に繋がりかねないと懸念すべきものであること。
    • 「ここをこう直せば良い」という指摘では追いつかないため、重大な問題点を指摘する形に留めているが、記事としては根本的な見直しが必要であろうということ。
  5. 7/26 編集部からの返事
    • CodeZine編集部より返事が来る。同時に、問題の記事に、指摘記事のトラックバックが反映されたことを確認する。*8
  6. 7/29 記事の修正(第一弾)
    • id:busaikuro:20100402#c1280355275 のSodaさんのコメントにより、記事の修正が入ったことを知る。
    • それに対し、私は、編集部へのクレームの影響である可能性を示唆する。
    • と同時に、修正点に対して抱いた感想は、「舐めた仕事」*9
    • ちなみに、この修正点については、CodeZineの修正履歴には載っていません。
  7. 7/29 編集部への確認
    • CodeZineへ再度メールを送り、状況の確認を図る。
    • 指摘事項としては、修正内容が不適切である点。
    • 確認事項としては、編集部側で、この修正について把握しているか*10という点。
  8. 7/30 インドリ氏の見解その1
    • インドリ氏のblogに、爆笑!世にも奇妙な誹謗中傷集団の観察日記が掲載される。
    • 上記id:busaikuro:20100402でのコメントの遣り取りを見て書いたものらしい。
    • この件に関する氏の見解は3点。*11
    • 私の行動が営業妨害であること。
    • 私の指摘はあさっての方向を向いた誹謗中傷であること。
    • 記事の修正は、氏が点検し改善したものであり、私の指摘が原因であるという考えは、自意識過剰だ。*12
  9. 7/30 追加の指摘記事
    • 「技術者失格」(id:ange1:20100730) を掲載し、修正内容に対する批判と、氏のblogに書かれた内容に対する見解を明らかにする。
    • blogの内容に対する見解は、一言で要約すると「頭大丈夫か?」なので、あまり新しい内容はなし。
    • 修正に対する批判は、主に、サンプルコードと実行結果を差し替えただけなので、説明文との不整合が発生しているという点。元々文章としておかしい点も同時に指摘。
    • よって、上の「インドリ氏の見解その1」における「改善」という表現は不適切であるとしている。
    • 後は、前の記事「インドリ氏のOpenMP記事の問題点〜再び」(id:ange1:20100723)での指摘事項が、まだまだ未対応であることも指摘する。…omp漏れは、修正の入った箇所以外に数箇所あったため、暫くこの話題が続くことになる。
  10. 7/31 インドリ氏の見解その2
    • インドリ氏のblogに、 逃げしか出来ない集団の凄い悪あがきが掲載される。
    • 内容としては、私の追加の指摘記事に対する非難、かな。多分。
    • 記事の7割位が、まあ、ほぼ悪口*13で、技術論と関係ないので、ここでは割愛。
    • 技術的な反論としては、私の「合計値を計算するサンプルになっていない」*14に対してのみ。
    • OpenMPのlastprivateの特徴として「初期化もしくは変数に値を設定する部分で、意図せず正しくない結果を出してしまう危険性があります」と説明した部分を引用して、「0〜4*15の情報が喪失しております」という説明をしている。
    • 氏の意図は詳らかにされていないため、推測になるが、「『合計値を計算するコードだが、lastprivateの性質のため、意図せず誤った結果が出る』ということは説明済みだから、『合計値を計算するサンプルになっていない』という批判は的外れだ」ということであろうか。*16
    • その他に、私の記事中に出てきたSodaさんのハンドル“Soda”と、ハテナID“Deppi”が一致していないことについて、「自分で名前を変えている事を発表しているし(笑)」という見解があった。しばらくこの話題で盛り上がることになる。*17
  11. 8/1 インドリ氏への要請その1
    • 氏のblogに1回目のコメントを入れる。
    • なぜ氏のblogかというと、CodeZineの記事のコメント欄は無効化されているため。*18ちょうど私の話も出た事だし、便乗というのもある。
    • 内容としては、記事の問題点への対応の要請である。氏のblogへの素直な評価も簡単に添えて。
    • omp漏れ問題はまだまだ残っていたため、そのことを示唆するフレーズをつけている。完全に対応されるまで、これは続くことになる。
    • なお、これに対するインドリ氏のコメントは、「angelのコメントをさらしました。」なので、意図は不明。
  12. 8/2 CodeZine編集部からの回答
    • 氏の記事修正に関する確認メールに対し、編集部から回答メールがあった。
    • 編集部としては、修正内容は把握していないとのこと。
    • 実は、先にSodaさんが編集部に確認していた。id:busaikuro:20100402#c1280571268 がそれ。
    • そのため、一旦記事が掲載されてしまうと、その内容については筆者に全て委ねられるということになってしまう。
  13. 8/2 インドリ氏への要請その2
    • 氏のblogに新たな記事 誹謗中傷軍団が営業妨害を自慢している件についてが8/1に掲載されていたため、そこにコメントを入れる。
    • ちなみに、この記事で取り上げられているのはSodaさんのコメント*19
    • Sodaさんや私が行っている、CodeZine編集部への指摘や確認を「営業妨害」と氏は断じると共に、編集部が自身の意に沿わぬ場合は、CodeZineを見限ると宣言している。
    • で、私のコメントでは、引き続き問題の記事への対応、特にomp漏れへの対応を要請すると共に、編集部への態度を改めるよう指摘をしている。*20
    • なお、前回の要請でもそうだが、デマレベルの問題記事を放置するのは害悪が大きいため、氏が個人blogを書くよりも、記事の修正の方がより優先度が高いものと考えている。そのため、毎回、「〜している暇があったら」という表現を使っている。
    • このコメントに対する氏の見解は、「ケアレスミスを課題解釈して、相手をけなす事しか考えていない」、typoでは片付かない問題である点は、指摘記事「インドリ氏のOpenMP記事の問題点〜再び」(id:ange1:20100723)にも書いているのだが、読んでいないものと考えられる。
  14. 8/2 インドリ氏への要請その3
    • まあ、同日ではあるが、別記事誹謗中傷集団の不思議な思想でもコメントにより要請を行う。
    • 話に出てくるJittaさんの件については、id:busaikuro:20100402#c1278696251 以下で話題になっている。早い話が、間違っていて指摘を受けたのなら対応しよう、ということ。
  15. 8/3 記事の修正(第2弾)
    • インドリ氏のコメントにより、8/3朝に修正報告がなされる。
    • 記事の内容を確認したところ、1箇所はompの漏れがあった所にompを補い、それに伴い変わった実行結果も載せ替える、もう1箇所は、“#pragma for”という指示行らしき所を削除する、という対応であった。
    • 実はコメント時点では前者しか対応していなかったようだ。id:busaikuro:20100402#c1280878074 で、Sodaさんが確認している。私も8/3昼に少し見た限りでは、後者が直っていなかったから。まあ、夜には全て直っていたので、大きな問題ではないが。
    • なお、後者に関してはompを補う対処であれば、結果は変わるにしても、問題は発生しなかったのだが、行削除という対応に出たため、バグがはっきり残ってしまった。id:busaikuro:20100402#c1280838185 以降、何回か話題に上っている。
    • ちなみに、この修正を受けて同日、最初の指摘記事(id:ange1:20100723)に、ompの漏れが解消された旨追記を行う。
  16. 8/3 インドリ氏への要請その4
    • 修正確認および次の対応の要請のコメントを入れる。
    • shared変数に対するデータ競合の問題は、まだ残っているため、その点について対応を要請するものである。*21
    • なお、「普通に修正できないんですか?」というのは、私の非常に素直な感情の吐露である。*22
  17. 8/3 インドリ氏の見解その3
    • データ競合の問題について、氏よりコメントが出る。
    • 「連載という意味を分かっていますか?」だけなので、意図が分かり難いが、恐らく「連載という形態を取っていれば問題とはならない」という認識なのだと推測できる。
  18. 8/3 インドリ氏への要請その5
    • データ競合を起こすサンプルを載せており、かつそのことに言及していないのは依然問題であると考えていることから、再度要請を行う。
  19. 8/4 記事の修正(第3弾)
    • インドリ氏より、修正報告が入る。
    • 記事を確認したところ、「このサンプルにも並列処理特有の問題があり、次回紹介する同期処理を駆使する必要があります」という文言により、サンプルに問題がある旨、明記されていた。
    • どういう問題点があるのか解説しないのは、記事として情報価値が低いとは思うものの、問題がある旨明らかにされるのは良いというのが私の感想。id:busaikuro:20100402#c1280934329 でコメントした通り。
    • ただし、データ競合のバグが同じく残っているreductionのサンプルに対しては、特に対応はなし。
  20. 8/4 インドリ氏への要請その6
    • まだ残っているデータ競合、reductionのサンプルの件につき、引き続き要請を行う。
    • これまで毎回そうだが、氏は何かしら私等を貶さないと気が済まないのだろうか。そんなことよりも、対応をしっかり一発で決めて欲しいという心情を、コメントには含めている。
    • 同時に、苦情コメントも載せる。ポイントは2点。
    • 1点目は、「何のために、何度も誤った結果を出すサンプルを作ったと思っているのですか?」というコメントに対して。誤ったサンプルを出したのが意図的だとしても、言及されなければ意味が無い所か、害悪であるということ。そもそも言及しないのが当然なら、omp漏れはどう判断すれば良いのか、と考えると、破綻を招く態度であることは疑いようがない。
    • 2点目は、純粋に私の怒り。まあ、そうとしか言えない。
    • それに対するインドリ氏の反応は、まあ拒絶反応であろうか。
  21. 8/5 インドリ氏への要請その7
    • 恐らく最期の要請を行う。
    • ここまでの反応を見るに、reductionのサンプルの問題点を理解していない可能性が高い。そのため、Yes/Noの質問を投げかける。*23
    • 果たして、氏はまともな回答を行わなかった。以降、出禁措置ということらしい。
    • 「リダクションはスレッドプライベートな変数を作り…」という氏のコメントを見るに、微妙に用語がずれているのは置いたとしても、どうも素でshared変数の競合に気付いていないらしい。
    • 出禁にされたといっても、私は氏に内容が伝われば十分だったので*24、別に困りはしないけど…。むしろ今まで良く私のコメントをオープンにしていたものだと、逆に感心している。
    • ただ、氏が残った問題点への対応を行うことは、もう期待できまい。

今後、何か大きな動きがあれば追加するかも知れません。

まだ残っている大きな問題点

一応インドリ氏が「ケアレスミス」という見解を出しているので、Sodaさんが一度記事で触れていることもあり、わざわざ詳細を説明してはいませんでしたが、念のため挙げておきます。
問題の記事の4ページ目の「reduction指示句の使い方を示すサンプル」からの抜粋です。

    int i, count, sum;
    count = 0;
    sum = 0;
    #pragma omp parallel num_threads( 10 ) reduction( +: count, sum )
    {
        for ( i = 0; i < 10; i++ )
        {
            count++;
            sum += i;
        }
        printf( "スレッド:%d\t実行回数%d回 合計値%d\n", omp_get_thread_num(), count, sum );
    }

はい。parallelリージョンの中で、i はshared変数です。それを、forループで i++ と更新をかけていますから、i に関してデータ競合が発生します。*25
…気付けばたったそれだけのことで、i を private と指定すれば済む話なんですが、変数がsharedかprivateかというのは、真っ先に意識すべきことであり、何度指摘されても気付かないというのは絶望的だと思います。
ちなみに、記事掲載当初は、forループの直前に“#pragma for”という指示行らしき行がありました。これを“#pragma omp for”と正しいOpenMPの指示行に直したならば、ループ変数である i は暗黙の内にprivate変数になりますから、データ競合は発生しませんでした。尤も、forループが分割されるかどうかで動作に違いが出ますから、実行結果の取り直しが必要ですが。

感想

思えば、2種類の問題の対応だけで、ここまで経緯が膨れ上がるって、尋常じゃない…、というか書いてて疲れました。リンクが正しく張れているかどうか、余り自信がありません。もし間違いに気付かれましたら、ご指摘願います。
一通りの対応がなされれば、まだ問題は多数あるにせよ*26、デマって程では無くなると思っていたのですが…。残念という他はありません。
これは偏に私のミスだろうと後悔しております。まさか、最後まで本当にデータ競合に気付かないことがあるなんて。彼の人を大きく読み違えていたことを非常に恥ずかしく思います。
とりあえず、CodeZine編集部には、クレームを入れた責任もありますし、近いうちに経緯を報告しようと思います。

おまけ

8/1 インドリ氏への要請その1でのコメントでは、Sodaさんのハンドル・ハテナID不一致に対する件も確認しています。「良いんですか?」と。*27ハテナのユーザであるid:AlexAndRite*28もコメントされていたので、話題を振っています。
この件については、やや本筋からそれるため、おまけとして触れることにします。
最終的には、id:AlexAndRite氏は、Sodaさんのハンドル・ID不一致について、問題視していない旨コメントをされています。
途中、じゃんぬねっとさんが、SodaさんのハンドルとハテナIDの不一致について、偽名を目的としたものではないこと、両名併記により異なる名前の同一性を担保していること、等々説明を行っていました。
非常に丁寧な方ですね。
…ただ、結局インドリ氏が何を問題視していたのか、じゃんぬねっとさんの説明で理解できたのかどうかは分かりません。何故か、「じゃんぬねっとさんが犯罪者を庇う」という話に、氏の頭の中では膨らんでいたようでしたが。

*1:記事の掲載日時を見ると7/21 14:00となっていますから、そうなのでしょう

*2:id:Deppi氏のこと

*3:atomicやcriticalといった指示

*4:当初は、サンプルに問題があるかどうかの言及はなかった。その点も含めて問題視している

*5:例えば、“#pragma for”とか

*6:実行結果をチェックするのをサボらなければ、普通気付くだろう、ということ

*7:媒体が個人blogなら兎も角、CodeZineですから

*8:編集部の判断が入るのか、トラックバックを送っても直ぐには反映されない模様

*9:この点については、次の指摘記事「技術者失格」(id:ange1:20100730)でも書いています

*10:要するに、編集部を通して修正を行っているのか、ということ

*11:ちなみに、別件での他の方への色々な文句も混じっていますが…

*12:…多分、自力で直したのだと氏がアピールしたいのだろう、そう私は推測します

*13:いつものことですが

*14:元記事の「このコードは、各スレッドで0〜9の値の合計値を算出するもので」に対する批判

*15:ループ変数がこれらの値を取る時の処理の影響を指す、と推測できます

*16:一応、私の見解を載せておくと、「合計値を計算したいのなら、lastprivateなんてそもそも使うな。用途を間違えている。勝手に期待しておいて、結果が異なるからってlastprivateのせいにするな」となる。

*17:普通に考えて貰えば分かることだが、普段使っているハンドルと一致するIDが取得できなかっただけの話である。

*18:過去に編集部からは、「記事のコメント欄は議論に使うことを想定していない」という見解を頂いている。そのため、指摘等でコメント欄が膨れ上がる事を、編集部側が事前に回避したのであろうと推測している

*19:id:busaikuro:20100402#c1280571268

*20:今まで載せたダメな記事に対する責任が残っているから

*21:指摘記事では、sharedに関するサンプル1箇所に留めているが、行削除を行ったreductionのサンプルでも同様の問題が顕在化している。その点については、SodaさんがCodeZineの記事にトラックバックした、「OpenMP変数編」(id:Deppi:20100726)という記事でも、既に触れられている。「そうそう、競合で思い出した」以降である

*22:というか、そろそろまとめ書くのも疲れてきた…

*23:といっても、氏に質問を投げかけて、まともに回答があった試しはなかったりする

*24:一度だけid:AlexAndRite氏に振っているものの

*25:実際には、ループ長が10回と非常に短いため、データ競合を起こす間もなく終わってしまうかもしれません。ループ長が長くなったり、1回のループで行う処理の負荷が高くなると、競合が起こる確率も上がるでしょう

*26:流石にこれ以上指摘するのは、こちらの身が持たない。何年かかるか分からないから

*27:ニュアンスとしては、「頭大丈夫ですか?」に近いことは言うまでも無い

*28:多分、本人だと思う