せっかちな人々(まったりも可)

どんなささいなことでも構いません.
面白い最適化のアイデアがありましたら書き込んで下さい.
無論雑談も大歓迎です.


 
名前
 
タイトル
 
e-mail
 
URL
 
パスワード
 
cookie
有効期限:10 日
メッセージ



  次へ  ← 355-301 / 323 件表示 →  前へ
件/頁   
 



355. ProcessorPackについて おさるさん  2000/11/27 (月) 06:54
はじめまして。
いつも、勉強(ROM)させてもらっているおさるさんといいます。

質問なのですが、ProcessorPackを落として
実行したのはいいんですが、インラインアセンブラで
SSEが使えません(T・T)
私は英語は苦手なのでよくわからないのですが
もしご存知の方がいらっしゃったら教えていただけませんか?

ちなみに環境はWindows2000 VC++ SP4です。

申し訳ないんですがよろしくお願いします。




354. お世話になりました べっち  2000/11/26 (日) 08:20
へるみさん、お世話になります。

>すいません下の説明でfunc()の定義が抜けてましたね。m(__)m

全然、いいですよ。お気になさらないでください ^v^
そのへんは僕がどうにかしなければならない部分だと思ってます。

>そうしたら、構造体のメンバのサイズが違うときに、`隙間'を
>うまく作らなかったら、構造体の配列を扱うときに困ることが
>想像できると思います。

もう大丈夫です。お陰さまで、しっかり理解できました。^v^
へるみさんにはご迷惑ばかりお掛けして本当に申し訳ありません
でした。
1日でも早く正しい知識を付けられる様頑張りたいと思います。
本当にありがとうございました。




353. お世話になりました。 べっち  2000/11/26 (日) 08:04
長船さん、お世話になります。

>無駄に専門用語に縛られている気がしますね

多分、情報処理試験の1,2種を受けた頃からだと思います・・
あんなもの受けるんじゃなかったです。

>専門用語を間違った意味で使われると、こちらも混乱します。

すいません。教わっている身でありながら、
教えてくださっている長船さんやへるみさんにご迷惑ばかり
お掛けしていたのですね・・
でも、1つ僕にとっては良かったことがあります。
もし、今回長船さんとへるみさんに僕の間違った知識の部分を
聞いていただけなかったら(見つけていただけなかったら)
多分、今後もずっと間違った知識と考え方で過ごしてしまって
いたと思います。
長船さんやへるみさんのように正しい知識を持たれておられる方
に今回聞いていただけたということがとても良かったと思います。
もちろん、長船さんやへるみさんにはいい迷惑でしょうけど ^^;

>その作業をどんな方式で行うかなど
>ユーザーが知る必要はありませんし、知る術もありません。

はい、分かりました。

>ソース上で書いた変数が実際にはどのSDRAMのどのセルに
>格納されているのかなど、プログラマが知るべき問題では
>ないです。

はい、分かりました。

>現在のパソコンのアーキテクチャを
>知るためには、古いパソコンでの概念も知る必要があります。

きちんとした知識を得るためにも是非古いものの概念から
しっかりと勉強し直したいと思います。
長船さんには本当、何から何までお世話になりました。
本当にありがとうございました。




352. alignment へるみ  2000/11/25 (土) 19:50
すいません下の説明でfunc()の定義が抜けてましたね。m(__)m
自分でなんでもいいから作れば良いのですが、例えば
void func(double *p, int n){
int i;
for(i=0;i<n;i++) p[i]++;
}

>「alignmentが崩れる」ということが起きるのですね。
>内部で何が行われているのかまでは分かりませんが、

崩れてると例えばdoubleだと8の倍数のアドレスのところで2回に分けて読みこむので遅くなるというイメージです。

0123456701234567 <= アドレス & 7
*|<p[0]>||<p[1]>|..... <= double変数が置かれた場所
<======><======> <= 下位層で読み出すパターン
まず0...7まで読んで0番目を捨てる。次の0から7まで読んで1...7番目を捨てる。
最初の1...7番目と今の0番目をくっつけてp[0]とする。以下同様。
#あくまでイメージです。実際にプログラマはこんなこと感知できません。
#それから実際には長船さんがかかれたように階層がいっぱいあって私は良く知りません。

>変数がレジスタサイズの倍数のアドレスにあわせて配置されている
>ということの意味が分かった気がします。

そうしたら、構造体のメンバのサイズが違うときに、`隙間'をうまく作らなかったら
構造体の配列を扱うときに困ることが想像できると思います。




351. 用語 長船 [URL]  2000/11/25 (土) 19:40
無駄に専門用語に縛られている気がしますね>べっちさん
名称なんてただの符号にすぎません。名称と機能とは別の
ものです。まずは専門用語をすっぱり忘れてください。
専門用語を間違った意味で使われると、こちらも混乱します。

> ・データやコードはメモリから32バイトずつノースブリッジの
> バッファ?(チャネルのような方式でしょうか?)に読み込まれ…

Pentiumはデータを読み込むときには、要求するデータサイズに
関わらず32バイト(64ビット幅で4回分)を内部のキャッシュに
いったん読み込み、そこから必要なレジスタに転送します。
要求するデータがPentium内部のキャッシュにあれば、32バイトの
読み込みサイクルは行われません。

ノースブリッジがどのような作業を行うかはチップメーカに
よってまちまちです。その作業をどんな方式で行うかなど
ユーザーが知る必要はありませんし、知る術もありません。

また、Pentiumなどのx86アーキテクチャのパソコンは拡張に
拡張を重ねたものなので、現在のパソコンのアーキテクチャを
知るためには、古いパソコンでの概念も知る必要があります。

> 今までハード側から1個ずつ見ていった場合とソフト側から1個
> ずつ見ていった場合とでは全然噛み合わなかったのですが、

SDRAMのデータアクセスからC++の変数のアクセスまでは
相当の隔たりがあるので当然です。
ソース上で書いた変数が実際にはどのSDRAMのどのセルに格納
されているのかなど、プログラマが知るべき問題ではないです。




350. 報告です。 べっち  2000/11/25 (土) 17:57
へるみさん、お世話になります。

>ひとまず今の話には関係無いので忘れたほうが混乱せずに
>すむと思います。

すいません。もっと勉強しないといけませんね ^^;
(古い環境を手に入れてものにしたいと思います。)
で、今はへるみさんのご教授通り忘れておきます。


>関数

へるみさんが意図した僕に伝えたいことをひょっとしたら、僕は
間違った解釈をしてしまったかもしれませんが、

>p=(double *)( (((int)buf + 7) & ~7) + 1 );

まず、(int)buf + 7) & ~7は確保された領域内を使うために
double型に合わせて8バイトの倍数のアドレスを指すように
しているのですよね?
そこから1バイトずれた位置からdouble型(8バイト)分に
無理やり何かしらの操作を行おうとしている、ということですね。
この時、へるみさんがおっしゃられていた「alignmentが崩れる」
ということが起きるのですね。
内部で何が行われているのかまでは分かりませんが、
実行時間の違いから、基本型にもalignmentがあることを
確認できたと思います。

へるみさんが僕に伝えたかったのはこういうことだったのですね。
変数がレジスタサイズの倍数のアドレスにあわせて配置されている
ということの意味が分かった気がします。

こういうことで大丈夫でしょうか?




348. Re:フラットモデル へるみ  2000/11/25 (土) 08:56
>ラージは86エミュレーション用に設計されたOS用のもので
違いますって(^^;
x86CPUはアドレス指定に汎用レジスタとセグメントレジスタという2つのレジスタを併用出来ます。
セグメントレジスタの指定は省略できます。
あるアプリケーションの中でcodeやdataが全て同じレジスタでアクセス出来るときそのアプリケーションは
small(あるいはflat)といいます。この場合普通はセグメントレジスタの指定を省略します。
16bitモードなら1セグメント64kbyte, 32bitモードなら1セグメント4GBまで扱えます。
16bitモードのときはそれだけでは足りないことが多かったのでコードの中で複数のセグメントを扱い、
より大きな空間にアクセスする方法が取られました。
やりかたの違いによって(compact, medium, larg)と呼ばれたのです。

>その為、特殊なものを勝手に省いてしまいました。
勝手に省いたというよりはメモリモデルの意味をそもそも理解されていないような気がします。
ひとまず今の話には関係無いので忘れたほうが混乱せずにすむと思います。

>へるみさんがおっしゃられているものはひょっとして、僕の
>言っている構造体へのことではなくて、
いきなり構造体ではなく先に基本的な型に対して理解したほうがよいと思ったからです。
それからある言葉を理解しようとするときに自分の知らない言葉を使うのはあまり意味が無いです。

>あと、alignmentなのですが、やっぱりよく分かりません。
次の関数の実行時間は1回目と2回目で差が出ます。何故出るのかもう一度考えてください。
またdoubleをintやshortに変えるなどいろいろ試してください。
#define NUM (1024*10000)
#define COUNT 100
int main(){
int i;
char *buf;
double *p;
buf = calloc(NUM*sizeof(double)+16, 1);
if(!buf) return 0;
puts("1回目");
p=(double *)( ((int)buf + 7) & ~7 );
printf("adr=%p\n", p);
for(i=0;i<COUNT;i++){
func(p, NUM);
}

puts("2回目");
p=(double *)( (((int)buf + 7) & ~7) + 1 );
printf("adr=%p\n", p);
for(i=0;i<COUNT;i++){
func(p, NUM);
}
return 0;
}




345. 一息ついて・・ べっち  2000/11/25 (土) 02:39
1度睡眠をとって、一息ついて、今まで長船さんとへるみさんに
ご教授いただいたことを1つ1つ整理してみました。
僕の今まで勘違いしていた部分 と 教わって気が付いた部分です。
勘違いしていた部分
・キャッシュの存在、物理的なデータの読み込み方を軽視しすぎて
 いたらしく、データの処理毎に、変数が1つずつメモリから
 読み出されてきているイメージで、自分でも知らぬ間に全てに
 おいて論理的な考えを適用してしまっていたのだと思います。
気が付いた部分
・データやコードはメモリから32バイトずつノースブリッジの
 バッファ?(チャネルのような方式でしょうか?)に読み込まれ
 (ここで変換(物理アドレスをPentiumバスという論理アドレス
  に変換)を行う。(メモリコントローラの仕事でしょうか?))
 で、バッファ?からCPUに8バイト単位で読み込まれていく・・
 といった感じでしょうか?
 ひょっとしたら回路的に時間の差分を埋めながら(変換もして)
 CPUに8バイトずつ渡していくのでしょうか?
 (この辺はまだよく分かりません ^^;)
・まあどちらにせよ、そこで起こる時間の差分をBIOSで
 ノースブリッジ内のメモリコントローラに設定するということ
 だと思います。
・で、ほとんどの場合(小さなプログラムやデータの局所化が
 上手くいっている場合)キャッシュが活躍しているということ
 だと思います。

今までハード側から1個ずつ見ていった場合とソフト側から1個
ずつ見ていった場合とでは全然噛み合わなかったのですが、
長船さんとへるみさんのご指導のお陰で整理がついてきました。
幾つか質問が混じっていますが、多分これらが理解できれば・・
多分、あと少しだと思います。あと少しで・・

あと不思議なのはへるみさんのおっしゃられている「alignment」
が、どのレベルでのことを指しているのかよく分かりませんです^^;




344. メモリモデル へるみ  2000/11/25 (土) 01:13
>Windows98などの32ビット環境ですと、
>フラットアドレッシングを使用しています。
>16ビット環境と異なり、1つしかメモリモデルが
>存在しません。intは32ビットです。

う〜む。やはりC言語の規格とx86CPU特有の状況がまざってる(^^;
1つしかメモリモデルがないわけじゃないです。
32bit環境でもセグメントレジスタを使ってメモリアクセスをする環境もあり得ます。
#そこではポインタ変数が32bit汎用レジスタ+16bitセレクタ=48bitの環境。
フラットモデル(多分smallモデルともいう)とは恐らくセグメントレジスタを使わない
環境のことでしょう。

>メモリを仮想化するため、プログラムからは4Gバイトのメモリ空間として使用することが
できます。
別にメモリを仮想化しなくても32bitモードでなら4GBアクセスできます。

ただこの話は今のべっちさんの質問には関係無いと思います。





343. alignment へるみ  2000/11/25 (土) 01:12
alignmentと#pragma packとは全く別の概念です。

メモリに配置されたデータAを汎用/MMX/FPU/SSEなどのレジスタで読みこむとします。
そのレジスタサイズ(4, 8, 16)に応じてAのアドレスが(4, 8, 16)の倍数でないとき
ペナルティによる実行時間の低下や保護例外が起こります。
それを回避するためにあらかじめデータAのアドレスをレジスタのサイズの倍数の
アドレスにあわせて配置すること、これがalignmentです。
VC++はdouble, float/int, short, charそれぞれに応じて8, 4, 2, 1byteのalignmentを
考慮してデータの配置を行ってくれます。

cool構造体を何も考えずにつめて配置する(sizeof(cool)=6)とせっかくcool型変数を
alignmentして配置してもそのメンバcへアクセスするときalignmentがくずれます。
これが嫌なのでVC++が勝手に間につめものをおいてsizeof(cool)=8の状態で並べます。
intのサイズが増えるわけじゃないです。intへのアクセスは常に4byte(x86-32bit系ならね)

普通プログラムを組むときは実際にsizeof(cool)が何byteであるかを意識しないで済むコードを書かないといけない。(最上位?)

で、メンバcにアクセスしたときその中身がキャッシュにあれば、そこから読まれる。
なければそのデータがある場所のメモリを読みこむ。
出来るだけキャッシュを有効活用するようにコードを書くことはある。(真ん中)
そのときバスから読まれるのは64bitごと。
バスからどう読まれてるか意識してコードを書くことは無い(と思う)。(最下位)




342. 論理的と物理的 長船 [URL]  2000/11/24 (金) 23:48
明確な線引きはありません。
基本的にレイヤ自身は上位階層に何があるのか知る術は
ありません。ですから、レイヤ自身で完結するものが
「論理的」なものであり、それ下位のレイヤが「物理的」と
私は区別しています。

チップセットはSDRAMの物理アドレスをPentiumバスという
論理アドレスに変換し、CPUはそのバスをメモリアドレスに
変換し、OSのメモリマネージャはそのメモリアドレスを
アプリケーション毎にフラットな論理アドレスに変換して
アプリケーションに提供します。

このようにたくさんの階層で論理⇔物理変換が行われているからSDRAMへの書き込み方法を知らなくても、アプリケーションを
作ることができるわけです。




341. やっと気付きました。 べっち  2000/11/24 (金) 18:44
へるみさんのおっしゃられている理由がやっと理解できました。

>>32ビット環境だからintが4バイトらしい

>CPUが何bitのレジスタを持っているかはC言語のintのサイズには関>係無いです。

コンパイラによって決まる、ということですね。
焦っていて全然気付きませんでした。
あ〜、どうしたんでしょう・・
頭の中ぐちゃぐちゃで冷静さが微塵もなさそうです ^^;




340. 直すのをまた忘れてました ^^; べっち  2000/11/24 (金) 18:27
今、気付きました。

>>char a[10] = {初期化};
>>int *p = a+2;
>int *p = (int *)(a + 2);と書いた方が良いと思います。

int *pではなくて、char *pでした。
へるみさん申し訳ありませんでした ^^;




339. う〜ん・・・ べっち  2000/11/24 (金) 18:06
長船さん、お返事ありがとうございます。

>どうも複数のレイヤがごっちゃになってる気がします。

すいません。そうだと思います。
(へるみさんや皆さん分かり辛くなってしまって本当にすみません)
今回、曖昧だったこのへんの仕組みをはっきり理解したいために
質問させていただいております。
お手数を掛けますが皆さん宜しくお願いします。


>バス幅やデータの転送順のどうこうというのは
>種類によって全く異なります。

>物理的にどんな並び方で格納されて、どの順で
>アクセスされるのかは、コンパイラの解釈で異なります。

どうやら、僕はこのあたりが良く分かっていないみたいです。
何処までが論理的で何処からが物理的なのかという事です。
sizeofや#pragmaディレクティブなどで指定していることは
どの位の位置で考えれば良いのでしょうか?
何を基準に行っているのか正直良く分かりません。

完全に切り離されたものとして考えて、物理的な部分というのは
考慮する必要がないのでしょうか?
頭の中が上手くまとまりません ^^;(境界線がよく分からない・・)




338. ありがとうございます! べっち  2000/11/24 (金) 17:30
へるみさん、お返事ありがとうございます。

>Pentium系CPUは32byteずつメモリから読み込んで
>キャッシュに入れていたと思います。
>その32byteを読むのにPentiumだと8byteずつ読み出すと
>いうことです。
>doubleも1回で読み込みます。
>一度読み込むと次その付近を読み込む時はキャッシュから
>読みます。
>メモリコピーを32bitレジスタでなくFPUレジスタを
>使うことで高速化する余地があるのはそのためです。

>ただこれはメモリがalignmentされている場合です。
>そうでない場合はアドレスが4の倍数になる部分で
>分けて読みます。

上記のへるみさんからのご教授いただいた部分が
僕の知りたい部分にかなり近いです!(一緒かも!?)
へるみさん、すごいです! でも・・
大変興味深くはあるのですが、ちょっと微妙な部分もあります。
このalignmentなんですが、#pragma packとは違いますよね?
もし、一緒だとしたら、それはそれで質問の方向が、ちょっと
変わっちゃうかもしれません。




337. 解釈 長船  2000/11/24 (金) 17:14
どうも複数のレイヤがごっちゃになってる気がします。

まず、C言語はOSフリー・CPUフリーな「プログラム言語」です。
intが4バイトというのは、Pentiumで動かしているWindows上で
たまたまそうなっているだけです。

で、アプリケーションの下にはOSがあります。UNIXやWindows
などのマルチタスクOSでは、メモリアドレスの動的な変換が
行われているため、論理的なアドレスと物理的なアドレスとが
一致している保証はありません。

そのOSやアプリケーションを実行しているのがCPUです。
PentiumなどのCPUにはキャッシュが内蔵されているため、一度に
数十バイトのデータをチップセットとやり取りします。

CPUの下にチップセットがあり、このチップセットが実際に
PCIバスやSDRAMとデータをやり取りしています。

なので、バス幅やデータの転送順のどうこうというのは
種類によって全く異なります。

で一番上に戻って、C言語というのは、これらすべての事柄を
何も考えなくてもいいように、つまり完全に論理レベルで
プログラムが組めるような仕様になっています。

ですから

struct cool {
char a;
char b;
int c;
};

というソースが、物理的にどんな並び方で格納されて、どの順で
アクセスされるのかは、コンパイラの解釈で異なります。




336. へるみさんへ 2 べっち  2000/11/24 (金) 17:05
>フラットモデル

メモリモデルのことです。
DOS や Windows3.1などの16ビット環境ですと、
セグメント化アドレッシングを使用しています。
intは16ビットです。
メモリの構成の仕方がセグメント分割アーキテクチャ?とやら
の関係で複数のメモリモデルが存在し、各モデルでデータや
コード、スタックの空間の最適化ないし、コンパイル方法が
異なります。
Windows98などの32ビット環境ですと、
フラットアドレッシングを使用しています。
16ビット環境と異なり、1つしかメモリモデルが
存在しません。intは32ビットです。
メモリを単純な繋がりとして扱い、メモリを仮想化するため、
プログラムからは4Gバイトのメモリ空間として使用することが
できます。



>そもそもchar型の配列が4byte alignmentされてる保証は
>無いですが・・

alignmentって、プリプロセッサディレクティブではなくて?
僕が言っているのは、#pragma packとは全く無縁です。





335. へるみさんへ べっち  2000/11/24 (金) 16:19
>>32ビット環境だからintが4バイトらしい

>CPUが何bitのレジスタを持っているかはC言語のintの
>サイズには関係無いです。

???
intのサイズは16ビット環境では2バイトです。
     32ビット環境では4バイトです。
?ごめんなさい。へるみさんが僕の文章をどういう風に解釈
されたのか、よく分かりません ^^;
_____________________________________________________

>そんな、データがどこにあるかどうかでintの大きさが
>変わったら恐いです(^^;

>printf("sizeof(int)=%d\n", sizeof(int)); で見えます。

う〜ん、そういう意味ではないんですが・・。
(僕の文章って分かり辛いですよね ^^; すみません ^^;;)
例えば、
struct cool {
char a;
char b;
int c;
};
とあった場合、sizeof(cool)とするとサイズは 8 ですよね。
この時、
|-|-|-|-|-|-|-|-|
|c|c|---| int |
こうなっていますよね?
これを #pragma pack(1) でアラインすると
|-|-|-|-|-|-|-|-|
|c|c| int |---|
となり、サイズは 6 になります。
(このときのアクセス方法を言っていたつもりなのですが・・)
ここで気を付けて見ていただきたいのは、どちらの場合でも
構造体cool には 8 バイトの領域が用意されているということ
です。1度のアクセスが4バイトなら・・ということです。
伝わっていないでしょうか? ^^;

int x; //アドレス:0x006BFDF4 サイズ:4
cool y; //アドレス:0x006BFDEC サイズ:8

//#pragma pack(1)
int x; //アドレス:0x006BFDF4 サイズ:4
cool y; //アドレス:0x006BFDEC サイズ:6




332. Re: フラットモデルだから? へるみ  2000/11/24 (金) 14:55
>やはり、フラットモデルだからCPUとは関係なく、
>バスを流れるデータは4バイト単位なのでしょうか?

フラットモデルが何を指すのか良く分からないのですが、
データバスが64bitだったら常に64bitずつデータをやりとりします。

>char a[10] = {初期化};
>int *p = a+2;
int *p = (int *)(a + 2);と書いた方が良いと思います。

>パターンAのように取り出されてくるのでしょうか?
>それとも、
>パターンBのように取り出されてくるのでしょうか?

そもそもchar型の配列が4byte alignmentされてる保証は無いですが、
そうだとすると、p[i]の形でアクセスすると毎回ペナルティが発生します。
ただそこにバスがどうからんでいるのか、いまいち質問の意味が
組みとれませんm(__)m

#う〜ん、長船さんヘルプー(^^;




331. Re: アクセス時に読み込む実際のデータ幅 へるみ  2000/11/24 (金) 14:32
CPUの設計と、C言語の規格と、内部の実装とがごちゃごちゃになっていませんか?

>32ビット環境だからintが4バイトらしい

CPUが何bitのレジスタを持っているかはC言語のintのサイズには関係無いです。
#私はC++を知らないのですがintは4byteって決まってるのでしょうか。

>この4バイト境界を跨いでデータが存在する場合に
>本当にそうなのか真実は分からない

そんな、データがどこにあるかどうかでintの大きさが変わったら恐いです(^^;

>自分の目で見たわけではないので・・

printf("sizeof(int)=%d\n", sizeof(int)); で見えます。

Pentium系CPUは32byteずつメモリから読み込んでキャッシュに入れていたと思います。
その32byteを読むのにPentiumだと8byteずつ読み出すということです。
doubleも1回で読み込みます。
一度読み込むと次その付近を読み込む時はキャッシュから読みます。
メモリコピーを32bitレジスタでなくFPUレジスタを使うことで高速化する余地があるのはそのためです。

ただこれはメモリがalignmentされている場合です。
そうでない場合はアドレスが4の倍数になる部分で分けて読みます。




330. Pentium 長船  2000/11/24 (金) 09:36
Pentiumプロセッサ技術情報

http://www.intel.co.jp/jp/developer/design/intarch/pentium/pentium.htm




329. フラットモデルだから? べっち  2000/11/24 (金) 03:29
やはり、フラットモデルだからCPUとは関係なく、バスを
流れるデータは4バイト単位なのでしょうか?
ひょっとしたら勘違いなことばかり言っているかもしれませんが
宜しくお願いします。


(ちなみに下で言っているポインタの話は下記のような感じです)
(入力文字数の制限がきてしまいましてので・・)

char a[10] = {初期化};
int *p = a+2;
と宣言し、計算式などで *p を使用するときデータバスを流れる
4バイトは(1 を1バイトとして見てください。)

パターンA: @1111@ 1111 1111 //配列の先頭から4バイト
パターンB: 11@11 11@11 1111 //ポインタ位置から4バイト
#@で括ったとこがバス幅だと思ってください。

パターンAのように取り出されてくるのでしょうか?それとも、
パターンBのように取り出されてくるのでしょうか?




328. DJ☆Uchiさんへ べっち  2000/11/24 (金) 03:04
DJ☆Uchiさん、ごめんなさい
ネームを間違えていました。




327. アクセス時に読み込む実際のデータ幅 べっち  2000/11/24 (金) 02:52
長船さん、DJU☆chiさん
CPUって思っていた以上に複雑なのですね ^^;
(かなり混乱中です ^^; 僕ってバカなのかも・・)
ちょっと、ペンティアムについて不思議なことがあるのですが、

1つは、
CPUが32ビットだから、OSもそれ用に設計され32ビット対応
だし、プログラム記述時のメモリ構成もフラットモデルでって
ことですよね?
僕は主に言語はC++を使っているのですが、32ビット環境だから
intが4バイトらしいんですけど、構造体とかでアラインメントを
考えるとき、この4バイト境界を跨いでデータが存在する場合に
本当にそうなのか真実は分からないのですが、
(自分の目で見たわけではないので・・)
「2回アクセス」して読み込むらしいのです。
(doubleも2回アクセスして読み込んでいるのものだと、僕は
(思っているのですが、違うのでしょうか?
(他にもポインタの場合、ポインタが指すアドレス位置から
(4バイトなのか、始めから(スタック領域の先頭から)
(4バイト単位に区切られていて該当する場所(4バイト)が
(読み込まれれているのか、どちらなのかもよく分かりません)
ペンティアムのデータバスの幅が64ビットもあるのに、本当に
2回もアクセスしているのでしょうか?
いままではデータバスが32ビットだと思ってやってきたので
それほど不思議ではなかったのですが・・
_________________________________________________

もうひとつは、
変数を読み込む時メモリから読み込まれてくるデータの幅が
どうなっているのか、分からなくなってきました。
char型の場合、型としては1バイトですが、(複数の変数を宣言
した時、確かめたのですが)char型であろうが1つの変数に対し
4バイト単位の領域がパディングされてなのか、フラグメン
テーションなのかは、分かりませんが与えられている
(用意されている)ことは知っています。
これは、僕はデータバス幅が32ビットだからだと思っていた
のですが、これが64ビットである場合、メモリからデータを
読み込むとき4バイトではなく、一体何バイトになっている
のでしょうか?
_________________________________________________

一生懸命書籍を立ち読みして探してはみたのですが、こんな
曖昧な部分は載ってませんでした。
こんなにいくつもお聞きしてばかりの自分の無力さに歯痒い
ばかりです・・
今以上に一生懸命がんばって勉強しますので、教えてください
どうか、どうか宜しくお願いします。




326. そいや Hash  2000/11/24 (金) 02:07
6809上位互換の6309って32ビットレジスタ持ってたしね(^^;




325. Re: ビット へるみ  2000/11/24 (金) 00:43
>8ビット及び16ビットCPUと呼ばれている物の中には、そのビット数以上の
>レジスタ幅を持つ物も少なくありません。

逆に386SXは32bitCPUと呼ばれていたのに外部16bitバスでしたよね。
x68000ユーザからよくいじめられていた気がする(^^;




324. 昔話 小次郎  2000/11/23 (木) 23:54
>最近の32ビット以上なCPU(x86系)は大体その認識で良いみたいですが、
>8ビット及び16ビットCPUと呼ばれている物の中には、そのビット数以上の
>レジスタ幅を持つ物も少なくありません。
>(販売数量的にはこちら↑の方が上かも?)

 Z80から8086に移ったときに「アレ?ぜんぜんレジスタ周りで楽にならないジャン」と
思ったのを思い出しました(笑)

#Pentium4のPDFを読んでいる暇がほしいッス…




323. 日立のCPU 長船  2000/11/23 (木) 23:45
日立はRレジスタのビット幅=○ビットCPUと言うみたい
なので、H8/300Hシリーズは16ビットで良いような (^^;




322. ビット DJ☆Uchi [URL]  2000/11/23 (木) 21:53
>>バス幅とは関係ありません。
>初めて知りました。そういう決め方だったのですね。

最近の32ビット以上なCPU(x86系)は大体その認識で良いみたいですが、
8ビット及び16ビットCPUと呼ばれている物の中には、そのビット数以上の
レジスタ幅を持つ物も少なくありません。
(販売数量的にはこちら↑の方が上かも?)

例えばH8/300HというCPUでは、汎用レジスタ長32ビット
アドレスバス24ビットであるにも関わらず、
外部バス幅が最大16ビットである事から
16ビットCPUであると日立は言っています。
個人的な意見としては、それでもなお誇張気味だと思う・・・(^^;

混乱させてしまうようで申し訳ないのですが、CPUのビット数呼称を
一概に決定づけられるようなファクターというのは在りませんし、
仮に無理矢理○○ビットCPUと呼んでみたところで、それは何の意味も
持ちませんから、あまり気にしなくても良いと思います。




321. お世話になりました。 べっち  2000/11/22 (水) 23:42
長船さん、とても分かり易く丁寧に教えてくださって
本当にありがとうございました。

>バス幅とは関係ありません。

初めて知りました。そういう決め方だったのですね。
とても勉強になりました。

本当にお世話になりました。それでは失礼します。




320. SDRAM 長船  2000/11/22 (水) 22:43
> 「〜ビット機」って、何を基準にしているのでしょうか?

一般にはCPUの内部でメインとなるレジスタのビット幅で
表します。バス幅とは関係ありません。
Pentiumには32ビットの汎用レジスタと80ビットのFPUレジスタ
64ビットのMMXレジスタがありますが、IA32アーキテクチャが
メインとなっているので、32ビットCPUに分類されます。

> この1区画は、普通、何ビット(バイト)単位で分けられている
> ものなのでしょうか?

種類によって違います。ご自分で検索して下さい。

日立のページ
http://www.hitachi.co.jp/Sicd/Japanese/Products/memory.htm

NECのページ
http://www.ic.nec.co.jp/memory/index.html

SAMSUNGのページ
http://www.intl.samsungsemi.com/Memory/DRAM/datasheets.htm

ISSIのページ
http://www.issi.com/dram.html#C




319. Re: 20日のコード へるみ  2000/11/22 (水) 18:13
言葉足らずですんません。m(__)m
doubleでもはみでたんです。




318. 20日のコード dsk [URL]  2000/11/22 (水) 17:20
本題とは異なるかもしらないが、
float func2( float a, float* buf, int n ) {
double x = 1e0;
int i;
for( i = 0; i < n; ++i ) x *= buf[i];
return pow( x, a );
}
は駄目なの?
float->double変換は powの呼び出しの1/8よりは速そうだけど....




317. ありがとうございます! べっち  2000/11/22 (水) 12:46
長船さん、ありがとうございます!
とてもよく分かりました!!
(バスサイクルって、コマンド発行してデータを受け取る1回の)
(やり取りで渡したり受け取ったりできるデータ量の単位かと)
(思ってました ^^;)


>Pentiumのバス幅は64ビットです。

ペンティアムのバス幅が64ビットなんですね ^^;
ちょっと、よく分からなくなってきたんですけど、
これってデータバスだけでってことですよね?
今のパソコンは32ビット機ではない?のですか?
「〜ビット機」って、何を基準にしているのでしょうか?


>4つの区画に分けて、それぞれを別々にアクセスできるように
>して高速化を図っています。この区画の事をバンクと呼びます。

なるほど、普通「バンク」と呼ばれるものはインタリーブの
1ブロックのことを指していたのですね。理解しました。
この1区画は、普通、何ビット(バイト)単位で分けられている
ものなのでしょうか?


またまた質問だらけで申し訳ありません ^^;;




316. ハードウェア 長船  2000/11/22 (水) 04:21
ハードウェアというのがどの程度のことを指して言っているのか
よくわからないので、的外れな解答かもしれませんが

> ・ペンティアムは1バスサイクル64ビット?なのですか?

Pentiumのバス幅は64ビットです。バスサイクルというのは
CPUがアクセスコマンドを発行して、実際にデータを受け取る
までのシーケンスの事を指し、単位はクロックです。

> ・メモリコントローラの具体的な役割は何ですか?

Pentiumに代表されるパソコン用のCPUはたいして器用ではない
ので、直接PCIスロットやメモリにアクセスする事ができません。
メモリコントローラはCPUとメモリの仲介を行います。

> ・メモリバンクは具体的に何をしていて、どのようなものなの
> ですか?

多分DIMMのバンクの事だと思いますが、DIMMにはSDRAMという
種類のRAMが使われています。SDRAMはチップの内部を2または
4つの区画に分けて、それぞれを別々にアクセスできるように
して高速化を図っています。この区画の事をバンクと呼びます。

> 実はメモリからのデータの取り出し方が知りたくて調べていたら、
> 上記の下の2つに関係あるようなので、(ハードよりですので)

メモリからのデータの取り出し、というのがソフトウェアレベル
での話(書き込まれている値をプログラム上で読み出す)なのか
ハードウェアレベルでの話(SDRAMのデータを電気信号として
取り出す)なのかが今ひとつわかりません。

物理的なSDRAMのアクセスチャートはNEC半導体のページに
記載されています。




315. 間違えました べっち  2000/11/21 (火) 14:28
すいません!

>int *p = a+2;

は、int ではなく、char の間違いです。
どうか、宜しくお願いします。




314. 突然失礼します。 べっち  2000/11/21 (火) 14:20
あの、突然失礼します。未熟者で修行中のべっちと申します。
あることを調べていたら、このページを紹介して頂きました。
パソコンの基本的な仕組みをお教え願いたいのですが、
よろしいでしょうか?

・ペンティアムは1バスサイクル64ビット?なのですか?
・メモリコントローラの具体的な役割は何ですか?
・メモリバンクは具体的に何をしていて、どのようなものなのですか?
 (ひょっとして、ただのスロットなのでしょうか?)

実はメモリからのデータの取り出し方が知りたくて調べていたら、
上記の下の2つに関係あるようなので、(ハードよりですので)
秋葉原で訊いてまわったところ、あまり思っているような情報が
得られませんでした。
そこで、ひょっとしたらプログラマの方のほうがメモリ操作とか
されてますし、逆にハードよりの方より詳しいのでは?
と思い、あるページでお尋ねしたところ、ここのページを紹介
して頂きました。

実際に一番疑問に思っていることなんですが、
char a[10] = {初期化};
int *p = a+2;
と宣言し、計算式などで *p を使用するときデータバスを流れる
4バイトは(1 を1バイトとして見てください。)

パターンA: @1111@ 1111 1111 //配列の先頭から4バイト
パターンB: 11@11 11@11 1111 //ポインタ位置から4バイト
#@で括ったとこがバス幅だと思ってください。

パターンAのように取り出されてくるのでしょうか?それとも、
パターンBのように取り出されてくるのでしょうか?

未熟者ですので理解力に乏しいように思われます。
なるべく詳しく教えていただければうれしいです。
宜しくお願いします。




313. float 精度で行けるのに double な変数達   2000/11/20 (月) 17:02
>double<=>float変換をMMX

それ自体は早くならないかもしれないけど、変換した後、それに続く演算を 3DNow! で float 演算しちゃうと、合わせ技で早くなるかも。
ってか、やってみます。




312. ネタ提供(?) へるみ  2000/11/19 (日) 00:50
最近ちょっと考えてるのはdouble<=>float変換をMMXを使ったら速くならないかなということ。
実験したらまた書きこんでみます。




311. Re: VC++で3DNow、SSEが。 うひょ! [URL]  2000/11/16 (木) 19:59
面白い最適化のアイデアですか?

ずばり、Pen4 SSE2対応!
モノがないって…?(^_^;)

下のほうにある MSDNのアップデートで
SSE2に対応したみたいです。

http://msdn.microsoft.com/vstudio/downloads/ppack/

Instructionは Intelのサイトにありました。
日本語はないのかな?

http://www.intel.co.jp/jp/developer/design/processor/future/manuals/index.htm




310. Re: 動きました うるり  2000/11/16 (木) 02:22
お役に立ててよかったです。
注意して危険地帯をお進みください^^;




309. 動きました EINS  2000/11/14 (火) 08:41
うるりさん「wrmsr, rdpmcを使うためのドライバ」への
レス、ありがとうございます。
さっそく試したところ、ちゃんと動きました。
ご丁寧な説明ありがとうございます。




308. チャレンジャーですね^^; うるり  2000/11/14 (火) 07:41
使ったことはありませんが、こんな感じでは?

初期化が
MSRGateInstallDriver()
MSRGateDeviceInit()
を使用して成功していますか?
NTの場合はInstallにadministrator権限が必要だと思います。

MSRGateWriteMSR( 0, 0xD0 );
ということですので
カウンタ0で、
INST_DECODER(デコードされた命令の数)のカウントで良いんですよね?
ただ直接MSRを制御するには設定が足りません^^;

まずファイルの修正を2箇所。

MSRGateWriteMSR{NT,95}()

para->nIndex = nIndexPMC + 0xc0010000; //K7
から
para->nIndex = nIndexPMC + 0x186; //P6
に変更

#define SETCOUNTER( COUNTER, EVENTMASK, UNITMASK )

MSRGateWriteMSR( COUNTER, (EVENTMASK) | ((UNITMASK)<<16) | 0x410000 )
から
MSRGateWriteMSR( COUNTER, (EVENTMASK) | ((UNITMASK)<<8) | 0x450000 )
に変更

ようやく本題^^;
MSRGateWriteMSR( 0, 0xD0 );

SETCOUNTER( 0, 0xD0, 0 )
に変更

こんなもんでいかがでしょう。
時間が無いので情報がちょっといい加減かもしれません。
MSRは設定を間違うとOSごと瞬殺ですのでチェックして
から試してください^^;




307. wrmsr, rdpmcを使うためのドライバ EINS  2000/11/12 (日) 14:18
はじめまして、EINS と申します。

「wrmsr, rdpmcを使うためのドライバ
Copyright(C) 2000 PEN」のことなのですが、
Windows2000,PentiumV,VC++6.0で、
インラインアセンブラで使用しています。
ドライバの初期化は成功するのですが、

// ドライバの初期化省略
int hi, lo, hi2, lo2;

MSRGateEnablePMC( TRUE );
MSRGateWriteMSR( 0, 0xD0 );
__asm {
mov ecx, 0
rdpmc
mov hi, edx
mov lo, eax
clc ; 計測の為
clc ; 計測の為
mov ecx, 0
rdpmc
mov hi2, edx
mov lo2, eax
}

printf( "1: %d\n", lo );
printf( "2: %d\n", lo2 );

MSRGateEnablePMC( FALSE );
// ドライバの後処理


上記のプログラムを実行すると、
1: 0
2: 0
と、表示されるのですが、
どこが違っているのか分からないので、
分かる方がいらっしゃれば
教えて頂けませんか。




306. VC++で3DNow、SSEが。 もす  2000/10/22 (日) 15:16
はじめまして。
最近アセンブラを学び始めたばかりですが、奥が深い・・・。それに難しいっす。
ところで、
http://msdn.microsoft.com/vstudio/downloads/ppack/
こんなの出たらしいです。
インラインアセンブラで3DNowやSSE、SSE2に対応したのかな?




305. アドレスデコーダ aya  2000/10/20 (金) 07:41
長船さん、へるみさん、
ありがとうございました。

== 長船さん ==
>アドレス計算はCPUのアキュムレータ(実行ユニット)が行う
>わけではなく、↑のアドレス計算を専門に行う部分で先に処理され
>その結果、確定したアドレスが実行ユニットに送られます。
ちょっと驚きです。
なんだか少し得した気分です。(^^;


== へるみさん ==
>設定 → C/C++ → ファイルリスティング → マシン語コードとソースを含む
>でbuildすると*.codというファイルが出来るのでそれをチェックして下さい。
VC++ にはこんな便利な機能があったんですね!
まだまだ VC++ の知らない機能がありそうで楽しみです。(^^;

>ただインラインアセンブラの場合はVC++が自動的にレジスタの退避復元のコードを追加していることがあります。
おっしゃる通り、VC++ が自動的にレジスタの退避 ( PUSH ) と復帰 ( POP ) をやってくれてました。
なんだか「いたれりつくせり」なコンパイラですね(^^;




304. Re: アドレスデコーダ へるみ  2000/10/19 (木) 10:59
>アドレス計算は専用のハードウェアが別に用意されているので(A)でも(B)でも速度は変わりません。

更に細かいつっこみを入れるとK6-2では(A)の方が命令長が長いためデコーダの段階で1clockの遅れを生じ結果的に遅くなることがあるようです。

>SH4やR5900にもアドレスデコーダが入ってれば楽なのにっ!
酒居さんもSH4って使ってらっしゃるんですよね。
x86以外のCPUを触ったことない私にはどんな世界か想像もつきません(^^;

ayaさん
>その前後で使用するレジスタの退避 ( push ) と復帰 ( pop ) を行わなくても良いのでしょうか?

殆んどのCコンパイラではeaxが関数の帰り値,
壊して良いのはecx, edx
壊していけないのはebx, esi, edi, ebp, esp
です。
VC++もそうなっています。ただインラインアセンブラの場合はVC++が自動的にレジスタの退避復元のコードを追加していることがあります。
そのため問題なく動いてるのかも知れません。
実際のコードがどうなっているかは
設定 → C/C++ → ファイルリスティング → マシン語コードとソースを含む
でbuildすると*.codというファイルが出来るのでそれをチェックして下さい。




303. Re: 必ずしもそうでもなさそうです へるみ  2000/10/19 (木) 10:43

>ところがそれだけで何らかの実行ユニットを使うらしくて、
>場合によっては遅くなる場合がありました。gogoでは試した
>ことありますが、速くなったことはほとんどなく、遅くなる
>場合があったのでやめました。

leaはフラグを変更しないので自由度も高いしアドレス生成ユニットが暇な時(?)は積極的に使うのが良いのですね。

>Athlonと実行ユニットの数が違うとか、デコーダの性能が
>違うとか、デコード後の命令の粒度が違うとか、いろいろあるようで

そうですね。P5ならどう頑張っても2命令/clockなので分かりやすいのですがAthlonやPIIIはどこまで速くなれるのか分からない...




302. アドレスデコーダ 長船@たまに見てます  2000/10/19 (木) 03:40
●酒井さん:
> ということで、私はアドレス計算ユニット(ってあるの?)のほうで
アドレスの計算を専門に行う「アドレスデコーダ」という部分はありますよ。
パイプラインの上では実行ユニットの1〜2個手前になります。

●ayaさん:
> movq mm0,[edi+ecx*8] <--- (A)
> movq mm0,[edi] <---------- (B)
> (A) と (B) とでは処理時間に違いがないのですか?
> 素人的考えでは (B) の方が速いと思うのですが・・・。

アドレス計算はCPUのアキュムレータ(実行ユニット)が行う
わけではなく、↑のアドレス計算を専門に行う部分で先に処理され
その結果、確定したアドレスが実行ユニットに送られます。

アドレス計算は専用のハードウェアが別に用意されているので
(A)でも(B)でも速度は変わりません。

まぁ厳密な意味での処理時間と言う点では、データやプログラムの
キャッシュヒットの有無まで考慮に入れなければなりませんが (^^;

SH4やR5900にもアドレスデコーダが入ってれば楽なのにっ!




301. レジスタについて aya  2000/10/18 (水) 23:29
へるみさん、酒居さん、
「ペアリング」へのレス、ありがとうございます。

ところで疑問があるのですが、
例えば下記の場合

movq mm0,[edi+ecx*8] <--- (A)
movq mm0,[edi] <---------- (B)

(A) と (B) とでは処理時間に違いがないのですか?
素人的考えでは (B) の方が速いと思うのですが・・・。

あと、
インラインアセンブラ ( 私の場合は VC++6.0 ) で
いろいろなレジスタを使う場合に
その前後で
使用するレジスタの退避 ( push ) と復帰 ( pop ) を
行わなくても良いのでしょうか?
具体的には

__asm
{
push eax
push ebx
push ecx

mov eax, 1
mov ebx, 2
mov eax, 3

push ecx
push ebx
push edx
};

とする必要はないのかなということなのですが・・・。
インターネットで公開されているいろいろなソースを
見てみたのですが、
やっていないことが多いような気がします。
先日見つけた MMX 命令が使えるかどうかを調べる
インラインアセンブラを使ったプログラムも
レジスタの退避と復元をおこなっていないのですが、
問題ないのでしょうか?


/*** MMX 命令が使えるかどうかを判定 ***/
BOOL CheckMMX()
{
BOOL bAvailableCPUID;
DWORD dwFeatureFlags, dwSteppingID;
int nHighestValue;
char szMaker[13];

/* CPUID 命令が使えるか? */
__asm
{
pushfd
pop eax
xor eax, 0x00200000
push eax
popfd
pushfd
pop ebx
cmp eax, ebx
mov bAvailableCPUID, 1
je CheckMMX_SupportCPUID
mov bAvailableCPUID, 0
CheckMMX_SupportCPUID:
};

if( !bAvailableCPUID ) return ( FALSE );

/* CPUID 命令を実行するときに EAX レジスタに設定できる値の最大値を取得 */
__asm
{
mov eax, 0

;↓は cpuid 命令の代わり
;_emit 0x0f
;_emit 0xa2
cpuid

mov nHighestValue, eax
mov dword ptr szMaker, ebx
mov dword ptr szMaker + 4, edx
mov dword ptr szMaker + 8, ecx
};

szMaker[12] = '\0';
if( nHighestValue < 1 ) return ( FALSE );

/* MMX テクノロジが実装されているか? */
__asm
{
mov eax, 1

;↓は cpuid 命令の代わり
;_emit 0x0f
;_emit 0xa2
cpuid

mov dwSteppingID, eax
mov dwFeatureFlags, edx
};

if( !( dwFeatureFlags & 0x00800000 ) ) return ( FALSE );

return ( TRUE );
}



 

  次へ  ← 355-301 / 323 件表示 →  前へ
件/頁   

 
password:
Copyright(C) 2000 NIFTY Corporation All Rights Reserved.