github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/ecache/cache_entry.go (about)

     1  package ecache
     2  
     3  import "sync/atomic"
     4  import _ "unsafe"
     5  
     6  //go:linkname systemMonoNanoTime runtime.nanotime
     7  
     8  //go:noescape
     9  func systemMonoNanoTime() int64
    10  
    11  // A cached mask with additional information to estimate how
    12  // much the entry is being used. Cache implementers may use this
    13  // type to make their life easier.
    14  type CachedMaskEntry struct {
    15  	Mask            GlyphMask // Read-only.
    16  	ByteSize        uint32    // Read-only.
    17  	CreationInstant uint32    // see CacheEntryInstant. Read-only.
    18  	// Won't be consistent after reboots. I
    19  	// don't know why would anyone try to
    20  	// save a cache, but I've seen worse.
    21  	accessCount uint32 // number of times the entry has been accessed
    22  }
    23  
    24  // Must be called after accessing an entry in order to keep the
    25  // Hotness() heuristic making sense. Concurrent-safe.
    26  func (self *CachedMaskEntry) IncreaseAccessCount() {
    27  	atomic.AddUint32(&self.accessCount, 1)
    28  }
    29  
    30  // A measure of "bytes accessed per time". Coldest entries
    31  // (smallest values) are candidates for eviction. Concurrent-safe.
    32  func (self *CachedMaskEntry) Hotness(instant uint32) uint32 {
    33  	const ConstEvictionCost = 1000 // additional threshold and pad
    34  	bytesHit := self.ByteSize * atomic.LoadUint32(&self.accessCount)
    35  	elapsed := instant - self.CreationInstant
    36  	if elapsed == 0 {
    37  		elapsed = 1
    38  	}
    39  	return (ConstEvictionCost + bytesHit) / elapsed
    40  }
    41  
    42  // A time instant related to the system's monotonic nano time, but with
    43  // some arbitrary downscaling applied (close to converting nanoseconds
    44  // to hundredth's of seconds).
    45  func CacheEntryInstant() uint32 {
    46  	return uint32(systemMonoNanoTime() >> 27)
    47  }
    48  
    49  // Creates a new cached mask entry for the given GlyphMask.
    50  func NewCachedMaskEntry(mask GlyphMask) (*CachedMaskEntry, uint32) {
    51  	instant := CacheEntryInstant()
    52  	return &CachedMaskEntry{
    53  		Mask:            mask,
    54  		ByteSize:        GlyphMaskByteSize(mask),
    55  		CreationInstant: instant,
    56  		accessCount:     1,
    57  	}, instant
    58  }