go-randomx/dataset.go
DataHoarder c41d6c8080
Some checks failed
continuous-integration/drone/push Build is failing
Support large pages, implement aligned / paged / large paged allocators
2024-05-02 16:18:50 +02:00

112 lines
2.8 KiB
Go

package randomx
import (
"errors"
"git.gammaspectra.live/P2Pool/go-randomx/v3/internal/memory"
"sync"
)
const DatasetSize = RANDOMX_DATASET_BASE_SIZE + RANDOMX_DATASET_EXTRA_SIZE
const DatasetItemCount = DatasetSize / CacheLineSize
type Dataset struct {
memory []RegisterLine
flags Flags
}
// NewDataset Creates a randomx_dataset structure and allocates memory for RandomX Dataset.
// Only one flag is supported (can be set or not set): RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages
// Returns nil if allocation fails
func NewDataset(flags Flags) (result *Dataset, err error) {
defer func() {
//catch too large memory allocation or unable to allocate, for example on 32-bit targets or out of memory
if r := recover(); r != nil {
result = nil
if e, ok := r.(error); ok && e != nil {
err = e
} else {
err = errors.New("out of memory")
}
}
}()
var alignedMemory []RegisterLine
if flags.Has(RANDOMX_FLAG_LARGE_PAGES) {
if largePageAllocator == nil {
return nil, errors.New("huge pages not supported")
}
alignedMemory, err = memory.AllocateSlice[RegisterLine](largePageAllocator, DatasetItemCount)
if err != nil {
return nil, err
}
} else {
alignedMemory, err = memory.AllocateSlice[RegisterLine](cacheLineAlignedAllocator, DatasetItemCount)
if err != nil {
return nil, err
}
}
return &Dataset{
memory: alignedMemory,
flags: flags,
}, nil
}
func (d *Dataset) prefetchDataset(address uint64) {
}
func (d *Dataset) readDataset(address uint64, r *RegisterLine) {
cache := &d.memory[address/CacheLineSize]
for i := range r {
r[i] ^= cache[i]
}
}
// Memory Returns a pointer to the internal memory buffer of the dataset structure.
// The size of the internal memory buffer is DatasetItemCount * RANDOMX_DATASET_ITEM_SIZE.
func (d *Dataset) Memory() []RegisterLine {
return d.memory
}
func (d *Dataset) InitDataset(cache *Cache, startItem, itemCount uint64) {
if startItem >= DatasetItemCount || itemCount > DatasetItemCount {
panic("out of range")
}
if startItem+itemCount > DatasetItemCount {
panic("out of range")
}
cache.datasetInit(d.memory[startItem:startItem+itemCount], startItem, startItem+itemCount)
}
func (d *Dataset) Close() error {
if d.flags.Has(RANDOMX_FLAG_LARGE_PAGES) {
return memory.FreeSlice(largePageAllocator, d.memory)
} else {
return memory.FreeSlice(cacheLineAlignedAllocator, d.memory)
}
}
func (d *Dataset) InitDatasetParallel(cache *Cache, n int) {
n = max(1, n)
var wg sync.WaitGroup
for i := uint64(1); i < uint64(n); i++ {
a := (DatasetItemCount * i) / uint64(n)
b := (DatasetItemCount * (i + 1)) / uint64(n)
wg.Add(1)
go func(a, b uint64) {
defer wg.Done()
d.InitDataset(cache, a, b-a)
}(a, b)
}
d.InitDataset(cache, 0, DatasetItemCount/uint64(n))
wg.Wait()
}