同じメモリ(に見えた)を使って64GBから128GBにするのに苦労した話

結論

Ryzen 9 7950XとASRock B650 Steel Legend WiFiで、DDR5 32GBを4枚、合計128GB搭載したところ、起動時のメモリトレーニングでかなり苦労しました。

今回使ったメモリはCorsair VENGEANCE DDR5-5600です。

型番は4枚とも同じ、

CMK64GX5M2B5600Z40

です。

しかし、実際には64GB(32GB×2)のキットを2セット購入しており、メモリに記載されているVersionが異なっていました。

  • 2枚:Ver 3.34.02
  • 2枚:Ver 4.43.02

2枚構成なら、どちらのVersionでも問題なく起動します。

さらにVer 3とVer 4を1枚ずつ混在させても、A2/B2の2枚構成なら問題なく起動しました。

ところが4枚にすると状況が変わります。

メモリトレーニングが非常に長くなったり、DRAMランプが点滅したまま起動しなくなったりしました。

今回いろいろ試して分かったのは、

同じ型番のDDR5メモリでも、32GB×4の4 DIMM構成は、32GB×2とはまったく別物として考えた方がよい

ということです。


使用環境

今回の環境は以下です。

項目構成
CPUAMD Ryzen 9 7950X
マザーボードASRock B650 Steel Legend WiFi
BIOS4.43
メモリCorsair VENGEANCE DDR5
型番CMK64GX5M2B5600Z40
公称速度DDR5-5600
容量32GB×4 = 128GB
Ver3.34.02×2、4.43.02×2

最初はBIOS 3.01を使用していました。

メモリ関係の問題を疑い、最終的にはBIOS 4.43まで更新しています。


そもそもA1/A2/B1/B2とは何なのか

これも今回調べていて分かりにくかったところです。

B650 Steel Legend WiFiのDIMMスロットは、CPUに近い側から、

CPU
 |
 v

+-----------+    +----+ +----+ +----+ +----+
|           |    | A1 | | A2 | | B1 | | B2 |
| Ryzen 9   |    |    | |    | |    | |    |
| 7950X     |    |    | |    | |    | |    |
|           |    |    | |    | |    | |    |
+-----------+    +----+ +----+ +----+ +----+

という順番です。

ここで重要なのは、

  • A1/A2 = Channel A
  • B1/B2 = Channel B

という関係です。

論理的には、

                Ryzen 9 7950X
                      |
            +---------+---------+
            |                   |
        Channel A           Channel B
            |                   |
         +--+--+              +--+--+
         |     |              |     |
        A1    A2             B1    B2

となります。


なぜ2枚ならA2/B2なのか

ASRockのマニュアルを見ると、メモリを2枚だけ使用する場合はA2/B2に挿すよう指定されています。

最初は、

A1とA2があるのに、なぜ「1」ではなく「2」を優先するのか?

というのがよく分かりませんでした。

しかし、A/Bがメモリチャネルだと考えると理解しやすくなります。

A2/B2に1枚ずつ挿すと、

Channel A             Channel B
    |                     |
   A2                    B2
    |                     |
  32GB                  32GB

となり、CPUの2つのメモリチャネルを両方使用できます。

物理的には、

CPU側 →

A1     A2     B1     B2
[ ]    [RAM]  [ ]    [RAM]
        ↑             ↑

です。

このA2/B2が、各チャネル1枚で使用する場合の推奨スロットです。


2枚構成では問題がない

最初に各メモリキットを単独で試しました。

Ver 3.34.02を2枚、

A1     A2     B1     B2
[ ]    [V3]   [ ]    [V3]

として起動。

これは問題ありませんでした。

次にVer 4.43.02を2枚、

A1     A2     B1     B2
[ ]    [V4]   [ ]    [V4]

としても正常に起動しました。

つまり、どちらの64GBキットも単独では正常です。


Ver 3とVer 4を混ぜてみた

次に、

A1     A2     B1     B2
[ ]    [V4]   [ ]    [V3]

としてみました。

これも問題なく起動しました。

この結果はかなり重要でした。

少なくとも、

Ver 3とVer 4を混ぜた瞬間に起動できなくなる

というわけではありません。

A2/B2の2枚構成、つまり各チャネル1 DIMMであれば、異なるVersionを混在させても私の環境では正常に動作しました。


3枚にすると話が変わった

そこで3枚構成を試しました。

例えば、

A1     A2     B1     B2
[V3]   [V4]   [ ]    [V3]

です。

この構成ではうまく起動しませんでした。

DRAMのLEDが点滅し続け、メモリトレーニングから抜けられない状態になりました。

ところが別の配置、

A1     A2     B1     B2
[ ]    [V4]   [V3]   [V3]

では起動できました。

つまり単純に、

3枚だから絶対にダメ

というわけでもありません。

DIMMの配置によって結果が変わりました。


4枚ではメモリトレーニングが問題になる

最終的に使いたいのは、

A1     A2     B1     B2
[RAM]  [RAM]  [RAM]  [RAM]

という128GB構成です。

2枚の場合は、

Channel A : 1 DIMM
Channel B : 1 DIMM

なので1DPC(1 DIMM Per Channel)です。

一方4枚の場合は、

Channel A : A1 + A2
Channel B : B1 + B2

となり、2DPC(2 DIMMs Per Channel)になります。

同じ32GBのメモリを使っていても、CPUのメモリコントローラから見ると条件が大きく変わります。

今回の環境では、4 DIMMにするとメモリトレーニングが非常にシビアになりました。


DDR5-3600まで落としても解決しなかった

当然、DDR5-5600で4枚動かすのは厳しい可能性があるため、メモリクロックも落としました。

最終的にはDDR5-3600まで落として試しています。

しかし、

3600まで落とせば4枚でも簡単に安定する

という結果にはなりませんでした。

メモリトレーニング後に一度Windowsが起動することはあります。

問題は、その次の起動です。

再度メモリトレーニングが始まり、DRAM LEDが点滅したままになることがありました。

このため、単純なメモリクロックだけの問題ではないと判断しました。


Memory Context Restoreについて

AM5には、

Memory Context Restore

という設定があります。

これは、一度成功したメモリトレーニングの結果を次回の起動で再利用し、毎回フルのメモリトレーニングを行うことを避けるための機能です。

B650 Steel Legend WiFiのBIOS 4.43では、私の環境ではMemory Context RestoreはデフォルトでEnabledになっていました。

つまり今回、

MCRを有効にしていなかったから毎回トレーニングされていた

という単純な話ではありませんでした。

MCRがEnabledでも、4 DIMM構成ではトレーニング結果をうまく再利用できない場合がありました。


Power Down Enableも関係する

AM5のメモリ設定を調べていると、

Power Down Enable

という設定も出てきます。

これはDRAMの省電力機能ですが、Memory Context Restoreと組み合わせた際の挙動にも関係します。

今回、

Memory Context Restore = Enabled
Power Down Enable      = Enabled

という組み合わせも試しました。

ただし、MCRをEnabledにすれば必ず解決するというものではありませんでした。

128GBの4 DIMM構成そのものが正常にトレーニングでき、その結果を次回起動時に正常に復元できることが前提になります。


BIOSも3.01から4.43へ更新

最初に使用していたBIOSは3.01でした。

メモリ互換性やAGESAの更新もあるため、途中で最新の4.43へ更新しました。

BIOS更新後は、

  • EXPO
  • DRAM Frequency
  • Memory Context Restore
  • Power Down Enable
  • SoC Voltage
  • DRAM Voltage

などを一度Autoまたはデフォルトに戻し、そこから検証しています。

それでも2 DIMMと4 DIMMでは明確に挙動が違いました。


同じ型番でもVersionが違った

今回、もう一つ気になったのがCorsairメモリのVersionです。

4枚とも型番は、

CMK64GX5M2B5600Z40

で完全に同じです。

しかし実際には、

2枚:Ver 3.34.02
2枚:Ver 4.43.02

でした。

つまり、型番だけを見れば同じメモリですが、製造Versionは異なります。

ただし今回の検証では、

A1     A2     B1     B2
[ ]    [V4]   [ ]    [V3]

という異なるVersionを混在させた2枚構成でも正常に動作しました。

そのため、

Versionが違うから起動しない

と単純には結論付けられません。

むしろ、4 DIMMによって1チャネルあたり2枚になることの影響が大きいように見えます。


現在試している配置

3枚で、

CPU側 →

A1     A2     B1     B2
[ ]    [V4]   [V3]   [V3]

が正常に起動しました。

そこで現在は、

CPU側 →

A1     A2     B1     B2
[V4]   [V4]   [V3]   [V3]

という配置を試しています。

論理的には、

Channel A
 |
 +-- A1 : Ver 4.43.02
 +-- A2 : Ver 4.43.02


Channel B
 |
 +-- B1 : Ver 3.34.02
 +-- B2 : Ver 3.34.02

です。

各チャネルの中ではVersionを統一した形になります。

この配置で一度メモリトレーニングを正常に完走し、Windowsまで起動できれば、DIMMの位置を固定した上で、次回以降Memory Context Restoreが正常に機能するかを確認する予定です。


今回分かったこと

今回かなりの組み合わせを試しましたが、現時点では次のように考えています。

構成結果
Ver 3 ×2、A2/B2正常
Ver 4 ×2、A2/B2正常
Ver 3 + Ver 4、A2/B2正常
3 DIMM配置によって成功・失敗
4 DIMMトレーニングが非常にシビア
DDR5-36004 DIMM問題の完全な解決にはならず
BIOS 3.01使用当初の環境
BIOS 4.43更新後も検証継続
MCR Enabled4 DIMMで必ずトレーニングを回避できるわけではない

特に大きかったのは、

異なるVersionを2枚混ぜてもA2/B2なら正常に動く

という結果です。

これによって、単純なメモリVersion混在だけが原因とは考えにくくなりました。


最終的に64GB×2の方がよい可能性もある

今回の目的は128GB搭載することです。

その方法には、

32GB × 4 = 128GB

だけでなく、

64GB × 2 = 128GB

もあります。

AM5で128GBを安定して使用することを最優先するのであれば、64GB×2の方が合理的な可能性があります。

64GB×2なら、

A1     A2     B1     B2
[ ]    [64]   [ ]    [64]

となり、128GBでも1DPCを維持できます。

今回32GB×4で苦労している、

1チャネルにDIMMを2枚接続する

という条件そのものを避けられます。


最終判断

Ryzen 9 7950XでDDR5を128GB搭載する場合、

「DDR5-5600の32GBを4枚買って、速度を3600くらいまで落とせば普通に動くだろう」

と考えていました。

実際には、それほど単純ではありませんでした。

2枚ではまったく問題のないメモリでも、4枚にした途端にメモリトレーニングが非常にシビアになります。

さらに、

  • DIMMの配置
  • 1DPC / 2DPC
  • メモリのVersion
  • BIOS / AGESA
  • Memory Context Restore
  • Power Down Enable
  • メモリクロック

などが絡んできます。

少なくとも今回の検証では、異なるVersionの混在2枚構成は正常に動作しました。

したがって、現在最も疑っているのは、Versionの違いそのものではなく、

32GB×4による2DPC構成

です。

128GBが必要で、これから新しくメモリを購入するのであれば、32GB×4よりも64GB×2を選んだ方がトラブルは少ないと思います。

一方、手元に32GB×4があるので、もう少しこの構成で検証を続けます。

現在は、

A1     A2     B1     B2
[V4]   [V4]   [V3]   [V3]

という、各チャネル内でVersionを統一した配置を試しています。

この状態でMemory Context Restoreが正常に働き、毎回の長いメモリトレーニングを回避できるのか。

結果が分かったら追記します。

MacOSの配布用Qtアプリケーション作りが難解過ぎた

黒基調のウィンドウは格好良いです。

1週間以上掛けて、ようやく配布用アプリケーションが作成できました。
MacOS版チケットぴあ自動購入の処理は、1年前のソースコードをそのまま持ってきました。(プラスnewspプラグインの処理を入れています)
MacOS版の方がWindows版よりも購入できるという報告をちらほら聞くため、敢えてそのようにしています。Success PostでMac版を使った時にはそれが分かるようにしているので、そこで判断できます。

今のバージョンである、macOS Sequoiaは、AppleシリコンのM1以降でのみ対応されており、そのCPUでビルドしたアプリケーションを作成する必要がありました。

別件でMac Miniを購入したことと、ユーザからの要望があったので作成してみようと思った訳ですが、情報が殆どないためAIサービスに頼るしかありませんでした。

最初は、ChatGPTに聞いていたのですが、開発者IDを取得するところで躓いてしまい、先に進めなくなってしまったため、ChatGPTよりも賢いと評判のClaudeに相談することにしました。

Apple M1以降のCPUを搭載しているMacOS用に配布するためのQtアプリケーションを作成するには、アプリケーションに開発者IDを署名する必要があります。

公式には以下に作成方法が書かれているのですが、中途半端な開発者ID証明書を作成するところまでは簡単にできます。
https://developer.apple.com/jp/help/account/create-certificates/create-developer-id-certificates/

xcodeから作成するのが手っ取り早い。

結論から言うと、開発者ID証明書には、中間証明書とCA証明書を付加する必要があります。

Apple Root CAは以下からダウンロードして、キーチェーンアクセス.appにダブルクリックして取り込みます。
https://www.apple.com/certificateauthority/

中間証明書のありかは、Claudeに聞いて取得してきました。

1.G2の中間証明書を直接ダウンロード:
curl http://certs.apple.com/devidg2.der -o devidg2.der
2.ダウンロードした証明書をインストール:
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain devidg2.der

xcode→Settings→Accounts→Manage Certificatesで以下の画面を開き、+ボタンからDeveloper Application IDを指定すると、CAルート証明書までリンクしている自己証明書が作成されます。

コマンドで「security find-identity -v -p codesigning」を実行して、Developer ID Applicationがvalid状態であり且つ、ルートCA証明書まで正しく登録できていれば証明書の作成は完成です。

次に、アプリケーションに署名を付与していきます。

プロジェクト内に「entitlements.plist」を作成し、内容を以下にします。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>

proファイルに以下の項目を追加します。

macx {
ICON = res/ticketpia.icns
QMAKE_INFO_PLIST = Info.plist
ENTITLEMENTS.files = entitlements.plist
ENTITLEMENTS.path = Contents
QMAKE_BUNDLE_DATA += ENTITLEMENTS
}

ビルドを行い、macdeployqtにて必要なライブラリをapp内に取り込みます。QtWebEngine.appも同様に行います。

% macdeployqt ticketpia.app 
% macdeployqt ticketpia.app/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app

# パスを変更
install_name_tool -change /opt/homebrew/opt/brotli/lib/libbrotlidec.1.dylib @executable_path/../Frameworks/libbrotlidec.1.dylib ticketpia.app/Contents/MacOS/ticketpia

install_name_tool -change /opt/homebrew/opt/brotli/lib/libbrotlienc.1.dylib @executable_path/../Frameworks/libbrotlienc.1.dylib ticketpia.app/Contents/MacOS/ticketpia

install_name_tool -change /opt/homebrew/opt/brotli/lib/libbrotlicommon.1.dylib @executable_path/../Frameworks/libbrotlicommon.1.dylib ticketpia.app/Contents/MacOS/ticketpia

以下にてアプリケーションに署名していきます。

# 拡張属性をクリア
xattr -cr ticketpia.app

# メインアプリの署名
codesign --deep --force --verify --verbose \
--sign "Developer ID Application: KAZUHIRO OZAWA (VSAYCF9RQD)" \
--options runtime ticketpia.app

# WebEngineProcessの署名(entitlementsを指定)
codesign --deep --force --verify --verbose \
--sign "Developer ID Application: KAZUHIRO OZAWA (VSAYCF9RQD)" \
--options runtime \
--entitlements ticketpia.app/Contents/entitlements.plist \ ticketpia.app/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app

この2つの署名を行わないと、例えばWebEngineProcessの署名を行わない場合、ticketpia.appのアプリは起動するがWebEngineが表示されずに落ちてしまう現象が発生します。

この情報がどこかに刺さったら嬉しいです。

I2C通信に触れてみた

最近仕事でI2C通信に触れる機会があり、触ったことが無かったため、体験する良い機会だと思い、自分で機材を買って動作確認を行った。

OSはUbuntu 22.04を使った。最近Ubuntuに嵌ってしまい、Windowsに戻りたくない病を患っている。Ubuntuを使ってつくづく思うのは、Windowsはとても恵まれた環境だということだ。使っている人数がUbuntuとは桁違いに多いため、企業が積極的にサポートしているおかげで、ドライバは必ず対応されている。それに比べてLinux環境は、最新のものを使おうとするとドライバが自動でインストールされないことがあるため、自分で探してきてインストールする必要があったり、ドライバのアクセス権を宣言しないとドライバ自体が使えなかったりと色々な知識やググりが必要になる。

今回I2C通信を体験するにあたり買った機材は、以下の2つ。

サンハヤト USB・I2C(SMBus)変換モジュール MM-CP2112
https://www.sunhayato.co.jp/material2/ett09/item_1052
→USBポートからI2Cへ変換するCP2112というICが搭載されたもの。I2Cのマスター側として動作する。

I2C通信のスレーブ側として動作させるのが以下のモジュール。

Grove-I2C高精度温度および湿度センサー(SHT35)

https://jp.seeedstudio.com/Grove-I2C-High-Accuracy-Temp-Humi-Sensor-SHT35.html

I2C通信は、WriteとReadを同時に行うことはできない。Writeしたい場合は、I2Cアドレスに何バイトのデータを書き込むことを伝えて、ACKを受信後、書き込むデータをWriteする。Readしたい場合も同様に、I2Cアドレスに何バイトのデータを読み込むことを伝えて、ACKを受信後、読み込むデータをReadする。主導権は常にマスター側にある。この0x45(default)とox44(optional)の使い方がサンプルソースを読んでも理解できず、2〜3時間悩んだ。SHT35のサンプルソースは以下だが、Arduinoという評価ボードから実行するためのコードであるため、CP2112のAPIとは異なるArduino専用のAPIを使っている点が分かり辛さを増幅していた。

https://github.com/Seeed-Studio/Seeed_SHT35

SHT35のデータシート(以下を参照)には確かに「The ADDR pin must not be left floating. Please note that only the 7 MSBs of the I2C Read/Write header constitute the I2C Address.(I2C Read/Write ヘ ッ ダ の 7 MSB だ け が I2C Address を構成することに注意してください。)」と書いてあるし、
https://github.com/SeeedDocument/Grove-I2C_High_Accuracy_Temp-Humi_Sensor-SHT35/raw/master/res/Datasheet%20SHT3x-DIS.pdf

CP2112のAPI仕様にも「slaveAddress is the address of the slave device to write to. This value must be between 0x02 – 0xFE. The least significant bit is the read/write bit for the SMBus transaction and must be 0.(アドレスはデバイスのスレーブアドレス(0x02-0xFE)です。デバイスはこのアドレスのみを認識します。デフォルトは 0x02 です。最下位ビットはSMBusトランザクションのリード/ライト・ビットで、0でなければなりません。)」と何故か1バイトのうち、1ビット目だけ指定できないようになっている点に疑問を持たなかったのが敗因だが、よくよく考えてみれば不自然な範囲である。

上の図の8ビット目のところは、I2C通信プロトコル固有のビットでWirteなら0、Readなら1に使われる。CP2112のAPI仕様のI2Cアドレスは0x02〜0xFEまでしか指定できないのは、1ビット目が固有ビットになっているから空けておけという意味なのである。
上手く行かなくて悩んでいるとき、「空ける必要があるのであれば、0x45は空いてないから0x44にしないと行けないのかな?」と訳の分からない解釈をしてわざわざジャンパーを0x44に切り替えるために、カッターと半田作業をして余計なことをしていた。。。


以下に今回試したソースコードをアップしました。0x44 << 0x1としている点が味噌です。
https://github.com/zattu1/i2c

上記を動かすには、Qtフレームワークが必要なのと、CP2112のサンプルコードにあるSiliconLabs.rulesを/etc/udev/rules.d/に放り込むのと、CP2112のライブラリ群を/usr/local/lib/に放り込む必要がある。

以下はCP2112のSDK
https://jp.silabs.com/documents/public/software/USBXpressHostSDK-Linux.tar