2016年8月14日 (日)

133週間目

47.1~47.9Kg/6.3~10.3%

体重は安定。体脂肪率も1日除けばほぼ安定。相変わらず食べる量を抑えているので大分落ち着いてきたかな。でもお腹がすく。大分すく。秋になったら反動がすごいかもしれない。

SASFのLongPaths対応、いろいろやってるうちにライブラリやらなにやらの古いバグがでるわでるわ。なんで大丈夫だったのよ! ってな感じで...。refactoringって大事よね、うん。しかしLongPaths対応はいろいろ大変だ。ちょっと腰を据えてやらないとだめかもなぁ。

| | コメント (0) | トラックバック (0)

2016年8月 9日 (火)

パス長の拡大対応判定

てなことで、アプリケーション自身がパス長制限を回避できているのかどうかを判定するためのコードを書いてみたり。面倒だったのはManifestを読み込んで対応部分を判定するところ。いや、XMLなんて扱ったことなかったもんで...。

uses
  winapi.windows,
  system.Win.registry,
  system.Classes,
  System.SysUtils,
  Xml.XMLIntf,
  Xml.xmldom,
  Xml.XMLDoc;

function IsLongPathsReady:boolean;
  function FindNode(nd:IXMLNode; name:string):IXMLNode;
  var
    i : integer;
    ndname : string;
  begin
    result:=nil;
    for i:=0 to nd.ChildNodes.Count-1 do begin
      ndname:=nd.ChildNodes.Nodes[i].NodeName;
      if CompareText(name,ndname)=0 then begin
        result:=nd.ChildNodes.Nodes[i];
        break;
      end;
    end;
  end;
var   rg:TRegistry;   vl : DWORD;   hM : THandle;   rs : TResourceStream;   xd : IXMLDocument; // TXMLDocumentだとmemory access violationが発生する   nd : IXMLNode;
  name,Value : string; begin   result:=false;   // 条件1 Windows 10 ver 1607以降であること   if (TOSVersion.Major<10) then exit;   if (TOSVersion.Major=10) then begin     if ((TOSVersion.Minor=0) and (TOSVersion.build<14393)) then exit;   end;   // 条件2  HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabledが0以外   rg:=TRegistry.Create;   try     with rg do begin       RootKey:=HKEY_LOCAL_MACHINE;       rg.Access:=KEY_READ;       if OpenKey('\SYSTEM\CurrentControlSet\Control\FileSystem',false) then begin         try           vl:=ReadInteger('LongPathsEnabled');         except           vl:=0;         end;         result:=(vl<>0);       end;     end;   finally     rg.Free;   end;   if NOT Result then exit;   // 条件3 manifestにlong path使用が指定されている   // 一旦falseにreset   result:=false;   hM:=LoadLibraryEx(PChar(ParamStr(0)),0,LOAD_LIBRARY_AS_DATAFILE);   if hM<>0 then begin
    try       if FIndResource(hM,MakeIntResource(1),RT_MANIFEST)<>0 then begin         rs:=TResourceStream.CreateFromID(hM,1,RT_MANIFEST);         try           rs.Position:=0;           xd:=TXMLDocument.Create(nil);           try             xd.LoadFromStream(rs);             name:=xd.DocumentElement.NodeName;             if 0=CompareText(name,'assembly') then begin               nd:=FindNode(xd.DocumentElement,'application');
              if nd<>nil then begin
                nd:=FindNode(nd,'windowsSettings');
                if nd<>nil then begin
                  nd:=FindNode(nd,'ws2:longPathAware');
                  if nd<>nil then begin
                    value:=nd.NodeValue;
                    FIsLongPathsReady:=(CompareText(value,'TRUE')=0);
                  end;
                end;
              end;
            end;           finally             xd:=nil;           end;         finally           rs.Free;         end;       end;
    finally       FreeLibrary(hM);     end;   end;   // 条件4 特定のAPIを操作しておく
  //       以降レジストリが変更されていても有効のままになる   if result then     vl:=GetFileAttributes(PWideChar(@(ParamStr(0)[1]))); end;

とこんな感じ。manifestの処はもうちょい厳密にattributesとか検査した方がいいのかもしれないけど、めんどくさくてこんな感じに。

8/13追記
コンソールアプリで使うときは使う前にCoInitializeを忘れずに。アプリ終了時のCoUninitializeも忘れずに。

8/4追記
コードをちょっと整理

| | コメント (0) | トラックバック (0)

2016年8月 5日 (金)

MAX_PATH制限解除に関してのメモ(8/20修正)

8/20修正 UDFのファイル名の最大長は254文字でした。

Win 10 rev 1607(Anniversary update)にて特定の条件下でMAX_PATH(260)の制限が解除される。

  1. win 10 Anniversary update以降であること。OSMjr=10,OSMnr=0,OSBuild=14393
  2. HKLM\SYSTEM\CurrentControlSet\Control\FileSystemのLongPathsEnabled(DWORD)が0以外
  3. アプリケーションのManifestで
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
            <ws2:longPathAware>true</ws2:longPathAware>
        </windowsSettings>
    </application>
    が指定されている

レジストリに関して、特定のAPI(see MSDN)を使用することでそのアプリケーションは常にMAX_PATH制限が緩和され、それ以後にレジストリが0に設定されても、MAX_PATH制限は解除されたままである。逆にレジストリが0に設定されていて特定のAPIを実行した場合、そのアプリケーションは常にMAX_PATHは260に制限される。

フルパスの最大長はファイルシステムによって制限される。NTFS/exFAT/UDFS/FAT32/VFATの最大パス長は32760(see MSDN)。32767じゃないのは\\?\C:\分を減らしているせい?

UDFSのファイル名の最大長はasciiだと254文字、ユニコードだと127文字。ascii+ユニコードだと127文字扱い。asciiはU+0020~U+00FFまでの範囲。ファイル名がこの文字の範囲内のみ使用しているならば254文字。1文字でもU+0100以降の文字がある場合は127文字が最大になる。これは他のFileSystemからUDFSにコピーするときに問題になる場合があるので注意。めんどくさい。GetVolumeInformationで取得できる最大ファイル名は254文字だけど、この制限があるから素直に使っちゃうとアレでナニ。

| | コメント (0) | トラックバック (0)

2016年6月14日 (火)

ソート覚え書き

♪ドレミファソートをDelphiに移植して幾つかの覚え書き。

quick sortは在る閾値pに対して、対象をp以下、p以上に二分して分割ソートしていく。
♪ドレミファソートの場合、それをp未満、p、pより大きい、の3つに分割し、p未満とpより大きい部分を分割ソートの対象とする。
オリジナルの♪ドレミファソートの場合、左右のデータの入れ替え時に、入れ替えたデータがpだった場合、一旦左右の端にpを詰め込んでいく。左右のデータ入れ替え終了後に、左右に詰め込んだpを中央に持ってきて三分割することになる。この最後の処理がかなり重く、オリジナルのロジックではソートデータの構造やスワップ処理党に工夫を凝らしてかなり高速化している。逆に、このぐらい高速化しないと元が中々取れない。
Delphiでプリミティブに実装した場合、このオーバーヘッドがかなりきつく、median of 3の通常のquick sortよりも大分遅い。早かったのは全部一定値のデータ とメディアンキラーな山形のデータ配置のみ。いろいろ試して見て、以下のコードがどうにか実用範囲内のスピードに落ち着いた感じ。

procedure T♪DoReMiFaSortThread.Sort(pData:PDataAry);
  procedure srt(L,R:integer);
  const
    InsLimit = 48;
  var
    w,p:uint32;
    wp : array[0..4] of uint32;
    x,i,j,M,pr_idx,pr_l_idx,pl_idx,pl_r_idx,chgL_idx,chgR_idx:integer;
  begin
    if InsLimit<(R-L) then begin
      // ♪ドレミファソート
      // pivot > 5つの中から選ぶ
      M:=(L+R) div 2;
      wp[0]:=pData[L];
      wp[1]:=pData[(L+M) div 2];
      wp[2]:=pData[M];
      wp[3]:=pData[(M+R) div 2];
      wp[4]:=pData[R];
      for i := 1 to 4 do begin
        w:=pData[i];
        if (pData[i-1] > w) then begin
          j:=i;
          repeat
            pData[j]:=pData[j-1];
            dec(j);
          until (j<=0) OR (pData[j-1]<=w);
          pData[j]:=w;
        end;
      end;
      p:=wp[3];
      // sort
      i:=L; j:=R;
      pl_idx:=-1; pr_idx:=-1;
      repeat
        while (pData[i]<p) do inc(i); // p以上を探す
        while (pData[j]>p) do dec(j); // p以下を探す
        if i=j then begin
          inc(i); dec(j);
          break;
        end;
        if i<j then begin
          w:=pData[i]; pData[i]:=pData[j]; pData[j]:=w;
          // pivot値の一番左端&右端のindexを覚えておく
          if pData[i]=p then begin
            if (pl_idx=-1) then pl_idx:=i;
            pl_r_idx:=i;
          end;
          if pData[j]=p then begin
            if (pr_idx=-1) then pr_idx:=j;
            pr_l_idx:=j;
          end;
          // 次へ
          inc(i); dec(j);
        end;
      until i>j;
      // ユーザー要請による中断判定
      if Terminated then raise EAbortSort.Create('abort');
      // 分割後、左の範囲に対してpivot値を右端に寄せる
      chgL_idx:=j;
      if pl_idx<>-1 then
        for x := pl_r_idx downto pl_idx do begin
          if pData[x]=p then begin
            pData[x]:=pData[chgL_idx]; pData[chgL_idx]:=p;
            dec(chgL_idx);
          end;
        end;
      // 分割後、右の範囲に対してpivot値を左端に寄せる
      chgR_idx:=i; // 右分割位置の左index start値
      if pr_idx<>-1 then
        for x := pr_l_idx to pr_idx do begin
          if pData[x]=p then begin
            pData[x]:=pData[chgR_idx]; pData[chgR_idx]:=p;
            inc(chgR_idx);
          end;
        end;
      // pivot値を除いて、左右分割して再帰呼び出し
      srt(L,chgL_idx);
      srt(chgR_idx,R);
    end else begin
      // 挿入ソート
      for i := L+1 to R do begin
        w:=pData[i];
        if (pData[i-1] > w) then begin
          j:=i;
          repeat
            pData[j]:=pData[j-1];
            dec(j);
          until (j<=0) OR (pData[j-1]<=w);
          pData[j]:=w;
        end;
      end;
    end;
  end;
begin
  srt(0,AryLimit-1);
end;

データスワップ時にpの位置の左右両端を覚えておき、スワップ終了後にpを中央に寄せるという形。これだとmedian of 3のquick sortより通常4~5%落ちくらいの測度で納まる。constance dataやmedian killerだとかなり早い。うーむ。思っている以上にデータ転送のコストが高いんだねぇ...。

追記
左右両方の区間でpを寄せるよりも、どちらか片方だけ寄せる方がコストとスピードのバランスが良さげ。

追記その2
結局の所、pivotをどうやって旨く取るかってのが大部分を握ってるなぁ...。

| | コメント (0) | トラックバック (0)

2015年9月 4日 (金)

Delphi 10で64bitコード上でSSEを含むアセンブラを書く

メモも兼ねて書いておきます。まずはこれ。

mandelbrot_0_3.zip
size : 2,238,160 bytes
SHA256 : f4675581b0adf165ad1c863f88a1e884f08f3724822e9c36715193f4132e81c7

昔書いたコードをDelphi 10でコンパイルできるようにした物。機能追加とかは無し。AVX2対応は10月に新PC買う予定なんで、それの環境が整ってから。

んで、Delphi10でコンパイルする時に嵌まった物。コンパイル自体はできるんだけど、64bit版だけ実行すると計算が延々と終わらない。なんでやー! とデバッガつかってみたら、何故過飽和演算のハズなのにオーバーフローエラーでとまっとる! SSEの意味がないじゃん! とか思いつつ調べたらXE2と2つほど変わってる点がありました。
1つ目はXMMレジスタの保護範囲。XE2だとXMM6~XMM15が保護範囲だったんだけど、Delphi10ではXMM4~XMM15までになってました。
2つ目は例外設定。Delphi 10だデフォルトでとSSEがoverflow exceptionを投げるようになってました。まー64bitだとSSEで浮動小数点計算するから、互換性考えるとそっちの方が正しいよね。
てことで、この2点を修正したらばDelphi 10でコンパイルした64bit binaryもちゃんと動くように。

しかし、Delphi 10になってもAVX/AVX2のアセンブラサポートが無かったのにはがっかりだよ! 当面は別途アセンブラでがりがり書くしかないねぇ。

2016/1/17 urlを新サイトに変更

| | コメント (0) | トラックバック (0)

2015年9月 3日 (木)

Delphi 10

Delphi XE2を買ってからしばらくの間ver upをほったらかしにしてました。理由は単純で、つい最近までメインPCのOSがWindows 7だったので、XE2でほぼ問題なかったから。sub pcはWin8→Win8.1とver upしてたんだけどそっちはまあ、ほぼ検証用とかだったしねー。
で、この度メインとサブの両方のPCのOSをWindows 10にしました。したら、XE2だと64bitバイナリのデバッグが出来ないことが判明。どーにかならんかなーと調べてみたんだけど、結局Windows 8以降はXE3以降じゃないと64bitのdebugができないと。しょーがないんで(その当時最新の)XE8を買おうと思ったら、XE2からのver upは出来なくて新規のみ。130Kもする! ...ちょうど某お仕事でお金は入るんだけどディスプレイのほうが優先だったのでDelphiを後回しにしてたんだよね。したら。。。Delphi 10のリリースと、それに伴う旧verからの特別ver upとか! 税込みで70K未満でいけるのが分かって速攻申し込みましたよ、ええ。XE2が2011年だから4年振りになるのかぁ。
で、シリアルコードが届くまではトライアルで様子見するかぁとTrial verをダウンロードしてインストール。で、メールで届いたサイトでトライアルコードを見ようとすると...文字が化けてさっぱり! どうしようも無いんでその日は諦めて、次の日日本語ページから飛んで再度トライアルを試したら今度はOKでした。
でも、それが次のハマリへの伏線だったとは。
今日になって製品版のシリアルコードが届いたので、とりあえずトライアルをアンインストールしてDelphi 10をインストール。完了後、ちょっと知りたかったWM_DPICHANGEDのメッセージ用構造体をみてみようとおもったら、sources以下にDUnitしかソースが無い。ええええええ! VCLのソースが無いの? Professionalなのに?!  と焦ったんだけど、ここでふと気がついたことが。もしかしたらトライアルをインストールしてたせい? ということで、ライセンスマネージャからトライアル用のライセンスを削除した上で、Delphi 10をレジストリごとアンインストール。その上で再インストールしたらちゃんとソースも展開されました。やれやれだぜー。
そのあと、DEKOさんからtwitterで突っ込みもらっちゃったのは、ご愛敬ということで。

で、ちょっとAyaClockをDelphi 10にプロジェクトを移してみたんだけど。前にもあったけど旧versionのプロジェクトをそのままコンバートすると64bit版ではdebug出来ないてのがやっぱり発生。まあ、これはプロジェクトファイル以外をもっていて.dpr読み込んで新規プロジェクトを作るで解決できるのであまり問題じゃなかったね。とりあえずSASF3もコンパイルできて一応動いたし。

てなことで、今後はDelphi 10での作業がメインになるかなぁ。これでVISTAのサポートも打ち切り。ま、VISTAの人はほとんど居ないだろうけど。

| | コメント (0) | トラックバック (0)

2015年9月 1日 (火)

Per-Monitor対応

WIndows 10上でマルチモニタ環境になったついでに、自作アプリのPer-Monitor対応を初めて見ました。XE2でな!
最初はまず簡単なところでAyaClockからいくかぁ、ってことで始めたんだけど...なぜかWM_DPICHANGEDが飛んでこない。新規に作ったテストFormには飛んでくるんだけどねぇ。で二日くらいやって全然理由が分からなくて、最後にmanifestを作り直したらいけました...orz なんでやねん。旧manifestと新manifestの違いはdiffとっても分からない。もうねー。

ま、とりあえず自力でDPIスケーリングをハンドリングできるようにしました。ドラッグ中にDPIの違うウインドをまたいでもドラッグが終わるまではサイズ変更は起きません。あと、動的にDPI変更したときに位置がおかしくなる問題も対応。ただ、このへんはWindows 8.1以降じゃないとだめ。Vista/7/8だと、そもそもDPIの変更がアプリに通知されないので対応できないんだよねー。まあ、起動時のDPIはきっちり取得するようにしたから大丈夫だとは思うけど。

で、次はICON。今までは16x16と32x32だけだったのに加えて48x48と256x256を追加。マイクロソフトのガイドラインを読む限りではこれで充分ぽいけど。とりあえずGIMPで外側の円と針だけ作成して、数字はgfieで作成してICONにコンバート。絵心が無いのはしょうが無いので諦める、と。

あとは.NET版弄ってから、SASFでどう対応するかだなぁ。フォントサイズの管理がちょいと面倒なのは分かったし。うーむ。

| | コメント (0) | トラックバック (0)

2015年8月20日 (木)

4K!

昨日、ついにEV3237が届きました。いや、でかいね。そして広い。今まで使っていたS2431はサブモニターとして使用することになりました。HD7850-2Gで行けるかな? とちょっと不安だったけど、余裕でした。その上DDOも楽々動く。これでR9 380とか買わないで済むよ!
Dual_monitor
デフォルトのscaling 150%だと確かにソフトとか見やすいんだけどちょっと広さがもったいないよね-、ってことで125%に変更。...なんか微妙な表示のソフトが増える(含む自作ソフト)。どうせなら100%に! ...文字が小さくて辛いです。でも、意外と読める。さすがに高精細度だねぇ。ふとおもったんだけど、Windows10ってこのくらいのサイズ&解像度を念頭にフォントを選んだんじゃないかな。1920x1200だと、ちと不満があったYu Gothic UIも、EV3237だと違和感がないんだよねぇ。

そして、高解像度&マルチモニタになって自作ソフトの細かい不具合が目に付くように。手直ししたいけどしばらくそんな余裕が無いしなぁ。更にXE8にしないと64bit版のデバッグができないし。ぐぬぬぬ....。その辺は9月末だなぁ。

| | コメント (0) | トラックバック (0)

2014年11月 8日 (土)

単純ミス

Jpeg2000をちゃんと書き出せなかった件、単純ミスでした。seekstream関数、seekの開始点をcurrentにしてたけど、本当は先頭からにしないとダメだったっす。うひー。skipstreamはcurrentが基準。まあ、そんな物よね...。

| | コメント (0) | トラックバック (0)

2014年11月 5日 (水)

ぐぬぬ。

OpenJpeg v2.1.0を使ってDelphiでJpeg2000を扱うユニット作成。とりあえず読み込むところはok。いろいろマズーな所は有るかもしれないけど! 今んところEYCCは不可、CMYKはサポートしたけどちゃんと動くかは未確認、とかいろいろ有るけど!
今は書き出す所で詰まってます。はき出せてはいるんだけど、一部ヘッダが不正なデータで書き出しているらしい...。作成時に与えるパラメータはcppの方のサンプルとおんなじなんだけどなぁ。うーん...どこが違っているのかがわからぬ...。

| | コメント (0) | トラックバック (0)

より以前の記事一覧