PENDINGゼロという目標は容易に達成可能

ようやく乗ってきたようだ.200箇所も分岐がある中でPENDINGをゼロにするなどという目標はとてつもないものに聞こえるかもしれないが,PENDINGから,①SPECIFICATION,②OPTIONS,③DEFECTED に移すという道が開けたのでPENDINGが空になるというのももはや時間の問題だ.ここで,①SPECIFICATIONというタグは「仕様」であり,このようなものを作るという「決定」だが,特に「それなしではシステムが動作しないようなオプション」が含まれる.言い換えれば裏面(#defineをコメントアウト)では動作しないことを認める.

一方,②OPTIONSは「任意選択可能なオプション」であり,基本的にはオンとオフの両側で動作するものでなくてはならない.ただし,「裏面の動作は必ずしも保証されない」としてよい.③DEFECTEDは本来ならOPTIONSの候補であるところだが,明らかに不具合が見られるようなもので,「当面の間使用を禁止する」類のものだ.

昨日の修正では誤って「仮修正」を廃止してしまったための手戻りが発生した.一応STOP文で停止してくれたのでことが発覚し,比較的短時間でシューティングできたが,やはり,「現状」というのは(そこまでの動作確認の積み重ねがあるので)重く見なくてはならない.『その場の思い付き命取り』という格言をもう一度噛みしめるべきだ.

PairBoxGeneChangeの中でノード対が削除される場合がある PairBoxGeneChangeの呼び出し箇所を総点検する必要がある

PairBoxGeneChangeは8箇所から呼び出しがあり,その中で戻り値を取っているのは4箇所だけだ.PAIRBIX::retrieveShiftedPairBoxでは自ノード対を対象にPairBoxGeneChangeを実行している.⇒この関数の動作は安全だ.出口で「このノード対は死んだ~」という表示が出るくらいだから…その他3箇所で対処した.

さて,昨日の続きに戻ろう.DEBUGタグとVERIFYタグをすべてオフにして,PENDINGの動作を検証しているところだ.定義文のコメントから「仕様」と考えられるものはとりあえずすべてOPTIONSに移動することにする.この中には「純正血統図をサポートする」,「同性婚をアブノーマルな婚姻とする」などがあるが,ここでは動作確認は行わない.

たとえば,「純正血統図をサポートする」ならオフの場合はどういう動作になるのかを調べなくてはならないが,「純正血統図をサポートする」をオフにしても,系図画面設定パネルから「純血統図」が消える訳ではないし,そのときの動作がどのようなものになるのかも分からない.しかし,そこまでやると手が回らないので,ここでは「OPTIONSの動作確認は出荷時検査で行う」とだけマニフェストしておく.

これでPENDINGタグのデフォルトでオンに残るのは7件になった.これらにはコメントからよく趣旨が汲み取れないもの,ないし疑義のあるものなどが含まれるが,一度すべてINCOMPLETEに差し戻して別途動作確認を行うことにする.これらはおそらくOPTIONSに昇格するのではなく,フィックス→確定になるはずだ.PENDINGカテゴリでデフォルトでオフのものに関してはすべて現状でフィックスでよいのではないかと思われるが,一通り調べてみる必要がある.この中には

  1. HeapUpperの循環検査を行なう→廃止
  2. 計算時間制限の代わりに計算ループ回数に上限を設定する
  3. MakeSectionだけでノード対区間計算を完結させる
  4. カード世代シフトの規制を強める
  5. 描画矩形領域オーバーフロー(3件)
  6. 直属系列落ちを許容する/しない

などがある.HeapUpperの循環検査はYリストの誤接続などで生じる循環を検出するもので,すでにそのようなバグは完全に消滅したとみられるので廃止でよいと思う.計算時間制限というのはメインループが止まらない場合に時間で処理を打ち切るという安全装置だがすでに廃止され,現行のループ回数制限を越えるような事象も起きていないと判断できるのでフィックスでよい.これにはTESTタグで「当面使用禁止」としているオプションも絡んでいるが,整理可能な論理のクリアランスが必要だ.ノード対区間計算もなんどか仕様変更を繰り返しているが,現状でフィックスでよいのではないだろうか?カード世代シフトの規制を強めるというのはよく分からないが,「カードシフト」という機構自体が廃止されているという話もあるので,調査する必要がある.

「描画矩形領域オーバーフロー」という事象もすでに根絶されているようなので周辺論理を含めて一掃でよいのかもしれない.「直属系列落ち」が何を示しているのかよくわからないが,「ここでは直属系列落ちを許容する」というのと,「直属系列落ちを無視する」というのがあり,混乱している.というか,「許容する」と「無視する」というのが同義であるとすれば,では「直属系列落ちを無視しない」ところはあるのか?ということになる.そのような場所がないというのなら,「直属系列」という概念自体消滅する.そういう場所があるとしたら,むしろ積極的に「この場所では直属系列落ちを…のようにする」ということが明示されなくてはならない.

開いていたサンプル(ZTシステム構成図7.ZEL)を閉じようとしてFAMILYTREE::GetPersonalBaseで停止 topologyが空になっている

VB側からの呼び出しによるものでVBではすでにFormClosingを実行しているところだ.PHASEはゼロでINITIALSTATEに戻っている.FAMILYTREE自体はまだ活きているが,スロットはすべて空になっている.再現できるだろうか?系図画面設定パネルを操作したあとしばらく放置してからアプリ終了という手順だったと思うが…VBからのコマンドから発生する例外はGCでキャッチするようになっているので異常終了のようなことにはならないとは思われるが…

開いて閉じる,あるいは開いて設定パネルを出して終了では起きないが,部分図への切り替え,カラー設定など操作してから終了すると再現する.VBとDLLは並列実行されていて,特に待ち合わせということをしていないので,VB側の終了処理が遅れればこのようなことはあり得るのではないかと思われる.どうすればよいか?通常それぞれのコマンドは単体で完結しているので,特に待ち合わせの必要はないが,終了時は全体の処理時間が相当なものになるためまだ存続していると思って問い合わせするなどのことはあり得るのではないか?

GetPersonalBaseではASSERT_NEVERで停止しているが,これを内部で判断して動作を変えることはできる.しかし,このようなことは他の関数でも起き得ると考えなくてはならないから,かなり広範な修正が必要になってくる.以下のような外部インタフェース関数では:

_EXPORT long __stdcall GetPersonal(long num, PERSONAL* person);

入口で_ASSERT_NEVER(!FamilyTree)を実行してFAMILYTREEが活きていることを確認しているが,ここに専用マクロを設置してPHASEを確認するようにすればよいのではないか?たとえば,_ASSERT_ACTIVEとし,PHASEがINITIALSTATEではゼロ復帰するというのでよいのではないだろうか?⇒INITIALSTATEではなく,BEGINNINGSまで戻っていた.⇒こういう状態で呼び出しが掛かってくるのはこの件一回だけだが,念のためすべての外部関数にこのマクロを仕込んでおくことにする.(!FamilyTree)の検査もこのマクロの中で実施して,マクロを一本化しておこう.⇒52箇所あった.ただし,うち2箇所はvoid関数(シグネーチャが異なる)なので直接コードを書き込んだ.

いや,今度は3つ呼び出しが掛かってきた.CallGetUndoStat,GetRecordCount,CallSetKeizuParm.タイミングによっていろいろ変わるようだ.すべての外部関数に仕込んでおいたのが正解だった.

CHECKHEAPCIRCULATION(HeapUpperの循環検査を行なう)はすでにどこからも参照されていないので単純に廃止.⇒間違えた.大ミスをするところだった…検索条件が「このドキュメント」になっていた.このオプションは2017年1月に廃止され,2018年3月に停止が確認されているので廃止でよいと思われるが,Yリストの上流方向での循環検査ルーチンというのが見当たらないので,どこかにコードとして残しておいた方がよい.この検査ではBobject::heaptestという専用変数を使っているが,他の検査ルーチンではcheckmarkというのを使っているので,これを使うように改めればよい.まず,Bobject::HeapUpperの中ある検査コードを切り出してみよう.

いや,この部分だけを切り出してもあまり意味がないかもしれない…HeapUpper自体動的にYリストを上昇しながら実行される計算過程なので,その関数内では動作が完結しない.Yリスト(描画リスト)というのはBobjectに備わった機構で3つのスロットと1つの整変数を使って構成される有向グラフだ.ルートを除くすべての描画オブジェクトは1入力枝と2出力枝を持ち全体として大きな2分木を構成する.たとえば,抽象グラフ検証系を使ってこのような有向グラフが有向木となることを検査することは難しくないが,それなりのコストが掛かる.

単発的にあるノードが上流経路で循環していないことを確認するには単純に木を上昇して自ノードに遭遇しないことを確認するだけでよい.コードにしても2, 3行で終わってしまう.有向グラフが木であるか否かを検査するツールを整備することは意味がある.親参照パスも同種の有向木だ.ただちに必要というものでもないので,これはまた後日ということにしておこう.ということで,ためらわず廃止でよいのではないか?

SORTINGTIMEOUTLIMITの説明には「計算時間制限の代わりに計算ループ回数に上限を設定する」とあるが,実際のコードではSORTINGTIMEOUTLIMITが未定義のとき(つまり現状では)TIMEOUTLIMITが立っていないときにのみ「制限時間」をレジストリに登録するという動作になっている.この値はVBで読み出されて表示される.分かり難い説明だが,どうも書き込まれているのは実際の計算に要した実時間で,「制限時間」という場所を借りているだけのようだ.

TIMEOUTLIMITというブール値はレジストリの「計算時間制限」に格納されている.計算時間制限と制限時間は下図のようにVBの隠しパーツで設定できるようになっている.

image

時間制限するがオンで計算時間3秒になっているが,実際の動作はどうなっているのだろう?⇒TIMEOUTLOOPがゼロでないときは時間制限は作動しない.ようやく少し読めてきた.

このシステムではループが停止しないときに備えて元々タイムアウトでブレークするような作りだったのだが,デバッグ上の都合で回数でブレークというのを導入したのだろう.なぜ回数か?というと,時間制限では実行時にムラが出て現象を再現出来ない可能性があるためだ.いくらマイクロセコンドのクロックで制御された機械でも実時間にはどうしてもさまざまな理由でムラが生じる.バックグラウンドタスクの影響を受けることもあり,室温にさえ左右されるかもしれない.事象が発生したときのループカウントを使えば現象を確実に再現できる.

現行論理ではデバッグ時にはTIMEOUTLOOPカウントを10に設定し,リリース版ではゼロに設定している.TIMEOUTLOOP値がゼロの場合には時間制限が掛かるはずだがそのような動作にも見えないのはなぜか?リリース版では時間計測していないから,時間はつねにゼロだ.

現行ではおそらくすべてのサンプルでメインループを2回しか回っていない.2回回るのは,システムが静定するのを待っているからだ.つまり,データが更新されている間はループするようになっているため,最小限でも2回回らなくてはならない.もし,2回目がデータが更新されないことを確認するだけのものであるのなら,ループではなく単純な線形処理に書き換えてしまってもよいはずだ.すでにそういう状態になっているのではないか?この点に関してはもう少し調べなくてはならない.

ともかく,SORTINGTIMEOUTLIMITというオプションは説明にあるほどのことをやっている訳ではないので,現状で単純にフィックスでよい.その他,loopcountとroundがまったく同じ値を持っていてどちらかは不用であるなど,気になる点は多々あるが,また後でということにしよう.SORTINGTIMEOUTLIMITの説明文は「計算時間制限なしの場合,計算実時間をレジストリ登録する」のように書き換えた.

MAKESECTIONFULL(MakeSectionだけでノード対区間計算を完結させる)はすでにフィックスしている.どこからも参照されていない.STRONGSHIFTREGULATIONも説明文が悪い.このオプションではTRIBEBOX::ResetCriticalの中で禁止ノード対リストを空にした後,系列内のすべての人名ノードのSHIFTRECURRENT属性をリセットしている.これが「カード世代シフトの規制を強める」ことだろうか?

いや,おかしい.そもそも禁止ノード対リストはとっくの昔に廃止したのではなかったろうか?何かまたとんでもない失敗をやらかしてしまったような予感がする…prohibitlistとshiftlistを廃止したのは11月9日だ.この日付には何か不吉感が漂っている.「系列枠のシフト管理用ノード対リストを廃止@20201109」という名義で始末しているはずなのだが…ソースファイルのどこにも痕跡がない.

確かに2020年11月10日には9日の二回目バックアップまで戻っているので,その後に実施された修正は抜けている.9日の記事は2つのノード対リストのパージ以外では一括変換のことしか触れられていないので,この部分だけ修正を入れれば多分同期が取れると思う.まず,これをやっておこう.キーワードには「系列枠のシフト管理用ノード対リストを廃止@20201113」とする.以下の関数・変数もすべて不用となる.

NAMEBOX::shiftnum,NAMEBOX::targetnum,TRIBEBOX::RemoveFromShiftList,UpdateShiftList,ShiftMultiCards,DumpShiftList,DumpProhibitList,PAIRBOX::shiftnode,gettarget,shiftcard,shifttarget

これからフィックスするところだが,かなり修正が入ったので一旦バックアップを取っておこう.mmm… また例外が発生してしまった.

image

障害発生日時:2020年11月13日20時56分51秒 bugflag=0 C:\Users\babalabo\Desktop\添付サンプル\源氏物語全系譜6.ZEL
Failed at  with error 1008: 存在しないトークンを参照しようとしました。 障害発生日時:2020年11月13日20時56分51秒 bugflag=1 C:\Users\babalabo\Desktop\添付サンプル\源氏物語全系譜6.ZEL
0x781DFFD0 (ZelkovaDLL3.dll) で例外がスローされました (ZelkovaTree2021.exe 内): 0xC0000005: 場所 0x000000A8 の読み取り中にアクセス違反が発生しました

エラーは画面右上の終了ボックスをチェックしたタイミングで発生する.⇒リリース版をビルドしていた.デバッグ版ではnodule::Disposeで停止する.nodule::Disposeに入ってくるときには,すべてのスロットが空になっていなくてはならないのだが,残留リンクがあるようだ.PAIRBOXの2つのスロットを潰しているのにインデックス名が残っていた.⇒対処した.問題なく閉じられるようになった.

さて,バックアップも取ったのでいよいよ「系列枠のシフト管理用ノード対リストを廃止@20201113」をフィックスすることにしよう.もちろん,最初から最終的な記述に進んでもよいのだが,やはり手順を踏んで最初に#defineを定義し,次に変更箇所を#ifndef で書き換えてゆくというステップの方が安全だ.どっちみち最終的には(修正タイムスタンプを除いて)すべて削除してしまうのだが…

修正箇所は35箇所あるが,すべて「系列枠のシフト管理用ノード対リストを廃止@20201113」のキーワードが付いているので検索で容易に位置を特定できる.あとはグレーの「アクティブでないブロック」を一つづつ潰してゆくだけだ.⇒終わった.

STRONGSHIFTREGULATIONをフィックスしようとしているところだった.STRONGSHIFTREGULATIONが作動しているのはTRIBEBOX:ResetCriticalでここでは「カードシフトの循環防止用パラメータを初期化する」を実行している.この関数はTRIBELIST:TribeRelocationから呼び出されているが,「垂直セグメント検定用パラメータを初期化する」という説明が付いている.垂直セグメント検定というものはすでに廃止されているので,この関数自体不用となっている可能性がある.

確かに,SHIFTRECURRENTという属性自体がすでに使われていない.「系列枠のシフト管理用ノード対リストを廃止@20201113」の一部として,SHIFTRECURRENTを廃止してみよう.もう一度このキーワードを#defineして始めよう.⇒修正した.これ以外の属性でもすでに使われていないものが発生している可能性があるので,点検しておこう.

ENDPOINTFAILUREはすでに使われていない.「すでに使われていない属性」が11種もあった.この修正はかなり大きなものになりそうなので,一度バックアップを取ってから初めた方がよい.「すでに使われていない変数」というのもある…

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA