トップページ⇒tech
1001コメント296KB

トリッキーなコード その2

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
独りよがりのためのスレッド
大体トリッキーなコードを書く奴に限って
致命的なバグを出したりするんだけど、
書きたいもんはしょうがない。

・・・らしい


前スレ http://pc3.2ch.net/test/read.cgi/tech/983191866
0153デフォルトの名無しさんNGNG
>>152
151を良く見ろ、コードが全く違うぞ。
それ以前の問題だ。
0154107NGNG
あ、ほんとだ。 var は不要だし、そもそも交換した結果を返してないや。
まあ、時間測るだけだからいいか
0155デフォルトの名無しさんNGNG
>>107 お前はいったい何の時間を計測してんだ?
for や func call やタスクスイッチのオーバーヘッドの方が
大きかったりしないか?
>>129 の方がまだ信憑性ありそうだな。

お前ら >>129 のコード実行してOS、CPU(ステップ&周波数含む)と共に報告スレ。
漏れはスペースが全部なくなってて挫折しますた。(w
0156デフォルトの名無しさんNGNG
OS云々はともかく、Pentiumに関して言うならば…。

push/pop での交換は確実に遅い。スタック操作を伴なうから
プロテクトモードでならメモリ保護チェックが必ず発生してしまう。
#コンパイラの最適化レベルを上げるとcall/retを減らすように
#アセンブルコードを出力しようとするのもこの理由による。

xor他による交換の場合は、二つ目、三つ目の演算命令は
その前の演算命令によってレジスタ内容が完全確定していないと
演算自体することが出来ないわけだから、それぞれの命令間で
パイプラインストールが発生する可能性が非常に高い。
#それぞれの命令間にNOPを挟んでも実行時間に大差なければほぼ間違いない

xchg の場合、厳密にはレジスタの内容を交換しているのではなくて、
現在ではレジスタの名前のほうを(CPU内部的に)交換していると思っていい。
なので交換対象レジスタの組み合わせによってはストールしにくい(またはしない)
#むかしのCPUでは確かにレジスタ内容自体を交換していた。(RISC系は現在でもそう)
#けど多段パイプラインやコード予測機能の絡みもあるので、
#CISC系ではそういうのに影響を与えにくい設計に進化してきている(はず)

まあ、純粋培養のソフト屋さんにハード依存の話をしても、
なかなか想像力が付いて来ないだろうとは思うけどね…。
0157デフォルトの名無しさんNGNG
>>156
マジレスカコワルイ

push/popはメモリアクセスする時点で遅いのは確定。
俺の興味はどっちかというとどれ位遅いかだな。

xorやmovによる交換も実質レジスタリネーミングされると
考えればパイプラインストールはほぼ発生してないはず。

129の結果どおりだとすれば、156のとは正反対の
mov/xor 3回よりは xchg の方が早いが、
xchg単体は mov/xor単体よりもずっと遅い
という結果が出てくる。
0158デフォルトの名無しさんNGNG
そもそもCPUの話題でOS他の環境のネタが出てくるところが痛いね。
ここの住民はそのうちメモリ容量とかHDD容量とかビデオチップとか
言い出す予感。
0159デフォルトの名無しさんNGNG
前スレ良かったな〜
0160107NGNG
>>155
負荷を測るなら for や call の時間込みで測定するのがホントじゃないの?
 まあ、ループした方がいいっていうなら
procedure TForm1.Button1Click(Sender: TObject);
procedure SwapXCHG;
var i:Integer;
begin for i:=0 to 100-1 do asm  xchg eax, edx end;
end;
procedure SwapXOR;
var i:Integer;
begin for i:=0 to 100-1 do asm
xor eax, edx
xor edx, eax
xor eax, edx
end;
end;
function RDTSC:Integer;
asm RDTSC
end;
var cXCHG,cXOR,c0,c1,i,j:Integer;
var a,b:Integer;
begin
a:=1; b:=2; cXCHG:=0;cXOR:=0;
c0:=RDTSC;
for j:=0 to 9 do begin
SwapXCHG;  c1:=RDTSC;inc(cXCHG,c1-c0);c0:=c1;
SwapXOR; c1:=RDTSC;inc(cXOR,c1-c0);c0:=c1;
end;
Memo1.Lines.Add(Format('XOR=%5d XCHG=%5d',[cXOR,cXCHG]));
end;
これでも 結果は XOR= 3589 XCHG= 3631 でAthronでは同じって結論でいいんじゃないの
0161107NGNG
上と同じコードをx86-Famiky6と表示されるパソコンで走らせたら
  XOR= 4044 XCHG= 3756
って事で、若干 XCHG 命令が速いね。 

まあ当然の結果だけど。
0162107NGNG
あと XOR の応用例

 abs(x) を CDQ /XOR /SUB で書けるように
 max(a,b) を書くのに分岐無しで書くのに応用出来る
0163デフォルトの名無しさんNGNG
>>157
何を言っているのかわからないんだけど・・・。

> xorやmovによる交換も実質レジスタリネーミングされると
> 考えればパイプラインストールはほぼ発生してないはず。

そうなの??
mov はわからんでもないけど、xor が?

> xchg単体は mov/xor単体よりもずっと遅い
> という結果が出てくる。

単体で比較して何か意味あるの?
mov や xor に xchg 相当の事をやらせて初めて比較の意味があるんだけど。
0164デフォルトの名無しさんNGNG
age
アセンブラの話よりも、本格的にトリッキーなコードキボンヌ
0165デフォルトの名無しさんNGNG
トレッキーなコードなら書きますが、それが何か?
0166デフォルトの名無しさんNGNG
int main(void){
 printf("VOYAGER マンセー\n");
 return 0;
}
0167デフォルトの名無しさんNGNG
#define is_kanji1st(c) ((unsigned int) (c ^ 0x20) - 0xa1 < 0x3c)
シフトJISの1バイト目か判定(コピペ
外出だったらスマソ。

新年もトリッキーなコードが飛び交いますよう
0168デフォルトの名無しさんNGNG
__machine {
 0x05, 0x0000ffff ;add eax, 0000ffff
}

機械語直打ちキター
0169デフォルトの名無しさんNGNG
>>168
大晦日に萎えるソースコード持ってくるな・・・
前スレ嫁、そして初日の出を見ることなく氏ね
0170デフォルトの名無しさんNGNG
__machine {
 0xff, 0xf1 ;push ecx
 0xe8, 0x40229833 ;call 40229833
}

(´∀`)あはは
0171デフォルトの名無しさんNGNG
__machine {
 0x90
}

( ゚∀゚ )あっひゃっひゃっひゃ
0172デフォルトの名無しさんNGNG
>>167
それは前スレで外出だったと思う。
どこからのコピペ?
0173デフォルトの名無しさんNGNG
>>172
http://www.st.rim.or.jp/~phinloda/phin/phin9509.html
0174デフォルトの名無しさんNGNG
>>173
NIFTYのどこかだと思ってたけど、元はFCだったか。
0175デフォルトの名無しさんNGNG
>>167
マシン語の世界ではごくごく普通に使ってた計算式であり、
アルゴリズムなんだけど、高級言語に浸かってくると
やっぱり忘れてしまうわな、そういうの…。

#CMP一発で5分岐するとかって、あったなぁ。
0176ツッコミ初めNGNG
>175
別にマシン語の世界じゃなくたって、一般的では。
境界線は自前で書いてるか、ライブラリ使ってるか、じゃないの?
0177デフォルトの名無しさんNGNG
それがトリッキーじゃないって事は、こういうのもトリッキーじゃないのか。

大小によって -1,0,1を返す関数

type  TValueSign  =  -1..1;
function  CompSign(A,B:Integer):TValueSign;
asm
  CMP  EAX,EDX;  //A-B
  SETGE CL
  ADD  CL,CL
  DEC  CL
  CMP  EAX,EDX;  //A-B
  SETZ  AL
  DEC  AL
  AND  AL,CL
  CBW
  CWDE
end;
0178デフォルトの名無しさんNGNG
VC6がそんなコードを吐いた気がする。
0179デフォルトの名無しさんNGNG
#include <iostream>

void SwapXCHG(int& a, int& b)
{
asm {
mov eax, [a]
mov ebx, [b]
xchg eax, ebx
mov [a], eax
mov [b], ebx
}
}

void SwapXOR(int& a, int& b)
{
asm {
mov eax, [a]
mov ebx, [b]
xor eax, ebx
xor ebx, eax
xor eax, ebx
mov [a], eax
mov [b], ebx
}
}
0180デフォルトの名無しさんNGNG
int RDTSC()
{
int i;

asm {
RDTSC
mov [i], eax
}
return i;
}

int main()
{
int a = 1, b = 2;
int c0, c1, cXCHG = 0, cXOR = 0;

for (int j = 0; j < 10; j++) {
c0 = RDTSC();
for (int i = 0; i < 1000; i++) SwapXCHG(a, b);
c1 = RDTSC();
cXCHG += c1 - c0;
c0 = RDTSC();
for (int i = 0; i < 1000; i++) SwapXOR(a, b);
c1 = RDTSC();
cXOR += c1 - c0;
}
std::cout << "XCHG = " << cXCHG << std::endl;
std::cout << "XOR = " << cXOR << std::endl;
}
0181デフォルトの名無しさんNGNG
>>179,180は>>160のソースをC++にしたものだが、Pen4で実行してみた限りでは
両者の関数のクロック数にほとんど差がない。

>>177の比較関数もC++化して実行してみたが、単純なif文の方が約40%ほど
速かった。アセンブラによるトリッキーな書き方にはクロックの上でのアドバン
テージはないのだろうか。
0182デフォルトの名無しさんNGNG
>>181
比較の場合はランダムデータですか?
最近のCPUは分岐予測が余程優れているのかな…。
0183デフォルトの名無しさんNGNG
>>182
ランダムデータではないです。変数に値を入れておいて比較しました。
こんな感じ。

int main()
{
int c0, c1, cSETCC = 0, cIF = 0;
int a = 1, b = 2;

for (int j = 0; j < 10; j++) {
c0 = RDTSC();
for (int i = 0; i < 1000; i++) {
cmp1(a, b);
cmp1(b, a);
cmp1(a, a);
}
c1 = RDTSC();
cSETCC += c1 - c0;
c0 = RDTSC();
for (int i = 0; i < 1000; i++) {
cmp2(a, b);
cmp2(b, a);
cmp2(a, a);
}
c1 = RDTSC();
cIF += c1 - c0;
}
std::cout << "setcc = " << cSETCC << std::endl;
std::cout << "if = " << cIF << std::endl;
}
0184デフォルトの名無しさんNGNG
あらら、ランダムデータにしたら、setccの方が30%ほど速くなりました。
分岐予測が働きにくくなるからでしょうね。
0185デフォルトの名無しさんNGNG
ランダムデータとソート済みデータで速度が変わるんだねえ
どれらいのランダムネス(?)が境界になるのか知りたいところ
0186デフォルトの名無しさんNGNG
>>185
P4だと、40個毎に乱数の系列を戻した時にほぼ同じタイムになるみたい。

const int N = 1000;

int cmp1(int& a, int& b)
{
int i;
asm {
MOV EAX,[a]
MOV EBX,[b]
CMP EAX,EBX; //A-B
SETGE CL
ADD CL,CL
DEC CL
CMP EAX,EBX; //A-B
SETZ AL
DEC AL
AND AL,CL
CBW
CWDE
MOV [i],EAX
}
return i;
}

int cmp2(int& a, int& b)
{
if (a < b) return -1;
else if (a > b) return 1;
return 0;
}
0187デフォルトの名無しさんNGNG
int RDTSC()
{
int i;

asm {
RDTSC
mov [i], eax
}
return i;
}

int main()
{
int c0, c1, cSETCC = 0, cIF = 0;
int a[N], b[N];

for (int i = 0; i < N; i++) {
a[i] = std::rand(); // ここで比較用データをセットする
b[i] = std::rand(); //
if (i % 40 == 0) std::srand(0); // 乱数系列初期化用
}
0188デフォルトの名無しさんNGNG
for (int j = 0; j < 10; j++) {
c0 = RDTSC();
for (int i = 0; i < 1000; i++) cmp1(a[i], b[i]);
c1 = RDTSC();
cSETCC += c1 - c0;
c0 = RDTSC();
for (int i = 0; i < 1000; i++) cmp2(a[i], b[i]);
c1 = RDTSC();
cIF += c1 - c0;
}
std::cout << "setcc = " << cSETCC << std::endl;
std::cout << "if = " << cIF << std::endl;
}

長文スマソ
0189デフォルトの名無しさんNGNG
いや、勉強になった。
少し前まで、分岐予測ミスのペナルティは大きくて 分岐なしが平均的には余程速かったのになあ
0190デフォルトの名無しさんNGNG
グッジョブ!
しかしこの比率ってCPUの世代で変わったりするのかな・・・
0191デフォルトの名無しさんNGNG
>>189
分岐履歴バッファがCPU内部にはあって、何重もの入れ子になった
ループの分岐を予測できるらしいですね。
P4のような深いパイプラインを持つCPUでは不可欠の機構なので
相当念入りに作ってあるようです。

P3やAthlonの結果も知りたいのですが、どなたか試してみていただ
けませんか?
0192デフォルトの名無しさんNGNG
AthlonXP1800+、VC++6にてテストしてみた。
概ねcmp1のほうが速いですが、評価順や最適化の有り無しでも
結果が変わるようです。(i % 40)の部分はほぼ影響なかった。
正確に測るには関数内に_asmでRDTSC入れてDWORD境界の
対策をしないと駄目かも知れず。
あ、最適化するとcmp2(if 〜 else if 〜)の関数内にあるジャンプ
命令は1個ですたw
0193デフォルトの名無しさんNGNG
あ、DWORD境界ってのはRDTSCの返り値がループした時の事です。
0194デフォルトの名無しさんNGNG
cmp1ってローカル変数に代入するから
こんな小さなコードだと少しはロスがあると思うわけ。
(フルアセンブラや、gccやbccのようにレジスタを直接返せれば別だけど)

ってゆーかさ、"トリッキーなコード"を名乗るんだったら、
せめてこの程度までは最適化してから比較しようよ。

と言ったものの、あまり詳しくないんで、
見た目が最適化されただけで、内部的なクロック数は増えてるしれない。

int cmp1(int a, int b)
{
 asm {
  mov eax, a  // 引数をレジスタ渡しだと・・・
  cmp eax, b  // 
  setl al
  setg cl
  neg al
  xor al, cl
  cbw
  cwde
  mov a, eax  // <-これがじゃま
 }
 return a;
}
0195デフォルトの名無しさんNGNG
>>194
SETxx はフラグに影響を与えなかったっけ?
0196デフォルトの名無しさんNGNG
SETccはフラグに影響しない(マニュアルに書いてある)

コンパイラはフラグを「比較直後」以外に使うのがうまくないんだよね。
その後で並べ替えることはあっても。
だから、アセンブラレベルでなら、add/subの代わりにleaを用いてフラグを維持し、
それから条件を調べる(jmp等)って方法なんかもでてくるわけさ。
もちろん、よほどクリティカルな部分でない限り、意味は無いけどね。

よく考えたら、>>194はxorではなくorを使ってもいいんだけど、
xorの方が意味が分かりにくい==トリッキーってことで許して。

で、ほぼ同じロジックでCで書くとしたら
int cmp2(int a, int b)
{
 return (a < b) | -(a > b);
}
だね。
0197デフォルトの名無しさんNGNG
そうか。intelから資料ダウンロードして確認したよ。
持ってた本に実行後にフラグが変更されてるような用例載ってたから勘違いしてた。

じゃあ1ステップ短く出来るよ

type  TValueSign  =  -1..1;
function  CompSign(A,B:Integer):TValueSign;
asm
  CMP  EAX,EDX;  //A-B
  SETLE AH
  SETGE AL
  SUB  AL,AH
  CBW
  CWDE
end;
0198デフォルトの名無しさんNGNG
せっかくいい感じにベンチマークできてたのに
194から急に厨臭くなった・・・
0199デフォルトの名無しさんNGNG
cbw+cwdeとmovsxはどっちがいいのかな?

と>>197を読んで思い出したけど、
似たようなロジックは半年くらい前にC言語スレで見た(書いた)気がする。
減算結果の最上位bitをシフトしてxorとるやつ。

とここまで書いて、その時見たのは「aとbの符号が一致しているかを返す」
だったのを思い出した。
そういうのがあったからxor使っちゃったんだな(もちろん、subの方が良いけど)
0200デフォルトの名無しさんNGNG
>>198
ん?ベンチマーク続けてかまわないんじゃないの?
一つのスレッドで複数の話題が進行するなんてよくあることだし。

要は、分岐予測があたることに期待した単純なコードと
分岐予測がはずれる可能性に備えて少し複雑なコードで
CPUやデータのばらつきによって、どちらが良いか、どのあたりが分岐点になるのかでしょ?
実際、現在のCPUでは分岐予測ミスやメモリアクセスなどの
ペナルティを減らす方がはるかに重要だし。
0201デフォルトの名無しさんNGNG
いや、急に見た目最適化とかステップ数とか
そういうのが当てにならないにもかかわらず
アナクロな方向になってあきれただけ
0202デフォルトの名無しさんNGNG
一つの命令自体のクロック数はあまり意味はないけど、
・メモリアクセスがない
・分岐がない
・複雑な命令がない
・依存関係のある命令が少ない
場合ならば、充分意味があるよ。

少なくとも俺は、
「両方Cで書いて分岐の有無によるテスト」か
「両方アセンブラで書いて分岐の有無によるテスト」
にしないなら、
「片方をC、片方をアセンブラで書いてどちらも分岐命令を使う」
「片方をC、片方をアセンブラで書いてどちらも分岐命令を使わない」
でなければ、あまり意味はないと思っているけどね。

出来れば、全てアセンブラでアラインも揃え、
分岐の有無による差を見たいけどね。
0203デフォルトの名無しさんNGNG
> 場合ならば、充分意味があるよ。

単なる思い込みコードをベンチマーク結果なしにみせつけられてもねえ。
0204デフォルトの名無しさんNGNG
そうだね。
このスレに書く"トリッキーなコード"はベンチマークがなきゃ意味無いよね。
0205デフォルトの名無しさんNGNG
速度のためのトリックならベンチマーク必須だね。
コード量削減のためならバイト数の計測。

他人を驚かすのが目的なら・・・どうしよう
0206デフォルトの名無しさんNGNG
>cbw+cwdeとmovsxはどっちがいいのかな?
あ! 忘れてた。 MOVSX があったんだ。

そりゃMOVSX1命令の方が短いでしょ

type  TValueSign  =  -1..1;
function  CompSign(A,B:Integer):TValueSign;
asm
  CMP  EAX,EDX;  //A-B
  SETLE AH
  SETGE AL
  SUB  AL,AH
  MOVSX AX,AL
end;
0207デフォルトの名無しさんNGNG
どーーーしても「コードを見れば明らか」と納得できない人約一名がいるみたいなので
ベンチマーク取りましたよ。
test1が>>183の外ループを10倍したもの
test2が>>187-188の外ループを10倍したもの
cmp1が>>197の前後にロードとストアを入れたもの
cmp2が>>186のcmp1の引数を参照にしなかったもの
呼び出し規約はcdeclで。

test1
cmp1 = 4943201
cmp2 = 7133229
test2
cmp1 = 1677185
cmp2 = 2230045

ま、こんなもんでしょ。
ロード/ストア/スタックフレーム操作/callが入るからそうそう極端な差はつかないね。
0208207NGNG
あ、アーキテクチャはP6ね
0209デフォルトの名無しさんNGNG
おう、厨房から脱出した人、おめでとう
0210デフォルトの名無しさんNGNG
安心しろ。
「明らか」な結果をわざわざ測定するのは今回だけ。学生実験とは違うから。
まあ雪で出かけられない中、良い暇つぶしになったよ。
0211デフォルトの名無しさんNGNG
結果が明らか?
んなアホな
0212デフォルトの名無しさんNGNG
>>186より>>197や>>206が速いのは(わかる人にとっては)明らかだよ。

もちろん、何十年後かのアーキテクチャでもそうだとは言い切らないけど、
今後10年の間は明らか。
逆転するようなことがあっても、その時代にはx86(IA-32)は寿命を終えている。
0213デフォルトの名無しさんNGNG
明らかな理由は>>202の前半に書いたけど、理解できなかったんだろうね。
0214デフォルトの名無しさんNGNG
うーん、厨房は死んでも直らないとはこのことか・・・
残念。
0215デフォルトの名無しさんNGNG
おもしろいからあげ

0216デフォルトの名無しさんNGNG
うん、俺はベンチマークも提示できないような厨房だから
煽りにも精一杯反応しちゃうよ。

ねー、ぼくちゃんは厨房じゃないんでしょ?
煽りに反応しちゃだめでしょ。
0217デフォルトの名無しさんNGNG
腐ってきた。194と197どっちが腐らせたんだ。
0218デフォルトの名無しさんNGNG
この程度で煽りと思ってしまうのはまずいと思う。
単なる指摘でしょう。

そういやIA-32って今年で18周年だね。
0219デフォルトの名無しさんNGNG
>198 >201 >203 >205 >209 >211 >214
0220デフォルトの名無しさんNGNG
なるほど、いきなり厨臭くなったことを指摘してくれたんだね。どうもありがとう。
0221デフォルトの名無しさんNGNG
非常に重要な指摘でした
有意義な時間を過ごせました
0222デフォルトの名無しさんNGNG
そうだ、>>198さんは
俺が>>202の後半で指摘した「ベンチマークは測定条件を揃えて」ってのは
放置しちゃったのかな?
>>198で、すごくベンチマークが楽しみそうだったのに。
0223デフォルトの名無しさんNGNG
まあ、測定条件を揃えずに、単に「分岐予測による効果で結果が変わる」ことだけなら
>>188まででわかったんだから
AthlonもP3も関係ないし、どちらが何%速いとか
どこで逆転するとかの報告は必要ないな。

確かに、アセンブラの方を最適化したから厨房臭かったかもね。
むしろ、「これ↓の結果を比較しろ」と書いた方が良かったか?
int cmp1(int a, int b) {
 return (a > b) - (a < b);
}
int cmp2(int a, int b){
 if (a < b) return -1;
 else if (a > b) return 1;
 return 0;
}

最後に付け加えとこ。
>>177(以降)はSETccを使って分岐をなくしているけど、
CMOVでも同じ結果が出てる。
少なくとも、現存のx86アーキテクチャは
 分岐予測成功 > CMOV >>> 分岐予測失敗
になってる。
0224デフォルトの名無しさんNGNG
>少なくとも、現存のx86アーキテクチャは
> 分岐予測成功 > CMOV >>> 分岐予測失敗
>になってる。

P3からP4になって、さらに強まった気がするんだけどどうかなあ
0225デフォルトの名無しさんNGNG
俺には難しいけどいいスレっぽいな。
がんばれ!
0226デフォルトの名無しさんNGNG
へえ CMOV か Pen2以後で使えるんだね。
0227デフォルトの名無しさんNGNG
なるほど、>>206さんのようにすると、ランダムな比較をしても速いね。
ステップ数が少ないので、if文では完全な規則性のある数を比較した場合
以外ほとんどかなわない。

CMOVを使ったプログラムでも検証してみます。
0228デフォルトの名無しさんNGNG
なるほど、CMOVccでもSETccと同等の速度が出るね。CMOVがイミディエート値
をロードできると思ってたけど、だめなのね。

int cmp1(int& a, int& b)
{
static int one = 1, mone = -1;
int i;
asm {
MOV ESI,a
MOV EDI,b
MOV EAX,0
CMP ESI,EDI;
CMOVL EAX,mone
CMOVG EAX,one
MOV i,EAX
}
return i;
}
0229デフォルトの名無しさんNGNG
>>228
CMP じゃなlくて SUB にすれば 引算結果のゼロを使えるから1ステップ短くなるよ
0230デフォルトの名無しさんNGNG
デバッガで追いかけたら、次の部分が正しいコードに展開されてなかった。

MOV ESI,a
MOV EDI,b

int&a, int& bとなっているので、aとbはポインタを与えてしまう。だからこれは

MOV ESI,a
MOV ESI,[ESI]
MOV EDI,b
MOV EDI,[EDI]

と書かなければならない。このような不都合を避けるため、intの参照ではなく
値で渡す事にした。if文の方も値で渡すようにしたのだが、意外とif文が速くなっ
た。乱数の発生系列の初期化を70個毎にしないとCMOVccやSETccが負けて
しまう。
0231デフォルトの名無しさんNGNG
>>229
それはなかなかトリッキーですね!早速やってみます!
0232デフォルトの名無しさんNGNG
>>229
このようにしてみました。規則的なifの速度にはかなわないけど、不規則な
ifに対しては、乱数の初期化を10個毎にしても勝てます!(Pentium4)

asm {
MOV EAX,a
MOV EBX,b
SUB EAX,EBX;
CMOVL EAX,mone
CMOVG EAX,one
MOV i,EAX
}
0233デフォルトの名無しさんNGNG
あんまり短いコードでベンチマークしても意味がないと思うけどなあ

分岐なしに書けるなら、多少冗長に見えても、使った方が全体のパフォーマンスが上がる事がおおいよ。
年々大きくはなっても、分岐ターゲット・バッファ(BTB)はやっぱり有限だからさ。
0234デフォルトの名無しさんNGNG
>>233
大規模なプログラムだと、分岐の過程は一般的にランダムだから、分岐フロー
を無くすようなプログラムが効果的でしょうね。ただ、短いコードでないと、分岐
無しで動作するようなプログラムを書く事は非常に難しいでしょうけど。
0235デフォルトの名無しさんNGNG
>>234
いやそうじゃなくて、再利用度の高い一部の関数とかを分岐無しが可能なら、出来る時に書いておけば
全体のパフォーマンスが上がるだろうって事。
たとえ、その関数だけ評価して if 文よりパフォーマンスが悪くても、

もちろん重い処理の内側のループを書くような場合は別だけどさ
0236デフォルトの名無しさんNGNG
>>235
ああなるほど、BTBをなるべく消費しない関数が書けるなら書いておこうって
事ですね。納得。その分別の箇所でBTBが有効活用できるって事か。
0237デフォルトの名無しさんNGNG
SSE2命令を使ったトリッキーなプログラムってありますか?
0238デフォルトの名無しさんNGNG
大規模なプログラムでそんなこと気にする人っているんかいな
0239デフォルトの名無しさんNGNG
SE を使ったトリッキーなプログラムってありますか?
0240デフォルトの名無しさんNGNG
>>232
キャッシュにヒットしないと遅い予感
って、そんな場合は、ほとんど意味が無いから置いといて
Pen4はCMOVccのレイテンシがマニュアルに見当たらないので
知らなかったけど結構早かったんですね…
でも、おそらくP6系ではSETccの方が早いはずので
P6系を持ってる方はレッツチャレンジ♪
(と言っても、あまり差は出ないと思うけど…)

ついでに両方の値をレジスタに入れる必要は…
asm {
  MOV EAX,a
  SUB EAX,b
  CMOVL EAX,mone
:
}
0241デフォルトの名無しさんNGNG
>>239
SEにプログラム作らせる事自体がトリッキー
0242デフォルトの名無しさんNGNG
なんかみんなスゲー。仕事でプログラムやってる人??
年齢もしりたいw
0243デフォルトの名無しさんNGNG
いつの間にか前スレが埋められてる・・・
2年間、もってくれるかなと思ってたけど、
それまでに落ちちゃうかなぁ。
0244IP記録実験NGNG
IP記録実験
http://qb.2ch.net/test/read.cgi/accuse/1042013605/

1 名前:ひろゆき ◆3SHRUNYAXA @どうやら管理人 ★ 投稿日:03/01/08 17:13 ID:???
そんなわけで、qbサーバでIPの記録実験をはじめましたー。

27 名前:心得をよく読みましょう 投稿日:03/01/08 17:20 ID:yL/kYdMc
SETTING.TXT管轄でないということは全鯖導入を視野に、か?

38 名前:ひろゆき ◆3SHRUNYAXA 投稿日:03/01/08 17:22 ID:rLfxQ17l
>>27
鋭いです。

73 名前:ひろゆき ◆3SHRUNYAXA 投稿日:03/01/08 17:27 ID:rLfxQ17l
>ところで、IPが抜かれて何か今までと変わることってあるのでしょうか?
・今までより、サーバが重くなる。
・裁判所や警察からの照会があった場合にはIPを提出することがある。
0245デフォルトの名無しさんNGNG
age
0246デフォルトの名無しさんNGNG
全レスです。
0247デフォルトの名無しさんNGNG
あこがれのヒモ生活のためにがんばってもらいたいものです。
>>10
0248デフォルトの名無しさんNGNG
>>212
     llllllllllll                               lllll
          lllllll                              lllll
        lllll                                llllll
    lllll  llllllllll  llllllllll                        lllll
  lllll      lllll    llllllllll    lllllllllllllllllllllllllllllllllll   lllllll
 lllll      llllllllll    llllllllll                  lllllllllllllll      lllll
llllllllll      llllllllll  llllllllll                  lllll    lllll  lllllllll
        llllllllll                          lllll      llllllll

       ∧_∧  ∧_∧  ∧_∧  ∧_∧
      ( ´_ゝ`) ( ´_ゝ`) ( ´_ゝ`) ( ´_ゝ`)
      ∧_∧ ) ∧_∧ )∧_∧ )∧_∧ )
     ( ´_ゝ`) ( ´_ゝ`) ( ´_ゝ`) ( ´_ゝ`)
   ∧_∧ ) ∧_∧ ) ∧_∧ )∧_∧ )
   ( ´_ゝ`) ( ´_ゝ`)  ( ´_ゝ`) ( ´_ゝ`)/|
  (____)  (____) (____) (____)
/   ./|./   /|./   /|/   /|
| ̄ ̄ ̄|/| ̄ ̄ ̄|/| ̄ ̄ ̄|/| ̄ ̄ ̄|/|
|| ̄ ̄ ̄|| || ̄ ̄ ̄|| || ̄ ̄ ̄|| || ̄ ̄ ̄||
0249デフォルトの名無しさんNGNG
無限にログを残してるサーバ管理者っていないと思います。
0250デフォルトの名無しさんNGNG
>>352
ひろしま必死だなっと・・・
0251デフォルトの名無しさんNGNG
>>475 大収穫じゃん
0252デフォルトの名無しさんNGNG
俺のプロバ当ててみろ!!!!!!!!
■ このスレッドは過去ログ倉庫に格納されています