2018年11月21日水曜日

C#のListでGetRange()とToCopy()とBlockCopy()を比較してみた

知ってる人にとってはばかばかしいと思いますが、C#素人の悲しさ故に何でもやってみないとわからないので、恥ずかしながら今回は単純なリストの範囲コピーの速度比較をやってみました。

測定条件:
コピー元: List<float> 100000件
コピー先: float[]
コピー条件: コピー元の4000件目から最後まで(96000件)
コピー回数: 100000回

結果:

メソッドコピー先を毎回確保コピー先を使いまわし
GetRange23327ms(使いまわせない)
ToCopy11499ms1958ms
BlockCopy20000ms11862ms

コピー先を使いまわす版は異常に高いnewのコストを除外するために測定しました。
とりあえずToCopyがいいみたいです。
以上です。

おまけ:
こんなコードで測定しました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class ListCopySpeedTest
  {
    List<float> fl = new List<float>();
    const int membernum = 100000;
    const int testcount = 100000;
    const int startindex = 4000;
    void init()
    {
      Random r = new Random();
      for ( int i = 0; i < membernum; i++ ) {
        fl.Add( (float)r.NextDouble() );
      }
    }
    float[] GetRange( float[] fa )
    {
      fa = fl.GetRange( startindex, membernum - startindex ).ToArray();
      return fa;
    }
    float[] ToCopy( float[] fa )
    {
      if ( fa == null ) {
        fa = new float[ membernum - startindex ];
      }
      fl.CopyTo( startindex, fa, 0, membernum - startindex );
      return fa;
    }
    float[] BlockCopy( float[] fa )
    {
      if ( fa == null ) {
        fa = new float[ membernum - startindex ];
      }
      Buffer.BlockCopy( fl.ToArray(), startindex, fa, 0, membernum - startindex );
      return fa;
    }
    delegate float[] testfunc_t(float[] floatarray);
    void testfunc( Stopwatch sw, testfunc_t f )
    {
      float[] fa = null;
      for ( int j = 0; j < 2; j++ ) {
        sw.Reset();
        sw.Start();
        for ( int i = 0; i < testcount; i++ ) {
          f( fa );
        }
        sw.Stop();
        Console.WriteLine( f.Method.Name + ": " + sw.ElapsedMilliseconds + "ms" );
        fa = new float[ membernum - startindex ];
      }
    }
    public void test()
    {
      init();
      Stopwatch sw = new Stopwatch();
      testfunc( sw, GetRange );
      testfunc( sw, ToCopy );
      testfunc( sw, BlockCopy );
    }
  }
  class Program
  {
    static void Main( string[] args )
    {
      new ListCopySpeedTest().test();
      Console.Read();
    }
  }

2018年11月15日木曜日

Windows 10 October 2018 Update(Redstone5)では回復ドライブは増殖せず肥大化するのね

ひとつ前の記事でWindows10を1803から1809にしたので、今度こそはまたまた前例通りにパーティションが増殖してくれていることを強く期待して、さっそくディスクアドミニストレータを見てみました。
あ~、今回もパーティションが増えてない・・・

ちぇ、と思って、がっかりするところでした。

が、よーく見ると、なんとサイズが増えて肥大化していたのでした(元は500MBでしたから378MB肥大化しました)。

Threshold2(1511)まではパーティションの数が増えてましたが、どうやらRedstone1(1607)以後はパーティションのサイズを奪い取る成長を遂げていたのですねえ。

それにしても空容量に対して使用量が60%、なんでこんな878MBなんて半端な数値なのかしら。

先頭にあるパーティション、Windows8.1から10にアップグレードしたときのあまりの増殖っぷりに驚いて大きめにわざわざ折角大きめに切ったのにぜーんぜん使われなくって、今はだぁれも住んでいない昔の回復パーティションなんですが、そこに十分おさまるじゃないですかぁやだぁ。

まあ、HDDなんで容量的にはどうでもいいし、パーティションが無意味に増殖してしまって分断されるよりははるかにましですのでさらにどーでもいいっちゃあいいんですが、Threshold2で勝手に作られた回復ドライブの容量が450MBだったことを思うと倍近いんですね。

もうWindows Phoneは放棄したし、あと必要そうなのは、メーカーお仕着せのノートパソコンのリカバリ用途くらいしかないけど、そういう用途ならOS丸ごと入っていたりするものなのでGB単位で切ってあるからますますこんなちっこい回復ドライブを必死に作る必要ってない気がするけど。

どうせストレージが死んだら道連れですし。

どこまで増やすのかな?

Windows 10 October 2018 Updateが0x800F081F-0x20003で更新に失敗する

まず結論だけ述べます。

1803までで「Windows開発者モード」をインストールしていると「Windows 10 更新アシスタント(Windows10Upgrade9252.exe)」で1809への更新が失敗する場合があります。

結論は以上です。

以下余談です。

0x800F081FとはDISMのエラーコードそのままを吐いています。
枝番の0x20003は、「Windows 10 更新アシスタント」の更新作業の、どの段階で何をしていたかを示します。
0x200はアップグレードで行われる4段階中の2段階目、Safe OSでの作業中に起こった事象ということを示し、0x03がアップデート(この場合のアップデートとはWindows 10 October 2018 UpdateにあてるべきWindows Updateの事を指しています)をインストール中である事を示しています。
アップグレードとアップデートは言葉が似ているのでヤヤコシイ。

で、今回は
Microsoft-OneCore-DeveloperMode-Desktop-Package~31bf3856ad364e35~amd64~~.cab
が原因でした。
DeveloperModeとファイル名にある通り、開発者モード用のパッチですが、これが不具合の原因ですので、これを回避すればいいわけです。

回避するには「Windows開発者モード」をアンインストールします。
アンインストールできる場所は「設定」->「アプリ」->アプリと機能欄の「オプション機能の管理」です。
勘違いしやすいので敢えて画像を添付します。


「設定」->「更新とセキュリティ」->「開発者向け機能を使う」->「開発者モード」ではないので念のためご注意申し上げます。

ちょっとお詳しい方ならDISMときたらsfc /scannowで解決だろ!とおっしゃる方もおいでかもしれません。
ところがどっこい、今回は不整合が検出されない場合のケースです。

redstone系列の最終段階であるWindows 10 October 2018 Updateが満を持して公開!!
・・・のはずが、直後にファイル消失という深刻な障害により公開中止となっていました。
ひと月以上たった昨日、ついに再公開されました。

今回も段階的にインストールできる人を増やしていくとのことで、まだ私の環境にはWindows Update経由ではインストールできませんでしたが、どうせWindows Updateの日なのでパッチが強制的に当たったうえに再起動を強制されるついでですので「Windows 10 更新アシスタント」を用いて一挙に更新してしまうことにしました。

1時間ほどかかった挙句、結局更新に失敗しました。
頭にきたので原因を探ってみました。

まず初回の失敗時の状況です。
当環境ではSandboxieというツールがインストールされているのですが、これをアンインストールしないと絶許ということでしたので、素直にアンインストールしたところ、まだSandboxieがあるじゃんアンインストールしろよと言われてしまい(つまりWindowsからは2つインストールされているように見えているようでした)、とはいっても、当方としてはもうこれ以上アンインストールできません。
とりあえずアンインストールを完了するには再起動しなさいとSandboxieに言われているところでしたので、「Windows 10 更新アシスタント」を中断してから再起動し、再起動後に再度「Windows 10 更新アシスタント」を起動したころ、なんだかWindows 10 October 2018 Updateの更新作業が進みだしてしまいました。

まあ、とりあえずなぜか進んだので、Sandboxieが原因だったのかな、それにしても何でインストールが先に進んでしまったのだろう、2つのうち一つしかアンインストールしていないわけですから進んじゃいけないはずなんだから、それって不具合だよねやっぱりテストしてないよね怖いよね、と思いながら眺めていましたが、今回もやっぱり更新中の再起動一回目の進捗14%のところで失敗して1803に巻き戻されました。

この際、何のエラーコードも表示されず、イベントログにも何も残っていませんでした。
普通こういう大型アップデートをかける場合は寝る前とか帰宅前とかで行うでしょうから、失敗だろうが成功だろうが結果を表示しなければ普通の人は「あ、(正常に)終わったのね」としか思わないはずです。
なんて不親切な設計なのかとびっくりしました。

Sandboxieのアンインストールに伴う再起動がまずかったのかな、と思い、再度「Windows 10 更新アシスタント」で更新を開始しましたが、今度も「Sandboxieをアンインストールしてください」と言われてしまい途方にくれました。

レジストリにゴミが残っちゃったのかしら、と舐めるように点検してもSandboxieなんかないし、どうしたものか、と思っていると、別ドライブにバックアップとしてファイルのコピーだけしてあったSandboxieのファイル群があるのを発見しました。
ダメ元でそのファイルを削除したところ、それだけでインストールが再開されました。

バックアップだろうが何だろうが、どうせ動かないプログラムだろうと何だろうと、とにかくマイクロソフト様が許さないと指名したファイルがあるというだけでインストールさせないほど超コワモテな姿勢です。
動いているデバイスドライバでも何でもないそんなものをチェックする余裕がある癖に、今回のインストールの失敗の原因(説明はこの記事の後のほうになります)は超単純なのにチェックしてないってのがとてもスバラシイ。

ですが、インストールが先に進みはしたものの、やっぱり1回目の再起動後の進捗率14%の段階でロールバックされてしまいました。
これ自体は前回と同じ結果でしたのでSandboxieそのものが原因ではないことはわかりました。
しかし、今回は前回と変わって大きな違いがありました。
ロールバック後に「Windows 10 更新アシスタント」が勝手に画面をポップアップしてエラーコードを表示して教えてくれたのです。
それが「0x800F081F - 0x20003」でした。
さっきは不親切さにびっくりしましたが、今度は「あ、本当は結果を表示するはずだったのね」という意味でびっくりしました。

結果が表示されないのはバグだったんですね。

この後も含めて、結局何回か更新作業を行うことになってしまったのですが、後にも先にもこの時しか「Windows 10 更新アシスタント」さんはエラーコードを教えてくれず、1回目と同様に何も表示されないまま1803にロールバックされました。
当然イベントログにも何の情報もありません(何のためのイベントログなんだか)。
やっぱりこの辺もユーザにエラーを通知する機能のテストが全然できてないものとお見受けいたします。
不安をさらに煽ってくれるいいスパイスとなりました。

でもまあ、いつものように「はじめました」->「やってます」->「できませんでした」という無意味なメッセージではなく、兎にも角にもエラーコードを教えてもらえただけでも幸運でした。

早速エラーコードでgoogle検索様に教えを請いましたところ、エラーコードの意味そのものは引っかかりませんでしたが、DISMがこのエラーコードをよく吐くという文言があちこちの検索結果から目に入りました。
こんな数値、とても偶然の一致とは思えません。

そーいやBCDとかもVistaからだったなあ、あの時なんかすげぇ苦労して今はidすら忘れた某ソーシャルサイトで長い記事書いたっけなぁとか眠い頭で連想するうちにsetupact.logの存在を思い出しました。
アップグレードの手順はVistaのころから変わっておらず、「何回か再起動されます」なんて曖昧なことを言われますが、実はアップグレード時のリブート回数は特殊なデバイスを搭載していない限り決まっています。

たとえば今回のように1803上「Windows 10 更新アシスタント」を用いた場合、リブートの1回目は元のOS上でインストールすべきファイルを収集し終えたあと、2回目はSafeOS上での手順がおわるまで、3回目はそれ以降の手順です。
で、なんで回数なんかに着目するかというと、何回目にリブートされたかによってログが吐かれる場所が変わるからです。

余談ですがこれはVistaSP1のころから変わっていません。さすがWindowsNT6.0というだけあっただけにXPのNT5系列から劇的な変化を遂げています。
製品としてのWindows10も(製品名とカーネル番号だけを合わせたので表示上はWindowsNT10.0ですが)実はカーネルは(まだ)WindowsNT6.4相当なのでその辺はほとんど変更がありません。
実際、1803でもバージョンは10.0.17134のままですし、今回の1809も10.0.17763です。
これらのバージョン情報はエンドユーザからは簡単には見えませんが、実はコマンドプロンプトでverコマンド(winverコマンドではありません)を入力すると確認できます。
まあ、普通の人はコマンドプロンプトなんか使いませんよね。
この国のIT業界ではスマホのほうがメール書くのはえぇっすよぉPCなんかつかってらんねぇっすよぉの世界が普通だそうです(えくせるほーがんしやぱわぽでの資料作成を命じると翌日には求人枠が一つ空くとかあかないとか)

ま、そんなわけですので、Vistaのガワだけ取り替えて見た目は劇的に変わってはいるものの、OSの大規模更新といったようなコアとなるような機能では、Vistaのころからのトラブルシューティングの知見が随分流用できます。

で、今回はsafeos内手順中での作業中の事故ということが0x20003の0x200の部分でも教えてくれていますので、そこにあるべきsetupact.logを検索しました。

すると、こんな行が見つかりました。


2018-11-14 22:10:04, Error                 SP     CAddPackage::DoExecute: Failed to add package Add [1] package C:\$WINDOWS.~BT\DUImageSandbox\Microsoft-OneCore-DeveloperMode-Desktop-Package~31bf3856ad364e35~amd64~~.cab. Error: 0x800F081F

これで0x800F081Fの出所もわかったし確かに枝番からわかる0x200の意味するところのSP_EXECUTION_SAFE_OSで 0x03の意味するところのSP_EXECUTION_OP_INSTALL_UPDATES でエラーが起きたことは確かだということが分かりました。

が、これ、実は、まだこれだけじゃ終わりません。
実際にはこのファイルは正しい形式で既定の場所にダウンロードされており、このMicrosoft-OneCore-DeveloperMode-Desktop-Package~31bf3856ad364e35~amd64~~.cab自体に問題はありません(ファイル名長すぎ)。

ですので、このファイルだけひねくり回しても何の解決にもなりません。

Errorとして報告されていない部分が実際の異常の原因なのでした。

このエラーだけ見るとMicrosoft-OneCore-DeveloperMode-Desktop-Package~31bf3856ad364e35~amd64~~.cabが異常だと思うじゃないですか。
本当は、このcabファイルがさらに必要とするファイルがあって、それがないという情報はErrorではなくInfoとして報告されているのです。

こんな具合です。
2018-11-14 22:10:03, Info                  CBS    FOD: Missing payload: Microsoft.WebDriver~~~~0.0.1.0
2018-11-14 22:10:03, Info                  CBS    Missing payload found on FOD execution [HRESULT = 0x800f081f - CBS_E_SOURCE_MISSING]
2018-11-14 22:10:03, Info                  CBS    Exec: Failed to retrieve FOD payload [HRESULT = 0x800f081f - CBS_E_SOURCE_MISSING]
2018-11-14 22:10:03, Info                  CBS    Failed to download and plan capabilities [HRESULT = 0x800f081f - CBS_E_SOURCE_MISSING]
2018-11-14 22:10:03, Info                  CBS    Failed to plan execution. [HRESULT = 0x800f081f - CBS_E_SOURCE_MISSING]
2018-11-14 22:10:03, Error                 CBS    Failed to process single phase execution. [HRESULT = 0x800f081f - CBS_E_SOURCE_MISSING]
2018-11-14 22:10:03, Info                  CBS    WER: Generating failure report for package: Microsoft-OneCore-DeveloperMode-Desktop-Package~31bf3856ad364e35~amd64~~10.0.17763.1, status: 0x800f081f, failure source: CBS Other, start state: Absent, target state: Absent, client id: DISM Package Manager Provider

つまり、WebDriverが必要なのにそれを適用しようとせずに、セットアップスクリプトが依存関係を無視してMicrosoft-OneCore-DeveloperMode-Desktop-Package~31bf3856ad364e35~amd64~~.cabを入れようとしてるのが悪いわけです。

これもバグですよねぇ。

なぜなら、Windows開発者モードが搭載された
「Windows 10 Anniversary Update(1607,redstone1)」
から、その後の
「Windows 10 Creators Update (1703,redstone2)」、
「Windows 10 Fall Creators Update (1709,redstone3)」、
「Windows 10 April 2018 Update (1803,redstone4)」
まで、3回もの大型更新ではまったく問題がないんですから完全にアウトですよねえ。

なぜ今回問題となったかというと、Features on Demand(FoD)化にあるんだと思います。
WebDriverは1908からFoDとしてDISMからインストールできるのですが、1903まではFoD化されてません。インストーラ経由でのインストールになります。

新機能を追加したのにテスト設計チームに全然伝わっておらず、テスト仕様書からごっそりと抜け落ちていたんでしょう。
最近のMSくぉりちーがここにも遺憾なく発揮されてしまったようです。
MS製WebDriverをわざわざ入れる人って極めて貴重なEdgeマニア(そんな人いるのかな)か、業務でEdgeらされている人だけでしょう。
業務としてはお気の毒ではありますがこのバグには遭遇しないと思いますので、日ごろの艱難辛苦が報われたことは誠にご同慶の至りです。

そして、1809になったらなったで、今度は「Windows開発者モード」が「設定」->「アプリ」->アプリと機能欄の「オプション機能の管理」->「機能の追加」から消えてしまっています。

これは多分、「設定」->「更新とセキュリティ」->「開発者向け機能を使う」->「開発者モード」を選択したら自動的にインストールされるからいいだろ、ということだと思います。
実際にやってみたところ、選択すると自動で「Windows開発者モード」がインストールされてしまいます。
明示的にユーザがインストールしたわけじゃないのに無理やりされちゃいます。
但し、インストール済みとして表示はされるようにはなるので、そのことを知ってさえいれば削除は可能です。

ところで、1809ではその代わりに、今度は「設定」->「アプリ」->アプリと機能欄の「オプション機能の管理」->「機能の追加」にWebDriverが追加されています。
このためにFoD化したんですよねきっと。

上記のラジオボタン選択による「Windows開発者モード」の強制インストールが行われても、一見WebDriverはインストールされないように見えて実はされちゃいます
どうせ一緒にインストールされちゃうなら、折角の大型アップグレードなんだから一緒のパッケージにすればいいのに。

まあ、要するにこのラジオボタン選択で自動で行われるインストール作業がアップグレード時には行われないのが今回のバグの原因ということなんでしょう。

こんなんじゃ近いうちにまたWindows Updateで問題が起きるかもしれません。
開発者モードはWindows 10 Anniversary Updateでbashが使いたいときにどうしてもインストールしなくちゃいけなかった機能でしたが、その後のWindows 10 Fall Creators Updateからは開発者モードにしなくても使えるようになりましたので、いまでは(もしかしたらUWPの案件が・・・なんて淡い期待とともに、あるいは完全に忘れっぱなしで)そのままにしておいた人や、本当にUWPの開発をしていてWebDriverが不要だった人に直撃です。

本気でUWPを普及させたいから、自分で「Windows開発者モード」を選択してインストールしなくても黙って入れちゃえよ~ともかく敷居だけでも下げられねぇかな~たのむよ~なんとかしてくれよぉ~、という経営上の要請が、WebDriverのほうもやっぱり、Edge普及しねぇんだよぉ~あのFirefoxにも負けてんだよぉ~たのむよぉ~インストーラなんか探さなくても手軽に入れられるようになんねぇかなぁ~、という市場戦略上の要請が、それぞれありありと見えますが、それでこんなバグだしてんだから世話ねえやね。

わはは。

UWP早くなくなれ。

ところで。
インストールの最終段階の全画面でのあの無意味な「こんにちは」から始まる一連のやつは今回も健在でした。
もう結構です。
口だけは達者と言われちゃっても知らないぞ。


それにしても、なんだかんだ言って使いやすいOSであることには違いないのになぁ。

先日のライセンス認証サーバがこけちゃう大ポカとか、ファイル消失なんてあっちゃいけないバグが分かってて出荷して出荷停止にする激ポカとか、小一時間は軽くかかるアップデートでこんなくだらないバグを出すとか、FHDだろうが4Kだろうが8Kだろうがお構いなく全画面でこんにちはとか言ってるようじゃどうしようもないんじゃないかなあ。

折角のOSの魅力を自分でスポイルするのはなんかの呪いなんですかねぇ。