いつも心は穏やかにと思っている私ですが……

この業界の基盤技術の核心! CPUってどんなもの?

»

 CPU、日本語に訳せば「中央処理装置」、頭のいい人は「頭がCPU」なんていわれる。コンピュータの心臓部といわれるだけに、ただなんとなくすごいことをしていると思っている人が多いだろう。

 ソフトウェア開発の仕事をしていたり、周辺機器のハードウェア設計をしている人もブラックボックスで分からなくてもいいや、と思っていませんか?

 IT業界で働くうえでは直接関係なくても、CPUはもっとも基本的な部分ですので、動作原理を知っておけば、パフォーマンスチューニング、サーバーの購入、設定のときに役立ちます。自分の作ったアプリケーションが、CPUという得体のしれないブラックボックスで動作するのは気味が悪いものです。

 システムエンジニアという仕事を長く続けていくためでも、「根本的なコンピュータシステムの理解」は、仕事に対する愛着という面で大きな支えになってくれるものです。それにしても書店の本とか大学の教科書とかはわけの分からない概念ブロック図が書いてあるものしかないですね。ハードウェアエンジニアは定年退職するまで、本なんて書く暇がないのでしょうか。まあ書いたところで印税はろくに入ってこないでしょう。一般受けするようなものではないのだし。

 デジタル回路では、「レジスタ」というところに数値が保存されています。またALU(Arithmetic Logic Unit)という回路は、加減算や論理演算を行うものです。従って、レジスタをALUの入力と出力に結線すれば、入力値が入っているレジスタの値をもとに、ALUの出力値がレジスタに入って計算が行われます。レジスタは複数のレジスタで構成されたレジスタファイルというものでできており、

 R3 = R1 + R2

のような加算は、3つのレジスタを使います。

 入力値のレジスタR1、R2をもとに加算された出力値は、レジスタR3に入ります。もちろん、加算の処理はALUで行われます。CPUの基本はたったこれだけです。簡単ですよね。しかしこれが皆さんの知っているCPUの動作周波数という性能値に大きな意味をもってくるのです。入力値のレジスタを読みだしてALUを通過し、出力値をレジスタに格納するまでの時間、これをサイクルタイムといいます。動作周波数は、サイクルタイムの逆数となります。もちろん、サイクルタイムは短ければ短いほど良く、動作周波数はその分高くなります。

 デジタル回路は、1と0しか意味を持たない電線の集合です。ALUやレジスタファイルを制御するのに、何本かの電線が出ています。それらの電線を1、もしくは0にするという組み合わせにより、いろいろなバリエーションのある処理ができるのです。つまり、サイクルタイム毎に何ビットかの1か0かの信号を送ればいいわけで、これを「命令」と呼んでます。

 「命令」が数値だけのマシン語である所以はここにあります。コンピュータのブートROMや制御用CPUのROMには、このマシン語が書かれています。ただし、数値の羅列だけでプログラミングするのは分かりにくいので、アセンブラというプログラムを作り、

 ADD r3, r1, r2

のようなアセンブラ言語を書けば、数値のみのマシン語に変換できます。アプリケーションで使われるような高級言語は、コンパイラによりアセンブラ言語に変換されます。

 昔はハードの性能が今ほどよくなかったので、高級言語でプログラミングしても、どうしても高速化したい部分はアセンブラで書いた、なんて話はよく聞きました。わたしが仕事を始めた時期は、コンパイラがかなり最適なアセンブラコードを出力してくれるので、そんな根気がいる仕事なんてしたことはありませんが……。

 せっかく算術演算ができるようになっても、レジスタに何らかの値を入れないと意味がないです。ROMやメモリから値を取ってくる必要があります。これが LOAD 命令です。逆に、メモリに値を書き込むのは STORE 命令と呼んでいます。何バイト分までCPUにメモリを接続できるかは、CPUからメモリに出るバス幅(つまり電線の数)で決まります。

 それでは、メモリ容量を超えた記憶域を使うにはどうするのか?

 仮想メモリとして知られるディスク領域にアクセスし、メモリとのデータ交換を行います。これがスワップイン、スワップアウトというものです。

 どうですか? 意外にCPUって単純なものでしょ。本文を読んで、少しでもコンピュータの処理が見えるようになっていただければ幸いです。

Comment(15)

コメント

神戸隆行

このコラム記事、小中学生にプロセッサの仕組みを教えてあげようってんじゃないですよね?

導入をとっつきやすくということで信号線やALUやレジスタから始めてもいいでしょうけど、せめてパイプライン処理や記憶階層(レジスタ-キャッシュ-メモリ-ファイルシステム)、可能ならばマルチコア(スレッドレベル並列)の話あたりまではしないと今時のソフトウェア作りの役に立たないのではないですか?

コラムでも述べられている通り、このコラムで説明されているレベルの事柄は、むしろ今時のコンパイラがよく最適化してくれているので殆どのソフトウェア製作者は配慮したくとも配慮のしようもないでしょう。(知ることは有用だとしても。)

一方、記憶階層とスレッド・レベル並列性はいまだにコンパイラが自動的に最適化しきれない分野ですからソフトウェアの設計・改良では避けて通れない要素だと思うのですが。

オススメ参考書:
コンピュータの構成と設計 - ハードウエアとソフトウエアのインタフェース 第3版 (上・下)、デイビッド・A. パターソン&ジョン・L. ヘネシー
ISBN-13: 978-4822282660

匿名

> ハードウェアエンジニアは定年退職するまで、本なんて書く暇がないのでしょうか。

多分、良い本を読んでいる感じも見つける努力もしている感じはしません。
友人のレポートをコピペして卒業されたパターンかな?
あなたの家の近くの本屋にはなくとも、世の中には良書が沢山ありますし、
日本語にも沢山翻訳されています。

この人、コンピュータ・アーキテクチャと言う言葉、
知っているのかしら?

匿名

この人は無能だよ。
他のコラムを読めばわかる。

sss

オススメ参考書にパタヘネをあげても無駄でしょ。パタヘネのうけうりなんだから。いまどき3レジスタのインストラクションなんて、アセンブラでの開発実務のないことを告白しているんじゃないの。

神戸隆行

受け売りですかね?だとしたらこのコラムの書き手はきちんと受け売れてないように思います。だからパタヘネをオススメしてみました。まぁそれにコラムの書き手には無駄でも検索エンジンでこの記事にたどり着いてしまう無垢な学生がいるかもしれないので。

ISA(インストラクション・セット・アーキテクチャ)はもはや現代ではコンピューター・アーキテクチャの中心的課題ではない(命令セットアーキテクチャ以外の最適化設計技術の比重が大きくなった&仮想マシンやバイナリ変換のような互換性向上技術もある)というのはまぁそうでしょうけど、それだけに3レジスタのインストラクションが特にマズいということもないような。

ちなみにMipsちっくなRISC命令セットは私の周囲では現役ですw(商用のアーキテクチャではないですが。)

みながわけんじ

神戸さん こんにちは

パターソン、ヘネシー懐かしいですね。私も若いころ読みました。
当時、MIPSはレジスタ32個だったと思います。英語の仕様書まで読みました。
MIPS社というものが存在しておりCPUを設計していました。その後MIPSはSGIに買収されましたが、プレーステーションに採用されましたよね。

ご指摘のとおり、パイプライン処理にはキャッッシュは必須ですね(命令フェッチとメモリアクセスをサイクルタイム以内に納めるために)

ふぉう

こんなとこで油売ってないで、オブジェクト指向云々のエントリをどうにかしたほうがいいんじゃないですか?

あと

>ご指摘のとおり、パイプライン処理にはキャッッシュは必須ですね(命令フェッチとメモリアクセスをサイクルタイム以内に納めるために)

神戸さんはこんな低次元な話をしてませんよ。
現在のCPUはいかなる構造になっていていかなる制御をしているため、ソフトウェア設計においてはこれこれこういう点に留意して設計すべし、くらいのレベルじゃないと役に立たないよって言われてるのがわかりませんか。
はっきり言って、このエントリが低レベルすぎて何の役にも立たないという指摘でしかないんですが。

どこに「基盤技術の核心」とやらがあるのか、教えていただけませんか。

#あと、貴方OSの機能とCPUの機能が切り分け出来てませんよね。

みながわけんじ

ふぉう様

>こんなとこで油売ってないで、オブジェクト指向云々のエントリ
>をどうにかしたほうがいいんじゃないですか?

他の記事で不適切な表現があったことをおわびします。
TLBはページテーブルの一部を連想記憶メモリにキャッシュしたものであり、mallocによる記憶領域確保とは関係ありません。

TLBに関しては mmap によるマッピングテーブルの一部をハード化したものであり、malloc と mmap の概念を取り違えてしまった私の過ちだと認めます。

http://ja.wikipedia.org/wiki/Mmap

ふぉう

なんでこっちに書きますかね・・・。
TLB云々はオブジェクト指向云々のエントリでコメントに書いたことですが。
書くべきところで書くべきことを書き込んで欲しいものです。

それと、ようやくしおらしげなことを書いたと思ったら

>TLBに関しては mmap によるマッピングテーブルの一部をハード化したものであり、malloc と mmap の概念を取り違えてしまった私の過ちだと認めます。

これはないでしょ、これは・・・。
構造体とインスタンスの理解がなってなかったことといい、Cの仕事をしてたと言いますが、Cもまともに書けませんって告白してるようにしか見えないです。

見苦しいです。
こんなレベルでいっぱしのエンジニア面をしないでいただきたい。

みながわけんじ

>構造体とインスタンスの理解がなってなかったことといい

はっ、それを言うなら「構造体とクラスの違いの理解」ではないですか?

構造体はC言語の時代からあるものですよ。
構造体は値型、クラスは参照型です。

do

元々の文脈がメモリアロケーションと絡んでいるので、「構造体とインスタンスの理解」についての言及で正しいでしょうね。

ちなみに「構造体とクラスの違いの理解」ですが、言語によって異なります。
>構造体は値型、クラスは参照型です。
これはC#の話ですね。ではC++では?

ふぉう

>はっ、それを言うなら「構造体とクラスの違いの理解」ではないですか?

いやいやいやいや、「構造体とインスタンスの理解」で間違ってません。
構造体が引き合いに出されたのは、みながわさんがCの経験者だというからインスタンスを理解するのに一番分かりやすいだろうという配慮かと思われます。
実際は、構造体のインスタンス化について何も分かってなかったことが暴露されただけでしたが・・・。

>構造体はC言語の時代からあるものですよ。
>構造体は値型、クラスは参照型です。

C言語においても「構造体は値型」という主張として受け取っていいですか?

神戸隆行

> ご指摘のとおり、パイプライン処理にはキャッッシュは必須ですね
>(命令フェッチとメモリアクセスをサイクルタイム以内に納めるために)

そんな指摘はしてませんが…。
ソフトウェアのエンジニアにとっても記憶階層(キャッシュ/仮想記憶)やパイプラインの理解なら直接的に役立つがALUとレジスタの話をしてもおそらく直接には役に立たない(優先度が低い)という話はしました。

ちなみに記憶階層とパイプラインでは記憶階層の方がソフトウェア作成にとっては優先度が高いでしょう。理由はコンパイラによる自動最適化の能力は後者についての方が高いからです。
(コンパイラが後者を比較的最適化しやすい理由はパイプライン化のための命令間の依存関係の解析は局所的で、複数の手続き/関数/メソッドにわたる大域的な解析を必要としないためです。)

さらに言えばパイプラインとキャッシュはそれぞれ独立の効果を持つアーキテクチャ上の工夫です。

命令のパイプライン処理はプログラム内の複数の命令の間にある並列性(命令レベル並列性)を利用し、命令の実行の各ステップをズラして並列実行することで1クロックあたりの命令の実行数(IPC)を高める仕組みです。

一方キャッシュ・メモリはプログラムについて知られている経験的な性質(参照局所性)を利用して利用頻度の高いデータを高速だけれど小容量なメモリに蓄えておくことでメモリ参照を透過的に高速にする仕組みです。

(注: 透過的とはその存在を意識しなくてもとりあえず動作するということです。キャッシュは透過的な仕組みなので意識しなくてもとりあえず動きますが、意識してプログラムの参照局所性を高める設計にすればよりその恩恵を受けることができます。透過的でない例としては、昨今のGPUなどに見られるように意図的にプログラムすることが必要な透過的でない階層的なメモリ構成を利用してもメモリアクセスを高速化することができます。)

現代のプロセッサは両者とも採用していることが多く、またキャッシュにはみながわ氏の指摘にもあるようにパイプラインを止める時間を減らす効果が期待できるとはいえ、パイプラインにキャッシュが必須なわけではありません。

神戸隆行

> 構造体は値型、クラスは参照型です。

それはC#でのclass/structキーワードの使い分けがそうだというだけで、オブジェクト指向言語について一般的というわけではありません。

実際C++ではクラスは構造体ともども参照型ではありません。
そして、ポインタ型と似たように直交的な型構成子である参照型を利用して変数や関数引数について参照型であるstruct/classを利用することができます。
(型構成子とは他の型を引数にとって新たな型を構成する仕組みを表す概念です。
配列型、ポインタ型、参照型、関数型、総称型などが典型的です。特に総称型はユーザが独自の型構成子を定義できる仕組みでもあります。)
C++ではメンバの隠蔽性(public/private)のデフォルトという違いを除いてstruct/classは互換です。

C#はC/C++とJavaを折衷したような言語です。その上で:
・C/C++のようなソースレベルの互換性を放棄しているためstruct/classの互換性というC++が持つキーワードの冗長さを維持する必要がないこと
・Javaの観察から多くのアプリケーションでクラス標準的な割り付け/参照方法を参照型にして支障がないこと
・しかしJavaと異なりシステム的なプログラミングの能力を保持するためCの構造体のようなオブジェクトの並び順とオフセットを明示できる仕組みは残したかったこと
以上からstruct/classで割り付け/参照方法の使い分けをして両方の仕組みを残すという方針に至ったのでしょう。C++のように値型を標準にして参照型を導入するというのとは違う、参照型を標準にして例外的な値型を導入する道を取ったということです。

このように元来値/参照の概念と構造体・クラスの概念は次元が異なるものです。C++、Java、C#のクラスはCの構造体をベースに考えられています。

ふぉう

繰り返し聞きます。

>構造体はC言語の時代からあるものですよ。
>構造体は値型、クラスは参照型です。

この発言は、C言語においても「構造体は値型」という主張として受け取れますが、それでよろしいんですね?
Yes/Noで答えてください。

コメントを投稿する