バイナリファイルのバイトSWAPの高速化方法

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
shiro

バイナリファイルのバイトSWAPの高速化方法

#1 投稿記事 by shiro »

はじめましてshiroと申します。

バイナリファイルをバイトSWAPするプログラムを作りました。
のぞむ機能は得られましたが、512Mbitデータの変換に、
15分程度かかってしまいます。
(ROMライタでSWAPしている時間を短縮したかった)

べたべたな作りで、恥ずかしいのですが以下がリストです。
ファイルアクセスに時間がかかるのかと思い、
フィールド長を大きくして、並べ替えてからPUTを試してみましたが、
あまり変わりません。

高速化する方法をご教示いただけると幸いです。
よろしくお願いします。

コード: 全て選択

OPEN PATH+"\"+FILE AS 1
OPEN PATH+"\"+FILE+"_SW.BIN" AS 2
FIELD #1,1	'ファイルフィールド長 1BYTE
FIELD #2,1	'ファイルフィールド長 1BYTE
PRINT "START";Time$()
/*データ入力&出力====================================*/
*DATA_GET
GET #1,COUNTER,K$1	'データ GET
GET #1,COUNTER+1,K$2
PUT #2,COUNTER,K$2	'SWAPデータ PUT
PUT #2,COUNTER+1,K$1
/*SUM値演算========================================*/
SUM1 = Asc(K$1)
SUM2 = Asc(K$2)
SUM_OR = SUM_OR + (SUM1*256+SUM2)
SUM_SW = SUM_SW + (SUM2*256+SUM1)
COUNTER = COUNTER+2
IF Eof(1) = -1 THEN *END_TASK			'END OF FILE
GOTO *DATA_GET
/*終了処理   ==========================================*/
*END_TASK
CLOSE 1
CLOSE 2
omasu
記事: 96
登録日時: 2005年9月02日(金) 22:15
連絡する:

512Mbitデータの変換について

#2 投稿記事 by omasu »

お世話になります。

 処理の高速化については私も悩みまくっております。(~o~)

しかし、標準入出力の1バイトずつのGetとPutでは、
 ファイルの入出力アクセスで単純に考えても時間がかかると思われます。

512Mbitデータが64MByteのバイナリファイルとすれば、
 全てのバイナリファイルを一回でメモリに読み込み、
  編集(それぞれのデータを相互に足し算?)の後
   一回でファイル出力をしたほうが効率的であると考えます。

「ROMライタ」という記述で躊躇したのですが、一考察として投稿をいたします。
 がんばってください。
最後に編集したユーザー omasu [ 2006年1月09日(月) 00:15 ], 累計 1 回
konisi
記事: 893
登録日時: 2005年7月25日(月) 13:27
お住まい: 埼玉県東松山市
連絡する:

#3 投稿記事 by konisi »

ファイル名の変更では、処理回数が一回だけ(だったと思う。)の為、あまり関係ないと思います。それより、Asc関数を呼び出さなければ相当速くなると思います。

before:

コード: 全て選択


SUM1=Asc(S$1)
after:

コード: 全て選択


SUM1=S$1[0]
読みやすさを無視して本当に高速化したいのであれば、関数を全てばらすと可也速くなります。(只、その後の改造が面倒になる。)

他に、実際に速くなるかどうかはわかりませんが、goto命令をDo~Loopに変えれば速くなる可能性もあります。
抜ける時はif文+Exit Do命令
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。

に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
konisi
記事: 893
登録日時: 2005年7月25日(月) 13:27
お住まい: 埼玉県東松山市
連絡する:

追伸

#4 投稿記事 by konisi »

先ほどの発言の正確性について次のコードをテストしたときの結果をそれぞれ返します。
文字列の変換時にAscを使った時と配列を使った時のスピード比較

コード: 全て選択


Dim I As Long
Dim A$ As String
Dim A As Byte
Dim StartTime As Long
Dim EndTime As Long
Dim UsedTime As Long
Dim StartTime2 As Long
Dim EndTime2 As Long
Dim UsedTime2 As Long
Declare Function timeGetTime Lib "winmm.dll" () As DWord
A$=" "
StartTime=timeGetTime()
For I=0 To 1000000
	A=Asc(A$)
Next I
EndTime=timeGetTime()
StartTime2=timeGetTime()
For I=0 To 1000000
	A=A$[0]
Next I
EndTime2=timeGetTime()
UsedTime=EndTime-StartTime
UsedTime2=EndTime2-StartTime2
Open "Test.txt" For Append As #1
A$=Str$(UsedTime)
Write #1,A$
A$=Str$(UsedTime2)
Write #1,A$
Close #1
MessageBox(0,"Test was end","EndDialog",0)
End
五回実行した時の結果の平均値
UsedTime=8581.8
UsedTime2=77.6

実際に出力したファイルの記述内容
4929
37
9706
105
9375
89
9511
102
9388
55

測定する順番を逆にした場合の結果
五回実行した時の結果の平均値
UsedTime=9690
UsedTime2=74

実際に出力したファイルの記述内容
9633
95
9603
40
9639
78
9734
75
9841
82

Do~Loopとgotoのスピード比較

コード: 全て選択


Dim I As Long
Dim A$ As String
Dim StartTime As Long
Dim EndTime As Long
Dim UsedTime As Long
Dim StartTime2 As Long
Dim EndTime2 As Long
Dim UsedTime2 As Long
Declare Function timeGetTime Lib "winmm.dll" () As DWord
I=0
StartTime=timeGetTime()
Do
	I=I+1
	if I>100000000 then Exit Do
Loop
EndTime=timeGetTime()
I=0
StartTime2=timeGetTime()
*A
	I=I+1
	if I>100000000 then goto *B
goto *A
*B
EndTime2=timeGetTime()
UsedTime=EndTime-StartTime
UsedTime2=EndTime2-StartTime2
Open "Test3.txt" For Append As #1
A$=Str$(UsedTime)
Write #1,A$
A$=Str$(UsedTime2)
Write #1,A$
Close #1
MessageBox(0,"Test was end","EndDialog",0)
End
五回実行した時の結果の平均値
UsedTime=4757
UsedTime2=4905

実際に出力したファイルの記述内容
4659
4884
4887
4949
4715
4931
4651
4879
4873
4882


結論:Asc関数を使わずに文字列の配列を使う価値は十分あるがgotoとDo~Loopでは殆んど差異が見られなかった。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。

に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
shiro

レスありがとうございます

#5 投稿記事 by shiro »

omasuさん。konishiさん。
レスありがとうございます。

ヒント、助言、テスト結果ありがとうございます。
いろいろ試してみたいと思います。

プログラム書くのが十数年ぶりなのと、BASIC基本7命令ぐらいしか
よくわかっていないので、時間がかかりそうですが.....

自分は、おとといActiveBASICを発見し
使用してみたのですが、便利ですねぇ!!
PC88、98がない状況でN88BASICが使えるとは!!

なにか結果がでれば、報告いたします。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#6 投稿記事 by イグトランス »

寝ぼけているので頓珍漢なことを書いていたらすみません。

2006/01/09 11:50
すみません。完璧に寝ぼけていましたね。
バイトスワップを見落としていました。
最後に編集したユーザー イグトランス [ 2006年1月09日(月) 11:51 ], 累計 1 回
omasu
記事: 96
登録日時: 2005年9月02日(金) 22:15
連絡する:

一考察として投稿Ⅱ

#7 投稿記事 by omasu »

お世話になります。

 私もアクティブベーシックと出会ったときは感激しました。

当初のファイル入出力を一回で行うコードを参考として投稿をいたします。(AB4.13.00)
77Mバイトのテストデータでは5秒くらいで終了します。
演算処理はロジックのどこかで使っているのでしょうか?(不明なため反映はしていません)
追伸:データが奇数の場合、最後のバイトはどうするのでしょうか?
追伸:データが巨大となる場合はメモリに取り込めない可能性があります。
shiro

SWAP作成

#8 投稿記事 by shiro »

お世話になります。

提示リストがわかりにくかったですね。申し訳ないです。

/* データ入力&出力  ====================================*/
*DATA_GET
GET #1,COUNTER,K$1 'データ GET
GET #1,COUNTER+1,K$2
PUT #2,COUNTER,K$2 'SWAPデータ PUT << 単純に1と2を入れ替えてPUTです。
PUT #2,COUNTER+1,K$1

ファイルアクセスの半減させるよう2バイトアクセスで、以下にしてみましたが、
かえって遅くなりました。
文字列操作が遅いのでしょうか?
メモリに展開してからという概念を勘違いしてますか?

/* データ入力&出力  ====================================*/
*DATA_GET
GET #1,COUNTER,K$1 'データ GET
LOW$ = Mid$(K$1,2,1)
HIGH$ = Mid$(K$1,1,1)
K$2 = LOW$ + HIGH$
PUT #2,COUNTER,K$2 'SWAPデータ PUT


>>omasuさん
データ数は偶数前提で作成してます。
過去ログをみて、勉強中です。
ソートロジック大会は読み物としても、おもしろいですね。
omasu
記事: 96
登録日時: 2005年9月02日(金) 22:15
連絡する:

メモリに展開してからという概念について

#9 投稿記事 by omasu »

お世話になります。

 omasuの投稿ロジックで機能ははたせると思われますが、
 何か不具合があるのでしょうか?

機能1.入力ファイルの全てのデータをメモリ(バッファ)に取り込む
機能2.メモリ(バッファ)内でバイト単位のスワップを行う。
機能3.スワップ済みのメモリ(バッファ)データをファイルに書き込む

※入出力アクセスは入力ファイル取り込みと出力ファイルの書き込みの一回ですみます。
※この結果処理時間は77Mバイトのファイルで5秒くらいとなります。

追伸:ソートロジック大会への参加も期待しております。(~o~)/
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#10 投稿記事 by イグトランス »

さらにその上を行く手段としてメモリマップドファイルと言うものがあります。
ようするにファイルを巨大なByte配列と見なして処理ができると言うことです。(Byte型に限らずなんでも良いですが)
もはやバッファとファイルとの読み書きなんて要りません。(裏でWindowsがよきに計らっているだけですが)
これで、omasuさんのものに比べおよそ半分の時間で実行できました。
(omasuさんのコードの前後にtimeGetTimeを挟んで計測しました。)
私のPCではおよそ80MiBytesのファイルでomasuさんのがおよそ3.2秒ほど,私のが1.6秒ほどでした。
shiro

激速ですね。

#11 投稿記事 by shiro »

お世話になります。shiroです。

omasuさん。イグトランスさん。ありがとうございます。

>>omasuさん
 実用的なスピードになりました。
 途中で変なレスしちゃいました。(失礼しました)

>>イグトランスさん
 すごいですね。
 内容が理解できていないので、まだ実施できていません。
 申し訳ありません。
 勉強して、組み込んでいきたいと思います。

初回作成版がROMライタと同程度の速度だったので、泣きが入っていました。
実用的なものができたし、学生時代を思い出して楽しくいじれたし、
とても有意義な3連休でした。

本当にありがとうございました。
omasu
記事: 96
登録日時: 2005年9月02日(金) 22:15
連絡する:

いえいえ

#12 投稿記事 by omasu »

お世話になります。

 お役に立てて幸いです。

私のコードはN88BASICそのものの記述で、やっとAB4になりつつある未熟者です。m(_w_)m

イグトランスさんのコードは高度すぎるため私としても、能力不足、理解不能を感じます。
 今は全体としてよりも、パーツとして、非常に貴重なコード、
  技術的な部分での魅力が豊富に存在していると思います。
   いつかは理解したいですね

そこから先が、konisiさんのコードになると思います。
 ABをカスタマイズしてしまおうという力量がすばらしいと思います。
  先にkonisiさんが出てくるとややこしくなりますが?
   申し訳ありません。m(_w_)m
    実用ロジック参考にしております。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#13 投稿記事 by イグトランス »

簡単に補足を。(補足になっていませんが)

あのコードの肝はpInputとpOutputです。
ようするにこの2つに対しての読み書きはメモリではなく,
全て入力・出力のファイルに対して行われます。
そこまでの長い行は全てこのための前準備でしかないです。
つまりバイトスワップのロジックだけ見たければ読み飛ばしてもなんら差し支えないと言うことです。
konisi
記事: 893
登録日時: 2005年7月25日(月) 13:27
お住まい: 埼玉県東松山市
連絡する:

#14 投稿記事 by konisi »

>>そこから先が、konisiさんのコードになると思います。
 ABをカスタマイズしてしまおうという力量がすばらしいと思います。
  先にkonisiさんが出てくるとややこしくなりますが?
   申し訳ありません。m(_w_)m
    実用ロジック参考にしております。

だから、元々そういう性格(「アイコンを手動で挿入」参照。)なのでついやっちまうんですよ。只、僕にもイグトランスsみたいにさまざまな関数を書き分けるだけの技量がないので能力不足は感じていますが。

そしてややこしくなった事に謝罪。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。

に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
omasu
記事: 96
登録日時: 2005年9月02日(金) 22:15
連絡する:

メモリの制限について

#15 投稿記事 by omasu »

お世話になります。

 自分の投稿の中に

> 追伸:データが巨大となる場合はメモリに取り込めない可能性があります。

自分も過去、メモリの少なさに嘆いていた時期があったことを思い出してしまいました。

こんなコードをそのままにしておけないと思い、書き直して見ました。
返信する