fr32 utils
This commit is contained in:
parent
e3d3887a0b
commit
4db8351348
@ -8,7 +8,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toReadableFile(r io.Reader, n int64) (*os.File, func() error, error) {
|
func ToReadableFile(r io.Reader, n int64) (*os.File, func() error, error) {
|
||||||
f, ok := r.(*os.File)
|
f, ok := r.(*os.File)
|
||||||
if ok {
|
if ok {
|
||||||
return f, func() error { return nil }, nil
|
return f, func() error { return nil }, nil
|
||||||
|
@ -105,7 +105,7 @@ func (sb *Sealer) AddPiece(ctx context.Context, sector abi.SectorID, existingPie
|
|||||||
return abi.PieceInfo{}, xerrors.Errorf("getting partial file writer: %w", err)
|
return abi.PieceInfo{}, xerrors.Errorf("getting partial file writer: %w", err)
|
||||||
}
|
}
|
||||||
pr := io.TeeReader(io.LimitReader(file, int64(pieceSize)), w)
|
pr := io.TeeReader(io.LimitReader(file, int64(pieceSize)), w)
|
||||||
prf, werr, err := toReadableFile(pr, int64(pieceSize))
|
prf, werr, err := ToReadableFile(pr, int64(pieceSize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return abi.PieceInfo{}, xerrors.Errorf("getting tee reader pipe: %w", err)
|
return abi.PieceInfo{}, xerrors.Errorf("getting tee reader pipe: %w", err)
|
||||||
}
|
}
|
||||||
@ -405,7 +405,7 @@ func (sb *Sealer) rewriteAsPadded(unsealed string, staged string) error {
|
|||||||
|
|
||||||
// OPTIMIZATION: upr is a file, so it could be passed straight to
|
// OPTIMIZATION: upr is a file, so it could be passed straight to
|
||||||
// WriteWithAlignment IF it wouldn't care about the trailer
|
// WriteWithAlignment IF it wouldn't care about the trailer
|
||||||
lupr, werr, err := toReadableFile(io.LimitReader(upr, int64(maxPieceSize)), int64(maxPieceSize))
|
lupr, werr, err := ToReadableFile(io.LimitReader(upr, int64(maxPieceSize)), int64(maxPieceSize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -489,7 +489,7 @@ func (sb *Sealer) FinalizeSector(ctx context.Context, sector abi.SectorID) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GeneratePieceCIDFromFile(proofType abi.RegisteredProof, piece io.Reader, pieceSize abi.UnpaddedPieceSize) (cid.Cid, error) {
|
func GeneratePieceCIDFromFile(proofType abi.RegisteredProof, piece io.Reader, pieceSize abi.UnpaddedPieceSize) (cid.Cid, error) {
|
||||||
f, werr, err := toReadableFile(piece, int64(pieceSize))
|
f, werr, err := ToReadableFile(piece, int64(pieceSize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,13 @@ import (
|
|||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/filecoin-project/specs-storage/storage"
|
||||||
|
|
||||||
"github.com/filecoin-project/sector-storage/ffiwrapper/basicfs"
|
"github.com/filecoin-project/sector-storage/ffiwrapper/basicfs"
|
||||||
"github.com/filecoin-project/sector-storage/stores"
|
"github.com/filecoin-project/sector-storage/stores"
|
||||||
"github.com/filecoin-project/specs-storage/storage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -414,3 +415,18 @@ func TestSealAndVerify2(t *testing.T) {
|
|||||||
|
|
||||||
post(t, sb, s1, s2)
|
post(t, sb, s1, s2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkWriteWithAlignment(b *testing.B) {
|
||||||
|
bt := abi.UnpaddedPieceSize(2 * 127 * 1024 * 1024)
|
||||||
|
b.SetBytes(int64(bt))
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
b.StopTimer()
|
||||||
|
rf, w, _ := ToReadableFile(bytes.NewReader(bytes.Repeat([]byte{0xff, 0}, int(bt/2))), int64(bt))
|
||||||
|
tf, _ := ioutil.TempFile("/tmp/", "scrb-")
|
||||||
|
b.StartTimer()
|
||||||
|
|
||||||
|
ffi.WriteWithAlignment(abi.RegisteredProof_StackedDRG2KiBSeal, rf, bt, tf, nil)
|
||||||
|
w()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
138
fr32/fr32.go
Normal file
138
fr32/fr32.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package fr32
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/bits"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mtTresh = 32 << 20
|
||||||
|
|
||||||
|
func mt(in, out []byte, padLen int, op func(in, out []byte)) {
|
||||||
|
threads := padLen / mtTresh
|
||||||
|
if threads > runtime.NumCPU() {
|
||||||
|
threads = 1 << (32 - bits.LeadingZeros32(uint32(runtime.NumCPU())))
|
||||||
|
}
|
||||||
|
threadBytes := abi.PaddedPieceSize(padLen / threads)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(threads)
|
||||||
|
|
||||||
|
for i := 0; i < threads; i++ {
|
||||||
|
go func(thread int) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
start := threadBytes * abi.PaddedPieceSize(thread)
|
||||||
|
end := start + threadBytes
|
||||||
|
|
||||||
|
op(in[start.Unpadded():end.Unpadded()], out[start:end])
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assumes len(in)%127==0 and len(out)%128==0
|
||||||
|
func Pad(in, out []byte) {
|
||||||
|
if len(out) > mtTresh {
|
||||||
|
mt(in, out, len(out), Pad)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks := len(out) / 128
|
||||||
|
for chunk := 0; chunk < chunks; chunk++ {
|
||||||
|
inOff := chunk * 127
|
||||||
|
outOff := chunk * 128
|
||||||
|
|
||||||
|
copy(out[outOff:outOff+31], in[inOff:inOff+31])
|
||||||
|
|
||||||
|
t := in[inOff+31] >> 6
|
||||||
|
out[outOff+31] = in[inOff+31] & 0x3f
|
||||||
|
var v byte
|
||||||
|
|
||||||
|
for i := 32; i < 64; i++ {
|
||||||
|
v = in[inOff+i]
|
||||||
|
out[outOff+i] = (v << 2) | t
|
||||||
|
t = v >> 6
|
||||||
|
}
|
||||||
|
|
||||||
|
t = v >> 4
|
||||||
|
out[outOff+63] &= 0x3f
|
||||||
|
|
||||||
|
for i := 64; i < 96; i++ {
|
||||||
|
v = in[inOff+i]
|
||||||
|
out[outOff+i] = (v << 4) | t
|
||||||
|
t = v >> 4
|
||||||
|
}
|
||||||
|
|
||||||
|
t = v >> 2
|
||||||
|
out[outOff+95] &= 0x3f
|
||||||
|
|
||||||
|
for i := 96; i < 127; i++ {
|
||||||
|
v = in[inOff+i]
|
||||||
|
out[outOff+i] = (v << 6) | t
|
||||||
|
t = v >> 2
|
||||||
|
}
|
||||||
|
|
||||||
|
out[outOff+127] = t & 0x3f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assumes len(in)%128==0 and len(out)%127==0
|
||||||
|
func Unpad(in []byte, out []byte) {
|
||||||
|
if len(out) > mtTresh {
|
||||||
|
mt(in, out, len(in), Unpad)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks := len(in) / 128
|
||||||
|
for chunk := 0; chunk < chunks; chunk++ {
|
||||||
|
inOffNext := chunk*128 + 1
|
||||||
|
outOff := chunk * 127
|
||||||
|
|
||||||
|
at := in[chunk*128]
|
||||||
|
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
next := in[i+inOffNext]
|
||||||
|
|
||||||
|
out[outOff+i] = at
|
||||||
|
//out[i] |= next << 8
|
||||||
|
|
||||||
|
at = next
|
||||||
|
}
|
||||||
|
|
||||||
|
out[outOff+31] |= at << 6
|
||||||
|
|
||||||
|
for i := 32; i < 64; i++ {
|
||||||
|
next := in[i+inOffNext]
|
||||||
|
|
||||||
|
out[outOff+i] = at >> 2
|
||||||
|
out[outOff+i] |= next << 6
|
||||||
|
|
||||||
|
at = next
|
||||||
|
}
|
||||||
|
|
||||||
|
out[outOff+63] ^= (at << 6) ^ (at << 4)
|
||||||
|
|
||||||
|
for i := 64; i < 96; i++ {
|
||||||
|
next := in[i+inOffNext]
|
||||||
|
|
||||||
|
out[outOff+i] = at >> 4
|
||||||
|
out[outOff+i] |= next << 4
|
||||||
|
|
||||||
|
at = next
|
||||||
|
}
|
||||||
|
|
||||||
|
out[outOff+95] ^= (at << 4) ^ (at << 2)
|
||||||
|
|
||||||
|
for i := 96; i < 127; i++ {
|
||||||
|
next := in[i+inOffNext]
|
||||||
|
|
||||||
|
out[outOff+i] = at >> 6
|
||||||
|
out[outOff+i] |= next << 2
|
||||||
|
|
||||||
|
at = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
248
fr32/fr32_test.go
Normal file
248
fr32/fr32_test.go
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
package fr32
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||||
|
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func padFFI(buf []byte) []byte {
|
||||||
|
rf, w, _ := ffiwrapper.ToReadableFile(bytes.NewReader(buf), int64(len(buf)))
|
||||||
|
tf, _ := ioutil.TempFile("/tmp/", "scrb-")
|
||||||
|
|
||||||
|
_, _, _, err := ffi.WriteWithAlignment(abi.RegisteredProof_StackedDRG32GiBSeal, rf, abi.UnpaddedPieceSize(len(buf)), tf, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := w(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := tf.Seek(io.SeekStart, 0); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
padded, err := ioutil.ReadAll(tf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tf.Close(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Remove(tf.Name()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return padded
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPadChunkFFI(t *testing.T) {
|
||||||
|
testByteChunk := func(b byte) func(*testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
var buf [128]byte
|
||||||
|
copy(buf[:], bytes.Repeat([]byte{b}, 127))
|
||||||
|
|
||||||
|
Pad(buf[:], buf[:])
|
||||||
|
|
||||||
|
expect := padFFI(bytes.Repeat([]byte{b}, 127))
|
||||||
|
|
||||||
|
require.Equal(t, expect, buf[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("ones", testByteChunk(0xff))
|
||||||
|
t.Run("lsb1", testByteChunk(0x01))
|
||||||
|
t.Run("msb1", testByteChunk(0x80))
|
||||||
|
t.Run("zero", testByteChunk(0x0))
|
||||||
|
t.Run("mid", testByteChunk(0x3c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPadChunkRandEqFFI(t *testing.T) {
|
||||||
|
for i := 0; i < 200; i++ {
|
||||||
|
var input [127]byte
|
||||||
|
rand.Read(input[:])
|
||||||
|
|
||||||
|
var buf [128]byte
|
||||||
|
|
||||||
|
Pad(input[:], buf[:])
|
||||||
|
|
||||||
|
expect := padFFI(input[:])
|
||||||
|
|
||||||
|
require.Equal(t, expect, buf[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoundtrip(t *testing.T) {
|
||||||
|
testByteChunk := func(b byte) func(*testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
var buf [128]byte
|
||||||
|
input := bytes.Repeat([]byte{0x01}, 127)
|
||||||
|
|
||||||
|
Pad(input, buf[:])
|
||||||
|
|
||||||
|
var out [127]byte
|
||||||
|
Unpad(buf[:], out[:])
|
||||||
|
|
||||||
|
require.Equal(t, input, out[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("ones", testByteChunk(0xff))
|
||||||
|
t.Run("lsb1", testByteChunk(0x01))
|
||||||
|
t.Run("msb1", testByteChunk(0x80))
|
||||||
|
t.Run("zero", testByteChunk(0x0))
|
||||||
|
t.Run("mid", testByteChunk(0x3c))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoundtripChunkRand(t *testing.T) {
|
||||||
|
for i := 0; i < 200; i++ {
|
||||||
|
var input [127]byte
|
||||||
|
rand.Read(input[:])
|
||||||
|
|
||||||
|
var buf [128]byte
|
||||||
|
copy(buf[:], input[:])
|
||||||
|
|
||||||
|
Pad(buf[:], buf[:])
|
||||||
|
|
||||||
|
var out [127]byte
|
||||||
|
Unpad(buf[:], out[:])
|
||||||
|
|
||||||
|
require.Equal(t, input[:], out[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoundtrip16MRand(t *testing.T) {
|
||||||
|
up := abi.PaddedPieceSize(16 << 20).Unpadded()
|
||||||
|
|
||||||
|
input := make([]byte, up)
|
||||||
|
rand.Read(input[:])
|
||||||
|
|
||||||
|
buf := make([]byte, 16<<20)
|
||||||
|
|
||||||
|
Pad(input, buf)
|
||||||
|
|
||||||
|
out := make([]byte, up)
|
||||||
|
Unpad(buf, out)
|
||||||
|
|
||||||
|
require.Equal(t, input, out)
|
||||||
|
|
||||||
|
ffi := padFFI(input)
|
||||||
|
require.Equal(t, ffi, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPadChunk(b *testing.B) {
|
||||||
|
var buf [128]byte
|
||||||
|
in := bytes.Repeat([]byte{0xff}, 127)
|
||||||
|
|
||||||
|
b.SetBytes(127)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Pad(in, buf[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkChunkRoundtrip(b *testing.B) {
|
||||||
|
var buf [128]byte
|
||||||
|
copy(buf[:], bytes.Repeat([]byte{0xff}, 127))
|
||||||
|
var out [127]byte
|
||||||
|
|
||||||
|
b.SetBytes(127)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Pad(buf[:], buf[:])
|
||||||
|
Unpad(buf[:], out[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnpadChunk(b *testing.B) {
|
||||||
|
var buf [128]byte
|
||||||
|
copy(buf[:], bytes.Repeat([]byte{0xff}, 127))
|
||||||
|
|
||||||
|
Pad(buf[:], buf[:])
|
||||||
|
var out [127]byte
|
||||||
|
|
||||||
|
b.SetBytes(127)
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
bs := buf[:]
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Unpad(bs, out[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnpad16MChunk(b *testing.B) {
|
||||||
|
up := abi.PaddedPieceSize(16 << 20).Unpadded()
|
||||||
|
|
||||||
|
var buf [16 << 20]byte
|
||||||
|
|
||||||
|
Pad(bytes.Repeat([]byte{0xff}, int(up)), buf[:])
|
||||||
|
var out [16 << 20]byte
|
||||||
|
|
||||||
|
b.SetBytes(16 << 20)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Unpad(buf[:], out[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPad16MChunk(b *testing.B) {
|
||||||
|
up := abi.PaddedPieceSize(16 << 20).Unpadded()
|
||||||
|
|
||||||
|
var buf [16 << 20]byte
|
||||||
|
|
||||||
|
in := bytes.Repeat([]byte{0xff}, int(up))
|
||||||
|
|
||||||
|
b.SetBytes(16 << 20)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Pad(in, buf[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPad1GChunk(b *testing.B) {
|
||||||
|
up := abi.PaddedPieceSize(1 << 30).Unpadded()
|
||||||
|
|
||||||
|
var buf [1 << 30]byte
|
||||||
|
|
||||||
|
in := bytes.Repeat([]byte{0xff}, int(up))
|
||||||
|
|
||||||
|
b.SetBytes(1 << 30)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Pad(in, buf[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnpad1GChunk(b *testing.B) {
|
||||||
|
up := abi.PaddedPieceSize(1 << 30).Unpadded()
|
||||||
|
|
||||||
|
var buf [1 << 30]byte
|
||||||
|
|
||||||
|
Pad(bytes.Repeat([]byte{0xff}, int(up)), buf[:])
|
||||||
|
var out [1 << 30]byte
|
||||||
|
|
||||||
|
b.SetBytes(1 << 30)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Unpad(buf[:], out[:])
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user