2022-08-11 読書メモ

文字列を示す "abc"、_T("abc\")、L"abc" は全て意味が違う!(UsefullCode.net)

まず自身の認識。TCHARUNICODE ビルドする/しないに応じて WCHAR / char のどちらにもなり得るプレースホルダ的なもの。

‘_T("<文字列>")‘ も同様で、UNICODE ビルド時は UNICODE 文字列として、非UNICODE ビルド時は Shift-JIS 等として扱われるそうだ。

ワイド文字

用語

  • ANSI C は標準でワイド文字をサポートしている
  • ワイド文字: 1文字表現するのに2バイト用いるもの
  • マルチバイト文字: 1バイト以上の文字のこと

L プレフィクス

文字列の前に付加することでコンパイラにワイド文字列として扱うよう指示する。

LinuC レベル1-101

cut コマンドのデリミタ指定

デフォルトでタブ区切りだが、タブ区切りを明示指定する場合は -d $'\t' のように指定する。Ctrl + V の後にタブキーを押しても良いが、-d $'\t' のほうがスクリプトとしては見やすい。しかしこれなんていう表記方法なんだろう。

fmt と fold

fold が指定桁数で問答無用で折り返すのに対し、fmt は単語境界等を考慮する。

C++ リテラル "あいうえお" のエンコード

C/C++ が何も分からないので、細かいことを無理に理解しようとせずいろいろやってみたい今日この頃。実行環境は Visual Studio 2022

char s[] = "あいうえお" のエンコード

#include <iostream>
using namespace std;

int main()
{
    char s[] = "あいうえお";
    cout << s << endl;
}

として実行すると、デバッグコンソールに あいうえお と表示される。問題はこのときのコードポイントが 932 (ANSI/OEM - Japanese Shift JIS) だということ。特に明示的にエンコードしていないが、どうやら Shift JIS エンコードされているらしい。

"あいうえお" のサイズ

Visual Studio 上で "あいうえお" にマウスオーバーすると (const char [11])"あいうえお" と出る。内部的に何らかのエンコーディングが施されていて、(文字列終端を除けば) 1文字あたり2バイト使っている計算。

"あいうえお" を1byteずつ表示させてみる

#include <stdio.h>
#include <iostream>
using namespace std;

int main()
{
    char s[] = "あいうえお";

    cout << s << endl;

    for (int k = 0; k < sizeof s; k++) {
        printf("%X ", (unsigned char)s[k]);
    }
}

実行結果

あいうえお
82 A0 82 A2 82 A4 82 A6 82 A8 0

文字コード表 シフトJIS(Shift_JIS) を見て確認。Shift JIS としてエンコードされており、ビッグエンディアンで格納されていることがわかる。

まとめ

正確なところはよくわからないが、Visual Studioコンパイラ設定?として非ASCII 文字リテラルを環境に応じていい感じにエンコードするようにしてくれているのかもしれない。

INT_MAX (DRAFT)

概要

ε-N論法について - Qiita ε\text{-}N 論法を勉強するために読んでいたのだけれど、例として C のコードで表現されている部分が理解できなかったのでメモ。C 言語は現状入門サイトを読んだくらい…。

float a[ INT_MAX ] (Win10, VS2022)

まずこの時点で目玉が飛び出そうになる。ものすごく巨大な配列を宣言しているように見えるが…。

手元に Visual Stdio 2022 Community をインストールし、C++ コンソールプロジェクトを作成して書いてみる。

まず、INT_MAX が定義されていないのでエラーになった。C言語入門 - 整数型(char型 int型)の最大値と最小値 - limits.h - Webkaru を読むと INT_MAXlimits.h に定義されているようなので include する。

#include <stdio.h>
#include <limits.h>

int main(void) {
    float a[ INT_MAX ];
    return 0;
}

array is too large のエラーが出る。無理やりビルドすると error C2148: total size of array must not exceed 0x7fffffff bytes と出る。やっぱりちょっと無茶な配列確保をしているように見えるが…。

INT_MAX はいくつか

エラーを解釈するため、順番に確認してく。まず INT_MAX がいくつなのか。

int main(void) {
    printf("INT_MAX = %d\n", INT_MAX);
    return 0;
}

// INT_MAX = 2147483647

2,147,483,647 (232 - 1) のようだ。これは 0x7fffffff に等しい。

sizeof_t(float) はいくつか

配列サイズが 型のサイズ * 要素数 で決まるならば、次に float のサイズが気になるところ。

int main(void) {
    printf("sizeof(float) = %d\n", sizeof(float));
    return 0;
}

// sizeof(float) = 4

sizeof(float) = 4 らしい。

なお書式指定子に %d を指定するのはダメなようで、下記のような警告が出ている。

Code Description
Warning C6328 Size mismatch: 'unsigned int64' passed as Param(2) when 'int' is required in call to 'printf'.
Warning C4477 'printf' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'size_t'
size_t 型を printf するための書式指定子は何か

いろいろググるVisual Studio C コンパイラが C の標準規格?にどこまで対応しているか?みたいな話が出てきてよくわからなくなってきたのだが、printfとsize_t型 - yohhoyの日記 を読むととりあえず %zd のように指定すると良いようで、警告は消えた。

配列サイズが 0x7fffffff bytes 未満になるように宣言してみる

以上より、INT_MAX = 0x7fffffff であること、sizeof(float) = 4 であることが分かった。

  (INT_MAX / 4) * 4
= (2,147,483,647 / 4) * 4)
= 2,147,483,644
= 0x7ffffffc < 0x7fffffff

だから、要素数INT_MAX / 4 にすればエラーは出ないのではないか。

int main(void) {
    float a[ INT_MAX / sizeof(float) ];
    return 0;
}

// fatal error C1126: automatic allocation exceeds 2G

error C2148: total size of array must not exceed 0x7fffffff bytes は出なくなったが、代わりに fatal error C1126: automatic allocation exceeds 2G が出た。

automatic allocation exceeds 2G エラーが出ないサイズを探す

INT_MAX / 4 = 536,870,911 から2分探索で減らしていきながら確かめた。

int main(void) {

    //--- fatal error C1126: automatic allocation exceeds 2G
    // float a[ INT_MAX / sizeof(float) ];

    //--- fatal error C1126: automatic allocation exceeds 2G
    // float a[511999993];

    //--- Stack overflow
    float a[511999992];

    return 0;
}

素数 511,999,992 のときにコンパイルエラーは出なくなったが、今度は実行時に Stack overflow が発生した。

Stack overflow が出ないサイズを探す

同じように2分探索で減らしていきながら確かめた。

int main(void) {

    //--- fatal error C1126: automatic allocation exceeds 2G
    // float a[ INT_MAX / sizeof(float) ];

    //--- fatal error C1126: automatic allocation exceeds 2G
    // float a[511999993];

    //--- Stack overflow
    // float a[511999992];

    float a[ 257175 ]; //--- 明確な境界は無いが大体このあたり

    return 0;
}

同じ値でも Stack overflow が起きるときと起きないときがあるものの、257,000 あたりから発生する様子。sizeof(float) = 4 をかけると 1,028,000 となることから、大体 1MB あたりに上限がありそうだ。

Stack サイズを増やす

"visualc stacksize increase" とかでググっていたところ、/STACK (Stack allocations) | Microsoft Docs を見つけた。

The /STACK linker option sets the size of the stack in bytes. Use this option only when you build an .exe file.

The reserve value specifies the total stack allocation in virtual memory. For ARM64, x86, and x64 machines, the default stack size is 1 MB.

やはりスタックサイズはデフォルト 1MB らしい。そしてこの値は project's Property Pages から変更できると書かれている。

  • Visual Studio メニューバーから Project<プロジェクト名> Properties とクリックすると <プロジェクト名> Property Pages が開く
  • Configuration PropertiesLinkerSystem と進む
  • Stack Reseve Size を大きな値にする。今回は INT_MAX と同じ 2147483647 としてみた

Stack サイズを増やしてから再実行

int main(void) {

    //--- fatal error C1126: automatic allocation exceeds 2G
    // float a[ INT_MAX / sizeof(float) ];

    //--- fatal error C1126: automatic allocation exceeds 2G
    // float a[511999993];

    //--- 成功
    float a[511999992];

    return 0;
}

511999992 指定時はデフォルトでは Stack overflow となったが、Stack サイズを増やしたところ成功。511999993 のときは変わらず fatal error C1126: automatic allocation exceeds 2G が出る。こちらは Stack サイズとはまた別の制限なのかもしれない。

結論: float 配列 をローカル宣言する場合のサイズ上限 (VS2022)

Windows + Visual Studio 2022 環境において、Stack Reseve Size を十分大きく取った場合、float 配列は要素数 511,999,992 までならローカル変数として宣言できる。

float a[ INT_MAX ] (Ubuntu 20.04.3 LTS)

上記では Visual Studion 2022 上でゴリゴリ調べていたが、Linux だとどうなのだろう?と思い立った。

$ cat ipsd.c
#include <limits.h>
#include <stdio.h>

int main(void) {
    float a[ 2096110 ];
    return 0;
}

$ gcc ipsd.c && ./a.out
$ gcc ipsd.c && ./a.out
Segmentation fault (core dumped)
$ gcc ipsd.c && ./a.out
Segmentation fault (core dumped)
$ gcc ipsd.c && ./a.out
Segmentation fault (core dumped)
$
$ gcc ipsd.c && ./a.out
$ gcc ipsd.c && ./a.out
Segmentation fault (core dumped)
$ gcc ipsd.c && ./a.out
$ gcc ipsd.c && ./a.out
$ gcc ipsd.c && ./a.out

やはり安定はしないが、要素数 2096110 あたりが上限に見える。VS2022 に比べると大きく見える。

Linux のスタックサイズ上限

Linux Stack Sizes - Stack Overflow を見ると Linux のスタックサイズ上限は ulimit -s で確認/設定できるとのこと。自身の環境も 8192 だった。

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31289
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31289
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

スタックサイズを増やしてから再実行

$ ulimit -s unlimited
$
$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31289
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) unlimited
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31289
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
$
$ cat ipsd.c
#include <limits.h>
#include <stdio.h>

int main(void) {
    float a[ INT_MAX ];
    return 0;
}

$ gcc ipsd.c && ./a.out
$ time ./a.out

real    0m9.900s
user    0m0.380s
sys     0m1.829s

ということで、float a[ INT_MAX ] でも全く問題なく実行できた。

ちなみに実行環境は ESXi 上に建てた Ubuntu VM で、割り当てメモリは 8G。上記実行中に top を見ると メモリの used7810 MiB まで上昇していた。INT_MAX * 4 = 8589934588 なので、おおよそ計算は合うことになる。

結論: Linux での float a[ INT_MAX ]

物理メモリが十分あって、ulimit -s unlimited していれば問題無し。元記事の筆者の方ももしかすると Linux 環境で試されていたのかもしれない。

休憩

float a[ INT_MAX ] を解釈するだけですごく大変だった。続きはまた今度。

はてなブログで Tex 記法が崩れる問題

概要

数学の復習をしたい → はてなブログは数式が書けるはずだ → ググってみるとどうやら [tex: ] という記法を使うらしい。→ うまく表示されないよ!という話。

結論: <div></div> で囲むとうまくいく。

うまくいく場合

例えばこのように書いてみる: [tex: ∀ε > 0, ∃N∈\mathbb{N} ]

  ∀ε > 0, ∃N∈\mathbb{N}

上記のように問題なく表示されている。

このときページソースはこの形。

<script type="math/tex" id="MathJax-Element-1">
 ∀ε > 0, ∃N∈\mathbb{N} 
</script>

うまくいかない場合

しかしこのように書いてみると: [tex: | a_n - \alpha | < ε ]

 | a_n - \alpha | &lt; ε

上記のようにうまくいかない。

このときページソースはこの形。< がなぜか &lt; と HTML エスケープされてしまっている。

<script type="math/tex" id="MathJax-Element-2">
 | a_n - \alpha | &lt; ε 
</script>

div で囲うと大丈夫

はてなブログで数式(Markdown) - エフアンダーバー を読んで回避策を見つけることができた。<div> で囲むとよいらしい。

<div style="margin: 1em">[tex: | a_n - \alpha | < ε ]</div>
 | a_n - \alpha | < ε

正常に表示された。

あらためて

書きたかったのは  ε\text{-}N 論法。

<div style="padding: 1em">
[tex: \displaystyle {
∀ε > 0, ∃N∈\mathbb{N}
 \ \ s.t. \ \ 
∀n ∈ \mathbb{N},n \geq N \Rightarrow  | a_n - \alpha | < ε
}]
</div>
 
∀ε > 0, ∃N∈\mathbb{N}
 \ \ s.t. \ \ 
∀n ∈ \mathbb{N},n \geq N \Rightarrow  | a_n - \alpha | < ε

うまく出力できた。これで数学関係のメモもブログに書けるだろうか。

そもそも Tex 記法がさっぱりなのでそれも勉強しないといけない。

LinuC 1-101 勉強

07/23

man のセクション番号

が覚えられないので語呂合わせを考えてみる。

ユーザのシステムをライブでデバイス設定するゲーム

セクション番号 説明
1 ユーザーコマンド
2 システムコール
3 ライブラリ
4 バイスファイル
5 設定ファイル
6 ゲーム

man コマンドを叩ける環境が手元にない。仮想マシンを立てるべきか。

man コマンドオプション

-k (--apropos)

-k, --apropos
       Equivalent to apropos.
       Search the short manual page descriptions for keywords and display any matches.
       See apropos(1) for details.
NAME
       apropos - search the manual page names and descriptions
DESCRIPTION
       Each manual page has a short description available within it. 
       apropos searches the descriptions for instances of keyword.

search A for B: B を求めて A を調べる,探す (引用)

page names / descriptions にキーワードを 含む ものを検索する。apropos は "適切に","折よく" といった意味。

$ man -k cron
cron (8)             - daemon to execute scheduled commands (Vixie Cron)
crontab (1)          - maintain crontab files for individual users (Vixie Cron)
crontab (5)          - tables for driving cron
keep-one-running (1) - run just one instance at a time of some command and unique set of arguments (useful for cronjobs, eg)
run-one (1)          - run just one instance at a time of some command and unique set of arguments (useful for cronjobs, eg)
run-one-constantly (1) - run just one instance at a time of some command and unique set of arguments (useful for cronjobs, eg)
run-one-until-failure (1) - run just one instance at a time of some command and unique set of arguments (useful for cronjobs, eg)
run-one-until-success (1) - run just one instance at a time of some command and unique set of arguments (useful for cronjobs, eg)
run-this-one (1)     - run just one instance at a time of some command and unique set of arguments (useful for cronjobs, eg)

-f (--whatis)

-f, --whatis
        Equivalent to whatis.
        Display a short description from the manual page, if available.
        See whatis(1) for details.
NAME
       whatis - display one-line manual page descriptions
DESCRIPTION
       Each manual page has a short description available within it.
       whatis searches the manual page names and displays the manual page descriptions of any name matched.
$ man --whatis cron
cron (8)             - daemon to execute scheduled commands (Vixie Cron)

$ man --whatis crontab
crontab (5)          - tables for driving cron
crontab (1)          - maintain crontab files for individual users (Vixie Cron)

-k, apropos と違い、page name がキーワードに 一致 するものを検索する。

ESXi 環境で遊びたい

前回までのあらすじ

Dell の G5 5000 という PC を昔買った.無駄にメモリが 64 GB もあるし単体で使うのはもったいないと,VMware vSphere Hypervisor (ESXi) をインストールしたのだった.それが楽しい地獄の始まりだった.

最初に悟ったのは ESXi はハードウェアとセットで買うものだなということ.そこらの適当な SSDNIC だとインストール時点でさっぱり認識しない.仕事で触るものは HP サーバなんかと一緒にライセンス購入しているのでそのあたり気にしたことがなかった.

その後ググりまくって Intel チップの NIC を取り付けたり ESXi のバージョンを下げたりして最終的にやっと ESXi 6.7 Update 1 のインストールに成功したのだった.

旧環境 (Hyper-V) から Windows VM を引っ越し,ライセンス認証して一息ついた後,「これだとせっかくの GeForce RTX 2070 が VM で生かせないじゃないか」と気づいた.そして PCI パススルーという概念を知り,さらなる地獄に突入していくのだった.

最終的に疲れ切ってしまい,結局今は 13 年もののデスクトップ PC をメインに使っている.

やりたいことを整理する

さてこの ESXi 環境で自分は何がしたいのか

  • VM Win 10 をメイン使いとしたい
  • GPU を生かしてゲームとか機械学習の勉強したい.

自然,PCI パススルーが要件になってくる.

あるべき形と遊び心

身も蓋もない結論から言うと,G5 5000 はそこそこ性能のいいゲーミング PC なのだから素直にスタンドアロンで使って,ESXi で遊びたいのであれば別途それ向きのハードウェアを買えばいい.それが最も自然な形.

だがお財布は厳しい.それが現実.それにせっかくの自宅環境,会社ではとてもできない攻めた構成をするチャンス.楽しい地獄に行こうじゃないか.

ESXi ホスト現状確認

ハードウェア情報

ESXi shell からコマンドで確認していく.

#--- ESXi 情報
[root@ESXI-01:~] vim-cmd hostsvc/hostsummary | grep -e fullName
         fullName = "VMware ESXi 6.7.0 build-10302608",
#--- PC モデル
[root@ESXI-01:~] esxcli hardware platform get
Platform Information
   UUID: *****
   Product Name: G5 5000
   Vendor Name: Dell Inc.
   Serial Number: *****
   Enclosure Serial Number: *****
   BIOS Asset Tag:
   IPMI Supported: false
#--- CPU 情報
[root@ESXI-01:~] vim-cmd hostsvc/hostsummary | grep -e cpuModel
      cpuModel = "Intel(R) Core(TM) i7-10700KF CPU @ 3.80GHz",

[root@ESXI-01:~] esxcli hardware cpu global get
   CPU Packages: 1
   CPU Cores: 8
   CPU Threads: 16
   Hyperthreading Active: true
   Hyperthreading Supported: true
   Hyperthreading Enabled: true
   HV Support: 3
   HV Replay Capable: false
   HV Replay Disabled Reasons: incompatible CPU
#--- メモリ 情報
[root@ESXI-01:~] esxcli hardware memory get
   Physical Memory: 68482859008 Bytes
   Reliable Memory: 0 Bytes
#--- SSD 情報
[root@ESXI-01:~] esxcli storage core device uidmap list

#--- SanDisk SATA SSD 240 GB
t10.ATA_____SanDisk_SSD_PLUS_240GB__________________20248N442803________
   Primary UID: t10.ATA_____SanDisk_SSD_PLUS_240GB__________________20248N442803________
   Alternative Primary UIDs:
   Legacy UID: vml.010000000032303234384e343432383033202020202020202053616e446973
   Alternative Legacy UIDs:

#--- Samsung NVMe SSD 512GB (ESXi システムディスク)
eui.353039304e8771560025384600000001
   Primary UID: eui.353039304e8771560025384600000001
   Alternative Primary UIDs: t10.NVMe____PM991_NVMe_Samsung_512GB______________________S509NF0N87715600000001
   Legacy UID: vml.0100000000333533305f333933305f344538375f373135365f303032355f333834365f303030305f303030312e504d3939
   Alternative Legacy UIDs: vml.0100000000202020202020533530394e46304e383737313536504d39393120

#--- SanDisk SATA SSD 240 GB
t10.ATA_____SanDisk_SSD_PLUS_240GB__________________20248N446313________
   Primary UID: t10.ATA_____SanDisk_SSD_PLUS_240GB__________________20248N446313________
   Alternative Primary UIDs:
   Legacy UID: vml.010000000032303234384e343436333133202020202020202053616e446973
   Alternative Legacy UIDs:

RDM ディスク情報

SATA 接続の SSD 2枚を VM 向けにパススルーしている.Maps to:vml. ... が上記 esxcli storage core device uidmap list の Legacy UID と対応している様子。

[root@ESXI-01:~] vmkfstools -q /vmfs/volumes/datastore1/RDM/SanDisk_SSD_PLUS_240GB_20248N442803.vmdk
Disk /vmfs/volumes/datastore1/RDM/SanDisk_SSD_PLUS_240GB_20248N442803.vmdk is a Passthrough Raw Device Mapping
Maps to: vml.010000000032303234384e343432383033202020202020202053616e446973
[root@ESXI-01:~]
[root@ESXI-01:~] vmkfstools -q /vmfs/volumes/datastore1/RDM/SanDisk_SSD_PLUS_240GB_20248N446313.vmdk
Disk /vmfs/volumes/datastore1/RDM/SanDisk_SSD_PLUS_240GB_20248N446313.vmdk is a Passthrough Raw Device Mapping
Maps to: vml.010000000032303234384e343436333133202020202020202053616e446973
[root@ESXI-01:~]

バイスパススルー状況

Address Description Passthrough メモ
0000:01:00.3 nVidia Corporation Serial bus controller Active VMGPU
0000:01:00.2 nVidia Corporation USB controller Active VMGPU
0000:01:00.1 nVidia Corporation Audio device Active VMGPU
0000:01:00.0 nVidia Corporation VGA compatible controller Active VMGPU
0000:03:00.0 Realtek Semiconductor Co., Ltd. Ethernet controller Active VM 用 LANポート
0000:05:00.1 Intel Corporation 82575EB Gigabit Network Connection Disabled ※未使用
0000:05:00.0 Intel Corporation 82575EB Gigabit Network Connection Disabled ESXi 管理アクセス用

Win10 VM 現状確認

PCI device 設定

PCI device 番号 バイス
PCI device 1 VGA compatible controller - 0000:01:00.0
PCI device 2 Audio device - 0000:01:00.1
PCI device 3 USB controller - 0000:01:00.2
PCI device 4 Serial bus controller - 0000:01:00.3
PCI device 5 Ethernet controller - 0000:03:00.0

モニタ出力

GPU パススルーしているので,RTX 2070 から HDMI ケーブルをモニタにつなげれば映る.再起動時やスリープ時に問題あり.

入力デバイス

オンボード USB ポートをパススルーできないので,マウスやキーボードを差せない.つまり直接動かす手立てがない.

音声出力

入力デバイスと同様,オンボードの音声入出力端子をパススルーできないため出力できない.

次にやること

  • USB カードを追加してパススルーし,USBマウス・キーボードを接続できるようにする
  • USB サウンドカードを接続し,外部スピーカーと接続する

まずはここからだ.

続き

it-muzukashiii.hatenablog.jp